<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Mike Walmsley]]></title><description><![CDATA[Solving interesting problems with data]]></description><link>https://walmsley.dev</link><generator>GatsbyJS</generator><lastBuildDate>Fri, 05 Apr 2024 13:44:57 GMT</lastBuildDate><item><title><![CDATA[Zoobot v2]]></title><description><![CDATA[New foundation models for galaxy morphology]]></description><link>https://walmsley.dev/posts/zoobot-scaling-laws</link><guid isPermaLink="false">https://walmsley.dev/posts/zoobot-scaling-laws</guid><pubDate>Fri, 05 Apr 2024 09:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;zoobot-20-scaling-up&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zoobot-20-scaling-up&quot; aria-label=&quot;zoobot 20 scaling up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zoobot 2.0: Scaling Up&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This blog summarises the paper &lt;a href=&quot;https://arxiv.org/abs/2404.02973&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Scaling Laws for Galaxy Images&lt;/a&gt;. Use our foundation models with the &lt;a href=&quot;https://github.com/mwalmsley/zoobot&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Zoobot 2.0&lt;/a&gt; Python package. &lt;a href=&quot;https://colab.research.google.com/drive/1A_-M3Sz5maQmyfW2A7rEu-g_Zi0RMGz5?usp=sharing&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Colab&lt;/a&gt;, &lt;a href=&quot;https://github.com/mwalmsley/zoobot&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;code&lt;/a&gt;, &lt;a href=&quot;https://zoobot.readthedocs.io/en/latest/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;docs&lt;/a&gt;, &lt;a href=&quot;https://huggingface.co/collections/mwalmsley/zoobot-encoders-65fa14ae92911b173712b874&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;models&lt;/a&gt;, &lt;a href=&quot;https://zoobot.readthedocs.io/en/latest/science_data.html#precalulated-representations&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;embeddings&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All my best work has come from giving a talk, getting asked a good question, and replying with totally the wrong answer.&lt;/p&gt;
&lt;p&gt;I spent the last couple of years making and then refining a set of AI models called Zoobot.
Zoobot is designed to be adapted to new galaxy tasks with minimal new labels.
I often call Zoobot a foundation model &lt;sup id=&quot;fnref-1&quot;&gt;&lt;a href=&quot;#fn-1&quot; class=&quot;footnote-ref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.
But after my talks, people often say: “Zoobot works, but it’s not really a &lt;em&gt;foundation&lt;/em&gt; model. It’s too tiny! Foundation models should have billions of parameters. What happens if you make it bigger?”&lt;/p&gt;
&lt;p&gt;Like literally every AI researcher in the world, I enjoy training big models. &lt;em&gt;Of course&lt;/em&gt; I tried making Zoobot bigger. It didn’t help much. I might even go further and say&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“There is no evidence that bigger AI models work better in astronomy”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It’s clear that big models do better when fueled by limitless labelled data (think billions of web-scraped images with alt-text). But astronomers work with thousands of labelled images, not billions.
Even ImageNet, with 1.3M images, is about four times larger than the largest astronomy equivalent (GZ DESI). I think that’s why there are no astronomy papers showing a convincing&lt;sup id=&quot;fnref-2&quot;&gt;&lt;a href=&quot;#fn-2&quot; class=&quot;footnote-ref&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; improvement from (say) large vision transformers.&lt;/p&gt;
&lt;p&gt;But if data is the limiting factor - what if we scaled that as well?&lt;/p&gt;
&lt;h2 id=&quot;pretraining-experiments&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#pretraining-experiments&quot; aria-label=&quot;pretraining experiments permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pretraining Experiments&lt;/h2&gt;
&lt;p&gt;I spent (insert silly amount of time here) pulling together a dataset of 800k+ galaxies with 100M+ Galaxy Zoo volunteer annotations. That’s more than half of all human galaxy annotations ever collected. Then I trained models to predict those annotations. I systematically worked through every popular architecture (ConvNexT, EffNetV2, MaxViT, etc.) and every model size, from 1M to 200M parameters. I then I did it twice more for error bars.&lt;/p&gt;
&lt;p&gt;Here’s what I found.&lt;/p&gt;
&lt;h4 id=&quot;adding-data-predictably-improves-performance-for-every-model&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#adding-data-predictably-improves-performance-for-every-model&quot; aria-label=&quot;adding data predictably improves performance for every model permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adding data predictably improves performance for every model&lt;/h4&gt;
&lt;p&gt;We expect that more labels help. What’s interesting is that the amount of improvement for each label added is &lt;em&gt;totally predictable&lt;/em&gt;.
For every architecture, we see an almost-identical power law relationship between labels and performance.
This means we can predict how much our models will improve as we add new labels.&lt;/p&gt;
&lt;p&gt;Each time we double the training data, we get the same improvement in performance. But we can’t keep doubling training data; this paper used more than half of all the annotations ever collected. There’s not much left to add!&lt;/p&gt;
&lt;h4 id=&quot;bigger-models-do-better-up-to-a-point&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bigger-models-do-better-up-to-a-point&quot; aria-label=&quot;bigger models do better up to a point permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bigger models do better, up to a point&lt;/h4&gt;
&lt;p&gt;When we use a quarter of our dataset, training bigger models does almost no better: they overfit. But our full dataset provides enough labelled galaxies to meaningfully train models up to around 100M parameters.
Our best models (ConvNeXT-Base and MaxViT-Base) outperform the small (5M) EfficientNetB0 model used for GZ DECaLS and GZ DESI.&lt;/p&gt;
&lt;p&gt;Beyond around 100M parameters, we start overfitting again. We could add some tricks like learning rate scheduling, aggressive regularization, etc., but it’s clear that we can’t scale indefinitely and expect better performance “for free”.&lt;/p&gt;
&lt;h4 id=&quot;more-data-helps-every-task-but-more-parameters-help-only-some-tasks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#more-data-helps-every-task-but-more-parameters-help-only-some-tasks&quot; aria-label=&quot;more data helps every task but more parameters help only some tasks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More data helps every task, but more parameters help only some tasks&lt;/h4&gt;
&lt;p&gt;We can measure performance separately for each of our Galaxy Zoo questions (88 in total). Adding data improves performance on every question. Remember the power law above? That applies to individual questions! But adding parameters only helps for some questions (possibly the more subjectively challenging ones).&lt;/p&gt;
&lt;p&gt;This is subtly different from the typical view that models are either data-limited or parameter-limited. Our models are data-limited for &lt;em&gt;all&lt;/em&gt; questions and parameter-limited for &lt;em&gt;some&lt;/em&gt; questions.&lt;/p&gt;
&lt;h2 id=&quot;finetuning-experiments&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#finetuning-experiments&quot; aria-label=&quot;finetuning experiments permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Finetuning Experiments&lt;/h2&gt;
&lt;p&gt;I then finetuned our models on five real scientific tasks: finding and characterising faint tidal features, classifying JWST galaxies, detecting ringed galaxies, and (okay, slightly less real) galaxy morphology in Galaxy10 DECaLS.&lt;/p&gt;
&lt;h4 id=&quot;we-can-do-well-at-new-tasks-with-just-hundreds-to-thousands-of-labelled-examples&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#we-can-do-well-at-new-tasks-with-just-hundreds-to-thousands-of-labelled-examples&quot; aria-label=&quot;we can do well at new tasks with just hundreds to thousands of labelled examples permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We can do well at new tasks with just hundreds to thousands of labelled examples&lt;/h4&gt;
&lt;p&gt;For every new task, the galaxy-pretrained models did better than models pretrained only on ImageNet (31% better, on average). They were good enough to do useful science on every task.&lt;/p&gt;
&lt;p&gt;Galaxy pretraining was most helpful when finetuning labels were scarce. This is exactly what Zoobot is for!&lt;/p&gt;
&lt;h4 id=&quot;for-new-tasks-pretraining-on-galaxy-images-is-more-important-than-using-big-models&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#for-new-tasks-pretraining-on-galaxy-images-is-more-important-than-using-big-models&quot; aria-label=&quot;for new tasks pretraining on galaxy images is more important than using big models permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;For new tasks, pretraining on galaxy images is more important than using big models&lt;/h4&gt;
&lt;p&gt;Bigger models did measurably better at the finetuning tasks, but the improvement was much smaller than from galaxy pretraining.
A large ImageNet-trained model is much worse than a small galaxy-pretrained model, and a large galaxy-pretrained model only adds a little extra benefit.&lt;/p&gt;
&lt;p&gt;That suggests that if you want good performance on galaxy images, you should focus on using a similar pretraining dataset rather than downloading the biggest possible model and hoping it works.&lt;/p&gt;
&lt;h2 id=&quot;where-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#where-next&quot; aria-label=&quot;where next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Where Next?&lt;/h2&gt;
&lt;p&gt;Alexander wept when there were no more worlds to conquer, and I weep now I’m out of human labels. Bigger models will require other techniques.&lt;/p&gt;
&lt;p&gt;Self-supervised learning is an obvious choice. I and my collaborators have been experimenting with this for a couple of years (e.g. &lt;a href=&quot;https://arxiv.org/pdf/2110.12735.pdf&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://academic.oup.com/mnras/article/514/2/2599/6575929&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;). Scientific foundation models are attracting &lt;a href=&quot;https://polymathic-ai.org/blog/announcement/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ever&lt;/a&gt; &lt;a href=&quot;https://arxiv.org/abs/2306.00258&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;more&lt;/a&gt; &lt;a href=&quot;https://arxiv.org/abs/2309.06126&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;interest&lt;/a&gt; and are still in their infancy in astronomy. I’m excited to see what we build together.&lt;/p&gt;
&lt;p&gt;The other side of the coin is finetuning. We can now use the new labels Galaxy Zoo volunteers are &lt;a href=&quot;www.galaxyzoo.org&quot;&gt;creating&lt;/a&gt; to quickly build specialized models, including for difficult tasks like &lt;a href=&quot;https://arxiv.org/abs/2312.02908&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;segmentation&lt;/a&gt;. Every label is now more valuable, not less. What new questions might we answer?&lt;/p&gt;
&lt;p&gt;If you’d like to join in, reach out - &lt;a href=&quot;emailto:mike.walmsley@dunlap.utoronto.ca&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;mike.walmsley@dunlap.utoronto.ca&lt;/a&gt;. I’m also part of the &lt;a href=&quot;https://deepskieslab.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;deepskies&lt;/a&gt; and &lt;a href=&quot;https://universetbd.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;universeTBD&lt;/a&gt; open AI communities.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I’m grateful to Prof. Anna Scaife for encouraging me in building Zoobot, even when it meant spending more time writing code than papers. It was a gamble and I’m glad it’s paying off. I’m also grateful to the Dunlap Institute for continuing to support my work building these tools for the community and applying them to Euclid. Finally, I am, as ever, grateful to the Galaxy Zoo volunteers who make this all possible.&lt;/p&gt;
&lt;hr&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;In the &lt;a href=&quot;https://arxiv.org/abs/2110.12735&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;first&lt;/a&gt; Zoobot paper, I studiously avoided using the phrase `foundation model’ because it was controversial at the time; some researchers felt it dangerously implied that AI models could be a solid foundation. Instead I just described what they are: “adaptable” models that “learn meaningful semantic representations of galaxies that are useful for new tasks on which the models were never trained”.&lt;/p&gt;
&lt;a href=&quot;#fnref-1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;With the possible exception of &lt;a href=&quot;https://arxiv.org/abs/2304.05350&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Daglit 2023&lt;/a&gt;, who recently trained a large CoAtNet-like model (~300M params) on Galaxy10 DECaLS (27k images) and hit about 94% top-1 accuracy. That’s much better than baselines with typical models, and about the same as &lt;a href=&quot;https://ui.adsabs.harvard.edu/abs/2023arXiv231101500P/abstract&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;another paper&lt;/a&gt; focused on using equivariance (and small models). I’m doubtful that the underlying Galaxy10 DECaLS labels are 94% accurate - but that’s a topic for another blog.&lt;/p&gt;
&lt;a href=&quot;#fnref-2&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Dunlap Fellowship Plans]]></title><description><![CDATA[My Dunlap Fellowship plan for detailed morphology in Euclid and Rubin]]></description><link>https://walmsley.dev/posts/rubin-euclid-dunlap-fellowship</link><guid isPermaLink="false">https://walmsley.dev/posts/rubin-euclid-dunlap-fellowship</guid><pubDate>Sat, 15 Jul 2023 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;I’ll be starting as a Dunlap Fellow at the University of Toronto from September 2023. I’m hyped to start officially running my own research program.&lt;/p&gt;
&lt;p&gt;In this post, I’d like to share what I’m hoping to do. The truth is I can’t do it on my own. If you’re interested in building shared software tools across surveys, in crowdsourcing and human-AI collaboration, and of course in applying deep learning to answer science questions, then please reach out. I’d love to chat.&lt;/p&gt;
&lt;h2 id=&quot;detailed-morphology-for-euclid-and-rubin&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#detailed-morphology-for-euclid-and-rubin&quot; aria-label=&quot;detailed morphology for euclid and rubin permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Detailed Morphology for Euclid and Rubin&lt;/h2&gt;
&lt;p&gt;I want to measure the detailed morphology of every resolved galaxy in Euclid and Rubin.&lt;/p&gt;
&lt;p&gt;I’ve spent the last four years building the tools to make this possible. The keystone is &lt;a href=&quot;www.github.com/mwalmsley/zoobot&quot;&gt;Zoobot&lt;/a&gt; (&lt;a href=&quot;https://joss.theoj.org/papers/10.21105/joss.05312&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;paper&lt;/a&gt;). Zoobot trains models that accurately answer every question we’ve ever asked at Galaxy Zoo. These “foundation” models can then be adapted to new problems and new surveys using very little new labels. Other folks have adapted Zoobot models to find interacting galaxies in HSC and the Hubble archives, segment bars in SDSS, locate clumps in DESI galaxies, find interesting anomalies like strong lenses, and more.&lt;/p&gt;
&lt;p&gt;Zoobot is effective because of the training data. It’s not a large model - the current best-performing architecture is MaX-ViT Tiny, with 30M parameters, and larger architectures don’t (currently) perform better on my benchmarks. But it’s trained on a unique pretext task - 92M human clicks from Galaxy Zoo volunteers selecting an answer to a Galaxy Zoo question. Predicting the answer to any question is a broad task (like predicting the next word for any sentence). This broad task helps Zoobot learn a general representation that’s easily adaptable to new questions.&lt;/p&gt;
&lt;p&gt;My Fellowship plan is less about trying the very latest architectures (that’s easy thanks to Zoobot’s &lt;code class=&quot;language-text&quot;&gt;timm&lt;/code&gt; support) and more about thoughtfully including more data and more pretext tasks. Practitioners sometimes call this data-centric ML.&lt;/p&gt;
&lt;p&gt;The outline below is simply Plan A for applying Zoobot to Euclid and Rubin. Perhaps you have better ideas - if so, tell me!&lt;/p&gt;
&lt;h2 id=&quot;label-efficient-learning-contrastive-learning-active-learning-and-domain-adaption&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#label-efficient-learning-contrastive-learning-active-learning-and-domain-adaption&quot; aria-label=&quot;label efficient learning contrastive learning active learning and domain adaption permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Label-efficient Learning: Contrastive Learning, Active Learning, and Domain Adaption&lt;/h2&gt;
&lt;p&gt;I want to have a morphology catalog ready on the day of Euclid’s DR1 release (Dec 2024, internally).&lt;/p&gt;
&lt;p&gt;First, we can use contrastive learning to exploit unlabelled images. We’ve tested this on &lt;a href=&quot;https://arxiv.org/abs/2206.11927&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DESI&lt;/a&gt; and on &lt;a href=&quot;https://arxiv.org/abs/2305.16127&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Radio Galaxy Zoo&lt;/a&gt; and found that contrastive learning reduces the amount of labels needed to achieve a given performance. We did this with BYOL, and might next try some more recent frameworks like MAE/DINO.&lt;/p&gt;
&lt;p&gt;Second, we can use active learning to select the most informative galaxies to label (from Euclid’s preview release, DP1). I first tested this &lt;a href=&quot;https://academic.oup.com/mnras/article/491/2/1554/5583078?login=false&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;back in 2019&lt;/a&gt; for SDSS galaxies (in collab. with Lewis Smith and Yarin Gal, from Oxford CS). Since then we’ve simplified the system and put it serverside on the Zooniverse. We ran it in anger from GZ HSC and we’re now testing it again for GZ JWST.&lt;/p&gt;
&lt;p&gt;Third, we can use domain adaption to make our models more robust to differences between surveys. Work by others, particularly &lt;a href=&quot;https://academic.oup.com/mnras/article-abstract/506/1/677/6296645&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;A. Ciprianovic&lt;/a&gt; and &lt;a href=&quot;https://home.strw.leidenuniv.nl/~mes/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Y. Mes&lt;/a&gt;, shows domain adaption can be effecive for galaxy images. I haven’t tried this yet!&lt;/p&gt;
&lt;h2 id=&quot;going-beyond-classification-segmentation-personalised-anomaly-detection&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#going-beyond-classification-segmentation-personalised-anomaly-detection&quot; aria-label=&quot;going beyond classification segmentation personalised anomaly detection permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Going Beyond Classification: Segmentation, Personalised Anomaly Detection&lt;/h2&gt;
&lt;p&gt;We know we can build accurate classification models, especially with many (50k+) labelled galaxies. Our &lt;a href=&quot;https://ui.adsabs.harvard.edu/abs/2021AAS...23811902W/abstract&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DECaLS&lt;/a&gt; and DESI models are as accurate as 5 to 15 human volunteers. So let’s up our ambition. Let’s do segmentation.&lt;/p&gt;
&lt;p&gt;Accurate classification models must be able to recognise morphological features within the image. So in some fundamental sense, they must “know” where those features are. Work by &lt;a href=&quot;http://dx.doi.org/10.1093/mnras/stac368&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;P. Bhambra&lt;/a&gt; showed this for barred galaxy classifiers using SmoothCAM. Separate early work by A. Spindler shows UNet works straightforwardly on galaxy images. Let’s extend our pretrained classifiers to do segmentation as well. I have a small grant from Meta to develop annotation tools with human-in-the-loop active learning (i.e. you start drawing on the image, and the model completes your brushstroke).&lt;/p&gt;
&lt;p&gt;I’m especially keen to do segmentation for low surface brightness features. Unlike detailed morphology in general (bars, spiral arms, etc) accurately identifying LSB features is an unsolved problem. I think segmentation annotations will be much better for this than classification labels, because these would explicitly tell the model which small part of the image contains the LSB feature. I’m putting together a cross-survey collaboration to give this a try.&lt;/p&gt;
&lt;h2 id=&quot;get-it-right-benchmarking-annotators-as-individuals&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#get-it-right-benchmarking-annotators-as-individuals&quot; aria-label=&quot;get it right benchmarking annotators as individuals permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Get It Right: Benchmarking, Annotators as Individuals&lt;/h2&gt;
&lt;p&gt;Visual galaxy morphology measurements from volunteers currently lacks the statistical rigor of, say, weak lensing inference. I think this is partly because, unlike weak lensing, we have historically not been able to simulate datasets where the right answer is known.
Comparing to expert labels has been used as a work-around - but there simply aren’t many large expert morphology catalogs for modern (post-SDSS) surveys.
If we want visual morphology to be taken as a serious quantative galaxy property in the 21st century, we need to know how often we get the right answer. We could do this with modern galaxy-scale sims (such as FIRE) with &lt;a href=&quot;https://github.com/cbottrell/RealSim&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;realistic synthetic images&lt;/a&gt; and particle/kinematic or new expert labels.&lt;/p&gt;
&lt;p&gt;If we can create a set of galaxies with known “ground truth” labels, we can then adapt our pipeline design to best recover these. I’m especially interested in understanding how individual volunteers learn to answer different questions. When collecting labels we could add personalised advice and examples to guide volunteers who struggle on a question. And we could build models that understand that annotators (both volunteer and expert) as individuals with individual preferences.&lt;/p&gt;
&lt;h2 id=&quot;closing-appeal&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#closing-appeal&quot; aria-label=&quot;closing appeal permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Closing Appeal&lt;/h2&gt;
&lt;p&gt;They say that man makes plans and God laughs. Perhaps I’ll look back on this post as a moment of hubris. But I think everything I’m pitching here is technically feasible. If we can pull it off, we’ll transform our understanding of why galaxies look the way they do. And along the way we’ll enjoy a unique playground for building human-AI collaborative systems.&lt;/p&gt;
&lt;p&gt;It’s a lot to do. I’d love to put together a team of people interested in working on this together. If you’d like to join in, reach out - &lt;a href=&quot;emailto:mike.walmsley@dunlap.utoronto.ca&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;mike.walmsley@dunlap.utoronto.ca&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What exactly do HDBSCAN's parameters do?]]></title><description><![CDATA[How HDBSCAN's parameters affect your clusters]]></description><link>https://walmsley.dev/posts/hdbscan-parameters</link><guid isPermaLink="false">https://walmsley.dev/posts/hdbscan-parameters</guid><pubDate>Mon, 08 May 2023 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;The HDBSCAN docs have an excellent high-level overview of how the algorithm works. But they don’t explain exactly how the HDSCAN code parameters fit in. This is my best effort at working that out.&lt;/p&gt;
&lt;h3 id=&quot;min_points&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#min_points&quot; aria-label=&quot;min_points permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;min_points&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;HDBSCAN constructs a graph linking all nearby points (single linkage tree). But we don’t want to accidentally link two clusters with a single random noise point halfway between. To avoid this, we should try to move noise points further away from other points. That’s done by defining a new distance measure - the mutual reachability distance.&lt;/p&gt;
&lt;p&gt;  core distance: distance to min_point’th nearest neighbour
mutual reachability distance: max(core(a), core(b), distance(a, b))&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If a or b is in a high density area, core(a) or core(b) is low and MRD=distance i.e. no effect.&lt;/li&gt;
&lt;li&gt;If a and b are in low density areas, core(a) and core(b) are high and MRD &gt; distance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the general effect of using MRD as a distance metric is to push points in low density areas further away from points in high density areas. Use this distance to safely construct the graph without accidentally including noise points.&lt;/p&gt;
&lt;p&gt;As you increase &lt;code class=&quot;language-text&quot;&gt;min_samples&lt;/code&gt;, this increases how many points count as a high density area. Consider two points in a moderate density area. If &lt;code class=&quot;language-text&quot;&gt;min_samples&lt;/code&gt; is low, distance(a, b) &gt; core(a) and core(b) and MRD=distance(a, b) i.e. MRD does nothing. But if &lt;code class=&quot;language-text&quot;&gt;min_samples&lt;/code&gt; is high, core(a) and core(b) &gt; distance(a, b) and so MRD &gt; distance(a, b) i.e. MRD is effectively pushing the points apart before constructing the graph. Greater &lt;code class=&quot;language-text&quot;&gt;min_samples&lt;/code&gt; means you need more neighbours to avoid having your graph distance (MRD) penalised.&lt;/p&gt;
&lt;p&gt;Further, &lt;code class=&quot;language-text&quot;&gt;min_samples&lt;/code&gt; affects whether you’re ultimately considered in a cluster at all.
Points are considered noise once the distance (edge weight) being dropped from the graph reaches that points core distance (i.e. distance to that point’s min_point’th nearest neighbor).&lt;/p&gt;
&lt;!-- singleton points are considered noise, and self-loop of core distance weight is added to every point. 

core distance (self-loop) can&apos;t be longer than MRD to any other points in the MST. If it has a single nearby point, MRD to that point is the core distance (greater than small actual distance) --&gt;
&lt;h3 id=&quot;min_cluster_size&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#min_cluster_size&quot; aria-label=&quot;min_cluster_size permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;min_cluster_size&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This is a bit more intuitive, thankfully.&lt;/p&gt;
&lt;p&gt;We have the graph and now we’re cutting edges to create clusters. Edges are cut in order of longest first. Clearly we can count the number of connected nodes as we go. But not every set of still-connected nodes should be considered a cluster - some will be just a few points falling away. When cutting the graph, how many connected points should count as a cluster?&lt;/p&gt;
&lt;p&gt;If you make a cut and the now-split part of the graph includes more than &lt;code class=&quot;language-text&quot;&gt;min_cluster_size&lt;/code&gt; nodes, consider the cluster as split - we now have two clusters, each with more than &lt;code class=&quot;language-text&quot;&gt;min_cluster_size&lt;/code&gt; points. &lt;/p&gt;
&lt;p&gt;If, instead, fewer than &lt;code class=&quot;language-text&quot;&gt;min_cluster_size&lt;/code&gt; points were disconnected, consider that not a true split creating a new cluster - we just lost a few points in the course of refining our one cluster.&lt;/p&gt;
&lt;p&gt;I hope this helps. Good luck!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Hooks in PyTorch Lightning v2]]></title><description><![CDATA[Updating hooks from Lightning v1 to v2]]></description><link>https://walmsley.dev/posts/pytorch-lightning-v2-hooks</link><guid isPermaLink="false">https://walmsley.dev/posts/pytorch-lightning-v2-hooks</guid><pubDate>Sun, 19 Mar 2023 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;PyTorch Lightning v2.0 has made two major changes to &lt;code class=&quot;language-text&quot;&gt;pl.LightningModule&lt;/code&gt; methods.&lt;/p&gt;
&lt;p&gt;First, &lt;code class=&quot;language-text&quot;&gt;training_epoch_end(outputs)&lt;/code&gt; methods have been removed in favor of &lt;code class=&quot;language-text&quot;&gt;on_training_epoch_end()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Notice how the &lt;code class=&quot;language-text&quot;&gt;_on&lt;/code&gt; function is not quite the same: the &lt;code class=&quot;language-text&quot;&gt;outputs&lt;/code&gt; argument has been removed, requiring users to explicitly store outputs as a &lt;code class=&quot;language-text&quot;&gt;self.&lt;/code&gt; property. The &lt;a href=&quot;https://github.com/Lightning-AI/lightning/releases/tag/2.0.0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;release notes&lt;/a&gt; have a good example:&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;class LitModel(L.LightningModule):
    
    def training_step(self, batch, batch_idx):
        ...
        return {&quot;loss&quot;: loss, &quot;banana&quot;: banana}
    
    # `outputs` is a list of all bananas returned in the epoch
    def training_epoch_end(self, outputs):
        avg_banana = torch.cat(out[&quot;banana&quot;] for out in outputs).mean()  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;class LitModel(L.LightningModule):
    def __init__(self):
        super().__init__()
        # 1. Create a list to hold the outputs of `*_step`
        self.bananas = []
    
    def training_step(self, batch, batch_idx):
        ...
        # 2. Add the outputs to the list
        # You should be aware of the implications on memory usage
        self.bananas.append(banana)
        return loss
    
    # 3. Rename the hook to `on_*_epoch_end`
    def on_training_epoch_end(self):
        # 4. Do something with all outputs
        avg_banana = torch.cat(self.bananas).mean()
        # Don&apos;t forget to clear the memory for the next epoch!
        self.bananas.clear()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The idea is to make it obvious that using &lt;code class=&quot;language-text&quot;&gt;epoch_end&lt;/code&gt; actions requires all the batch-level outputs to be stored until the end of the epoch rolls around.&lt;/p&gt;
&lt;p&gt;If you were using &lt;code class=&quot;language-text&quot;&gt;training_epoch_end(outputs)&lt;/code&gt; to update your &lt;code class=&quot;language-text&quot;&gt;TorchMetric&lt;/code&gt; metrics, as the &lt;a href=&quot;https://torchmetrics.readthedocs.io/en/stable/pages/lightning.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;TorchMetrics docs suggest&lt;/a&gt; (&lt;a href=&quot;https://github.com/Lightning-AI/metrics/issues/1632&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;my issue&lt;/a&gt;), this will now raise an error.&lt;/p&gt;
&lt;p&gt;You might think you could replace the TorchMetrics updates in the similar &lt;code class=&quot;language-text&quot;&gt;training_step_end(outputs)&lt;/code&gt; methods. Unfortunately, and much less obviously from the release notes, these have also been removed - and will now silently do nothing.&lt;/p&gt;
&lt;p&gt;Instead, you can use &lt;code class=&quot;language-text&quot;&gt;on_train_batch_end(outputs)&lt;/code&gt;. For example, in Zoobot:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;def on_train_batch_end(self, outputs, *args):
    self.train_loss_metric(outputs[&apos;loss&apos;])
    self.log(
        &quot;finetuning/train_loss&quot;, 
        self.train_loss_metric, 
        prog_bar=self.prog_bar, 
        on_step=False,
        on_epoch=True
    )&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This appears to work well for multi-GPU training. It also avoids storing batch outputs in memory. Overall I’m grateful to the Lightning team for the new release - I hadn’t noticed the previous memory-consuming behaviour before.&lt;/p&gt;
&lt;p&gt;The Zoobot changes are now on &lt;code class=&quot;language-text&quot;&gt;dev&lt;/code&gt; and will be live on &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; and PyPI in the next few days.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Typesetting Figures for MNRAS]]></title><description><![CDATA[Matching figure size and fonts to MNRAS ]]></description><link>https://walmsley.dev/posts/typesetting-mnras-figures</link><guid isPermaLink="false">https://walmsley.dev/posts/typesetting-mnras-figures</guid><pubDate>Tue, 03 Jan 2023 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;Figures look best when they match the style of the document. How can you make matplotlib figures that match the style of journal paper?&lt;/p&gt;
&lt;p&gt;I mostly publish in MNRAS, so I’ll use that as an example, but this approach should work for any latex paper format (ApJ, NeurIPS, etc.).&lt;/p&gt;
&lt;p&gt;There’s two parts that need adjusting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;graphics elements: primarily figure size, which affects line widths, tick spacing, etc.&lt;/li&gt;
&lt;li&gt;text: primarily the font and size.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;alignleft is-resized&quot;&gt;
  &lt;img src=&quot;https://walmsley.dev/comparison.png&quot; alt=&quot;&quot; class=&quot;wp-image-9572&quot; width=&quot;640&quot;&gt;
  &lt;figcaption&gt;
  The same figure, before (above) and after (below) changing matplotlib&apos;s settings to match the journal style.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;graphics-elements&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#graphics-elements&quot; aria-label=&quot;graphics elements permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Graphics Elements&lt;/h2&gt;
&lt;p&gt;The first and most important step is setting the right figure size. Everything else follows.&lt;/p&gt;
&lt;p&gt;The default matplotlib figure size is &lt;a href=&quot;https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.figure.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;6.4 by 4.8 inches&lt;/a&gt;. To fit in a two column paper format, figures need to be about half that default size. I used to resize the final figure image with &lt;code class=&quot;language-text&quot;&gt;[width=\columnwidth]&lt;/code&gt;. But this makes &lt;em&gt;everything&lt;/em&gt; proportionally smaller - the text, the line widths, etc. I think this is why a lot of student reports (including mine) have borderline-unreadable figures.&lt;/p&gt;
&lt;p&gt;Instead, &lt;strong&gt;make the figure the correct size in the first place&lt;/strong&gt;. You can do this by trial and error, but it’s easiest if you know the actual width required. You can check this in LaTeX with &lt;code class=&quot;language-text&quot;&gt;\the\columnwidth&lt;/code&gt; (&lt;a href=&quot;https://tex.stackexchange.com/a/407373&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;StackOverflow&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For MNRAS, the column width is 240 points (pt). 1pt is 1/72 of an inch, so the column width is exactly 10/3 inches. Set every figure 10/3 inches wide and they will fit perfectly into the MNRAS columns.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;fig, ax = plt.subplots(figsize=(10/3, 3))  # height can be anything
ax.plot(...)
fig.tight_layout()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Matplotlib and Seaborn both have sensible defaults for the size of graphics elements provided you set the figure the same size that it will appear on the page. If you want to tinker further, check out &lt;code class=&quot;language-text&quot;&gt;sns.set_context&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;sns.set&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;text&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#text&quot; aria-label=&quot;text permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Text&lt;/h2&gt;
&lt;p&gt;Figure text looks professional when it is the same font and of a similar size to the body text.&lt;/p&gt;
&lt;h3 id=&quot;sizing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sizing&quot; aria-label=&quot;sizing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sizing&lt;/h3&gt;
&lt;p&gt;If we resize the figure to make it fit in a column (&lt;code class=&quot;language-text&quot;&gt;[width=\columnwidth]&lt;/code&gt;) then the text will also be resized. So it’s crucial to get the figure size right first. Check the section above.&lt;/p&gt;
&lt;p&gt;Got that done? Good. Now let’s set the font size.&lt;/p&gt;
&lt;p&gt;You can check the font size of the body text using the following &lt;a href=&quot;https://tex.stackexchange.com/a/24600&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;LaTeX command&lt;/a&gt;: &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;\documentclass{article}

\makeatletter
\newcommand\thefontsize[1]{{#1 The current font size is: \f@size pt\par}}
\makeatother

\begin{document}
    \thefontsize\small
    \thefontsize\normalsize
    \thefontsize\large
\end{document}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is also measured in points (pt). For MNRAS, \normalsize text is 9pt.&lt;/p&gt;
&lt;p&gt;Now set matplotlib to make text in that size. You can use the &lt;code class=&quot;language-text&quot;&gt;fontsize&lt;/code&gt; argument with most matplotlib commands e.g. &lt;code class=&quot;language-text&quot;&gt;ax.set_xlabel(..., fontsize=9)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I like to make my figures in a dedicated Jupyter notebook with Matplotlib’s global text parameters &lt;a href=&quot;https://stackoverflow.com/a/39566040&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;set&lt;/a&gt; in a cell at the top at the top.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# in points - start with the body text size and play around
SMALL_SIZE = 9
MEDIUM_SIZE = 9
BIGGER_SIZE = 9

plt.rc(&apos;font&apos;, size=SMALL_SIZE)          # controls default text sizes
plt.rc(&apos;axes&apos;, titlesize=SMALL_SIZE)     # fontsize of the axes title
plt.rc(&apos;axes&apos;, labelsize=MEDIUM_SIZE)    # fontsize of the x and y labels
plt.rc(&apos;xtick&apos;, labelsize=SMALL_SIZE)    # fontsize of the tick labels
plt.rc(&apos;ytick&apos;, labelsize=SMALL_SIZE)    # fontsize of the tick labels
plt.rc(&apos;legend&apos;, fontsize=SMALL_SIZE)    # legend fontsize
plt.rc(&apos;figure&apos;, titlesize=BIGGER_SIZE)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There’s no need for the size to match exactly. I find slightly larger axes labels look good.But now the text sizing will be deliberately chosen and consistent for all your figures.&lt;/p&gt;
&lt;p&gt;Before tinkering with the sizing, remember to match the font (below).&lt;/p&gt;
&lt;h3 id=&quot;fonts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fonts&quot; aria-label=&quot;fonts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fonts&lt;/h3&gt;
&lt;p&gt;Seaborn and Matplotlib use minimalist fonts, while journals tend to use fonts that look more serious and typewriter-esque. Changing the figures to use the serious journal font will help keep a consistent visual style. It will also help you precisely match the sizing (above) as different fonts can look different sizes even if they are technically the same points.&lt;/p&gt;
&lt;p&gt;LaTeX sets fonts via &lt;code class=&quot;language-text&quot;&gt;\usepackage{}&lt;/code&gt; in the main document (not in the style file, confusingly) so take a look at which packages your document uses to find the font. This may require some sleuthing.&lt;/p&gt;
&lt;p&gt;MNRAS uses &lt;code class=&quot;language-text&quot;&gt;\usepackage{newtxtext}&lt;/code&gt; which is part of &lt;a href=&quot;https://www.ctan.org/pkg/newtx?lang=en&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;newtx&lt;/a&gt;. The LaTeX Font Catalog &lt;a href=&quot;https://tug.org/FontCatalogue/newtx/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;lists&lt;/a&gt; newtx as using “URW Nimbus Roman”. We can check a sample on &lt;a href=&quot;https://www.fontsquirrel.com/fonts/nimbus-roman-no9-l&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;fontsquirrel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Matplotlib can only use fonts which are installed on your computer. Download URW Nimbus Roman (.otf file) from &lt;a href=&quot;https://www.fontsquirrel.com/fonts/nimbus-roman-no9-l&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;fontsquirrel&lt;/a&gt;. Installing fonts is different for different OS, so you might need to google what to do next. For me, on CentOS, I placed the .otf in the new folder &lt;code class=&quot;language-text&quot;&gt;/home/{user}/.fonts&lt;/code&gt; and ran &lt;code class=&quot;language-text&quot;&gt;fc-cache -v&lt;/code&gt; to check for new fonts.&lt;/p&gt;
&lt;p&gt;Now check the font is installed correctly. &lt;a href=&quot;https://stackoverflow.com/a/8755818&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;This command&lt;/a&gt; will list the install location of every font. You should see the path to your new .otf file, if you installed it.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import matplotlib.font_manager
matplotlib.font_manager.findSystemFonts(fontpaths=None, fontext=&apos;ttf&apos;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we’re ready to set matplotlib to use that font. We need to find what the font is called, using a &lt;a href=&quot;https://stackoverflow.com/a/68810954&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;similar command&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;fpaths = matplotlib.font_manager.findSystemFonts()

for i in fpaths:
    f = matplotlib.font_manager.get_font(i)
    print(f.family_name)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can set matplotlib to use that font with &lt;code class=&quot;language-text&quot;&gt;plt.rc&lt;/code&gt; in just the same way as setting the text size.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;plt.rc(&apos;font&apos;, family=&apos;Nimbus Roman&apos;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Your figures should now have the same font and text size as the journal body text.&lt;/p&gt;
&lt;p&gt;Now all you have to do is write the paper…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Towards Galaxy Foundation Models]]></title><description><![CDATA[Adaptable models through broad pretraining and contrastive learning]]></description><link>https://walmsley.dev/posts/galaxy-foundation-models</link><guid isPermaLink="false">https://walmsley.dev/posts/galaxy-foundation-models</guid><pubDate>Sun, 26 Jun 2022 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This blog is a summary of my ICML Machine Learning for Astrophysics paper “&lt;a href=&quot;https://arxiv.org/abs/2206.11927&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Towards Galaxy Foundation Models with Hybrid Contrastive Learning&lt;/a&gt;”.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Computer science is coming to terms with a result that’s both exciting and tragic.
For nearly any task, training a model directly on that task works less well than finetuning some existing large model that was pretrained on a huge and diverse dataset. These models are (controversially) called &lt;a href=&quot;https://arxiv.org/abs/2108.07258&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;foundation models&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is exciting because we can build better models than before - models which are not only more accurate but also more robust. It’s tragic because it risks entrenching well-resourced labs as the highly-paid gatekeepers of those models. But first let’s consider what this means for you.&lt;/p&gt;
&lt;p&gt;My impression of our field is that many extragalactic astronomers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have a specific galaxy morphology question &lt;strong&gt;not answered by GZ’s questions&lt;/strong&gt;  (e.g. finding a rare galaxy type)&lt;/li&gt;
&lt;li&gt;Have 100-10,000 expert-labelled galaxies where the answer is known&lt;/li&gt;
&lt;li&gt;Want to solve the problem with deep learning (for effectiveness and for hype/career impact) but are not DL experts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Foundation models are perfect for this. Thanks to pretraining, they can be adapted to new tasks using very little data. &lt;strong&gt;I want to create foundation models for galaxies using Galaxy Zoo&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class=&quot;alignleft is-resized&quot;&gt;
  &lt;img src=&quot;https://galaxyzooblog.files.wordpress.com/2022/06/screenshot-2022-06-27-at-06-31-57-cvpr-2022-fgvc9.png?w=1024&quot; alt=&quot;&quot; class=&quot;wp-image-9572&quot; width=&quot;456&quot;&gt;
  &lt;figcaption&gt;
  Finetuning pretrained &quot;foundation&quot; models can answer new questions with minimal data. These ring galaxies were found by finetuning Zoobot, a CNN pretrained on those questions, with ~200 examples of rings.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I previously open-sourced &lt;a href=&quot;www.github.com/mwalmsley/zoobot&quot;&gt;Zoobot&lt;/a&gt; - a CNN pretrained to solve every GZ DECaLS DR5 question. My tests showed that adapting Zoobot worked better than adapting from ImageNet or training the same model directly.&lt;/p&gt;
&lt;p&gt;This new paper takes the same idea and scales it up. I make two key changes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;More labels: I train on &lt;strong&gt;four separate Galaxy Zoo campaigns&lt;/strong&gt;, with nearly 100M human clicks between them.&lt;/li&gt;
&lt;li&gt;More images: I use contrastive learning to benefit from &lt;strong&gt;1.3M images that haven’t been labelled by humans&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Training on different Galaxy Zoo campaigns is tricky because the questions and answers are different between campaigns and images are usually only labelled in a single campaign. So what should the model predict? Happily, the Dirichlet loss function I introduced in &lt;a href=&quot;https://arxiv.org/abs/2102.08414&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GZ DECaLS&lt;/a&gt; can handle this naturally. The loss essentially measures &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p(k|w, N)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03148em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02691em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.16666666666666666em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10903em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; i.e. the odds of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;k&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.69444em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03148em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; out of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.68333em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10903em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; volunteers giving some answer to some question and for some deep learning model &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.43056em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02691em;&quot;&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. But when &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.68333em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10903em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is 0, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p(k=0|N=0, w) = 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03148em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2777777777777778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2777777777777778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.10903em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2777777777777778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2777777777777778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.16666666666666666em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02691em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2777777777777778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2777777777777778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.64444em;vertical-align:0em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and so the w doesn’t affect the loss - hence unanswered questions have no effect on training. It’s therefore easy to learn from galaxies with only a few answered questions: &lt;strong&gt;if the question is not answered, the model simply ignores it&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To train on totally unlabelled images - where no questions in any GZ campaign have been answered - I used the contrastive learning framework Bootstrap Your Own Latent (&lt;a href=&quot;https://arxiv.org/abs/2006.07733&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;BYOL&lt;/a&gt;). This essentially presents two randomly-augmented versions of the same image to two networks, and asks one network to predict the internal representation of the other network. Because they see differently-augmented images, the representations of both must be invariant to those augmentations, which provides a learning signal. But &lt;strong&gt;BYOL is unsupervised&lt;/strong&gt;, and I want to benefit from both unlabelled and labelled images. I did this by &lt;strong&gt;adding a supervised prediction head to one of BYOL’s networks&lt;/strong&gt;, forcing it to both predict the representation of another network &lt;strong&gt;and&lt;/strong&gt; solve the supervised Dirichlet loss task at the same time.&lt;/p&gt;
&lt;figure class=&quot;alignleft is-resized&quot;&gt;
  &lt;img src=&quot;https://galaxyzooblog.files.wordpress.com/2022/06/screenshot-2022-06-26-at-23-23-52-cvpr-2022-fgvc9.png?w=1024&quot; alt=&quot;&quot; class=&quot;wp-image-9572&quot; width=&quot;456&quot;&gt;
  &lt;figcaption&gt;Adding a new supervised head (top) to BYOL (Grill 2020) helps guide the otherwise-unsupervised method to solve downstream tasks astronomers care about.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Making these two changes creates a model which substantially outperforms both direct training and pretraining, for the specific task of finding ring galaxies given scarce labels. &lt;/p&gt;
&lt;p&gt;Historically, Galaxy Zoo has shared catalogs of vote counts for questions we hoped would be generally useful to many people. Choosing these questions is a compromise between scientific precision, broad applicability, and limited volunteer time. Now we no longer need to compromise. I believe Galaxy Zoo can shift towards &lt;strong&gt;creating adaptable foundation models that you can use to answer exactly the questions you care about&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I’d love to test this on more than just ring galaxies. If you have a small expert-labelled dataset centered on a specific question, please reach out (&lt;a href=&quot;emailto:m.walmsley@utoronto.ca&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;email&lt;/a&gt;, &lt;a href=&quot;https://www.twitter.com/mike_walmsley_&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;twitter&lt;/a&gt;).&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Practical Galaxy Morphology Tools]]></title><description><![CDATA[Using deep learning representations to solve new tasks]]></description><link>https://walmsley.dev/posts/practical-galaxy-tools</link><guid isPermaLink="false">https://walmsley.dev/posts/practical-galaxy-tools</guid><pubDate>Thu, 21 Oct 2021 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This blog is a summary of my paper “Practical Galaxy Morphology Tools from Deep Supervised Representation Learning”.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What does a CNN learn? &lt;/p&gt;
&lt;p&gt;At heart, deep learning is all about learning to make useful representations. Models need to learn a function to map an image (say) onto a lower-dimensional vector that represents the content of the image. That representation can then be used to make predictions, often by feeding it to a few final dense layers.&lt;/p&gt;
&lt;p&gt;Representations have recently become really important in the natural language (NLP) community. By training models to predict masked words in sentences, essentially all digital text becomes useful training data. This allows groups with enough cash and engineers to train ridiculously large models with billions to trillions of parameters. While there’s a degree of “mine is bigger than yours”, larger models are genuinely useful: thanks to all that training data, the representations they learn are excellent for fine-tuning to downstream tasks like summarising news articles or writing code.&lt;/p&gt;
&lt;p&gt;Could such an approach work for astronomy? Self-supervised methods have made huge progress in the last year (see e.g. simCLR). That said, self-supervised methods (and unsupervised methods more broadly) are not informed by human labels and thus might learn representations that are not as scientifically meaningful as supervised methods. &lt;/p&gt;
&lt;figure class=&quot;alignleft is-resized&quot;&gt;
  &lt;img src=&quot;https://galaxyzooblog.files.wordpress.com/2021/10/screenshot-2021-10-21-at-14.23.38.png?w=1024&quot; alt=&quot;&quot; class=&quot;wp-image-9572&quot; width=&quot;456&quot;&gt;
  &lt;figcaption&gt;Schematic of our approach. By training to answer all the diverse Galaxy Zoo questions, our models learn a general representation that is useful for tasks on which the model was never trained.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In my paper, I show that we can train excellent galaxy representations using a supervised approach. The key is Galaxy Zoo. Because the GZ questions are very broad, and my models have to learn to answer all those questions with the same representation, they end up learning a general representation that is useful for new tasks on which the model was never trained. &lt;/p&gt;
&lt;p&gt;This is much like how ImageNet pretraining is helpful for other terrestrial tasks because ImageNet is so broad. Pretraining on a broad galaxy task, however, works much better than a broad terrestrial task. I test this by trying to find ring galaxies using networks pretrained on GZ, pretrained on ImageNet, or trained from scratch. The GZ-pretrained network performs best. Interestingly, finetuning layers below the head is much less important than for the ImageNet-pretrained network, exactly as expected if the GZ representation is more useful.&lt;/p&gt;
&lt;figure class=&quot;alignleft is-resized&quot;&gt;
  &lt;img src=&quot;https://galaxyzooblog.files.wordpress.com/2021/10/loss_by_rings-1.png?w=1024&quot; alt=&quot;&quot; class=&quot;wp-image-9572&quot; width=&quot;456&quot;&gt;
  &lt;figcaption&gt;When fine-tuning to find ring galaxies, it is much more effective to pretrain on Galaxy Zoo (blue) than ImageNet (orange, purple) or train from scratch (black dashed). This is because the Galaxy Zoo representation is already useful to find rings, and likely other kinds of galaxies as well.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The obvious upshot is that you can finetune our GZ models to solve your own galaxy morphology tasks using just hundreds of labelled examples. Want to find irregular galaxies? You can do that. Close pairs? Probably! Tidal features? Go for it.&lt;/p&gt;
&lt;p&gt;You can find code, documentation and pretrained models at &lt;a href=&quot;https://github.com/mwalmsley/zoobot&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://github.com/mwalmsley/zoobot&lt;/a&gt;. I’ve spent a long time writing guides and minimal working examples for you to adapt. Everything is designed to be accessible to researchers with no previous deep learning experience. &lt;/p&gt;
&lt;p&gt;Our representations are also already useful to solve certain new tasks for which the models were never trained. I show two such tasks in the paper:  a similarity search, where you can find the most similar galaxies to a query galaxy, and a human-in-the-loop anomaly detection system, which uses the models’ understanding of similarity to learn which galaxies a user is personally most interested in. Both work very well thanks to the representations.&lt;/p&gt;
&lt;p&gt;I think the future of ML for galaxy morphology will start to include the thoughtful sharing of representations. The jury is still out whether those representations are supervised, self-supervised, some combination of the two, or some method that hasn’t been found yet.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Getting Started with Deep Learning for Astronomers]]></title><description><![CDATA[How to start using deep learning for useful science]]></description><link>https://walmsley.dev/posts/deep-learning-for-astro</link><guid isPermaLink="false">https://walmsley.dev/posts/deep-learning-for-astro</guid><pubDate>Sat, 07 Aug 2021 12:46:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Welcome - come on in. Sorry for the debris. Grab a chair - steal Nick’s, he’s always in the lab.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Your supervisor said you’ll be using deep learning? But nobody actually told you how? Yes, you’ll find that a lot around here. Let’s see - what do you need to know…&lt;/em&gt;&lt;/p&gt;
&lt;!-- and asked if I could &quot;get you started&quot;? Y --&gt;
&lt;h2 id=&quot;what-are-you-trying-to-do&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-are-you-trying-to-do&quot; aria-label=&quot;what are you trying to do permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What are you trying to do?&lt;/h2&gt;
&lt;p&gt;It is tempting to take the latest, fanciest model design you can find on &lt;a href=&quot;http://www.paperswithcode.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;paperswithcode&lt;/a&gt; and throw it at your problem.
If you are doing “CV-driven research”, with the aim of moving into industry or just riding the deep learning hype, that’s a perfectly fair approach - just be honest with your collaborators about what you’re trying to achieve.
However, if you’re trying to do good science, this will cause two headaches. First, fancy models have drawbacks; more code and more parameters make them generally slow, data-hungry, and hard to debug. Second, your paper will quickly be superceded by the next person using the inevitable slightly-fancier model.&lt;/p&gt;
&lt;p&gt;A better strategy is to think carefully about what makes your problem hard, and then search for an approach that targets the hard parts. Maybe you are classifying faint tidal features in galaxy images, and so clever preprocessing might help. Maybe you have very little labelled data, and so you might look for ways to learn from unlabelled data or to intelligently choose which data to go out and label. Maybe the physics of the problem involves some symmetries or rules you can bake into your model. Some challenges will be unique to your astronomical context and this might be an opportunity to do some novel computer science research. When your method follows from your problem, your models will work better and your paper will stand out as thoughtful and original.&lt;/p&gt;
&lt;p&gt;Most importantly, stay focused on the science question. The most common audience response at machine-learning-in-astro conference tracks is “So what?“. You have to be able to say what your method will be able to tell us about the universe. Even if you don’t have a single specific science question - perhaps you’re aiming to make an automated catalog or optimize a telescope schedule - you should be clear on how those outcomes will support other people’s science. This is the difference between making an impact in your field and spending a year carefully solving the wrong problem.&lt;/p&gt;
&lt;h2 id=&quot;what-can-i-read&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-can-i-read&quot; aria-label=&quot;what can i read permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What can I read?&lt;/h2&gt;
&lt;p&gt;The good news is that there are thousands of websites to learn from. The bad news is that there thousands of websites to learn from. Turns out, &lt;a href=&quot;https://walmsley.dev&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;anyone can make one&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Books (remember them?) are surprisingly helpful. I suggest
&lt;a href=&quot;http://www.deeplearningbook.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;www.deeplearningbook.org&lt;/a&gt;. It’s written by the inventor of GANs and strikes a good balance between words and math.&lt;/p&gt;
&lt;h2 id=&quot;what-can-i-ignore-at-first&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-can-i-ignore-at-first&quot; aria-label=&quot;what can i ignore at first permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What can I ignore at first?&lt;/h2&gt;
&lt;p&gt;Many blogs tell you all the things you need to learn. I found this overwhelming. Let me instead tell you what not to learn.&lt;/p&gt;
&lt;p&gt;The big thing to ignore is math. You’ve made it through a Physics degree (probably) and that puts you ahead of most folks trying to pick up deep learning. You have all the rusty tools you need to get the basic math.&lt;/p&gt;
&lt;p&gt;You should learn the &lt;em&gt;idea&lt;/em&gt; of backpropogation (calculating first derivatives at each layer, then combining them with the chain rule ) but you don’t have to work through the equations - that’s what software is for. You should be able to explain to your supervisor how layers work (try at your own risk) but you don’t need to write out the operations with Einstein notation.  You don’t need to brush up on linear algebra (phew). &lt;/p&gt;
&lt;p&gt;Math is foundational and, like all foundations, is best left buried until an extension is needed.&lt;/p&gt;
&lt;p&gt;The other big thing to ignore is deployment. Much of the online wisdom is written by engineers, for engineers.  They  want machine learning pipelines running on multiple GPUs, on the cloud, on Kubernetes, on microcontrollers, in the browser, inside your phone and behind your eyes. You need it to run on your laptop first. Most astronomers will probably never need it to run anywhere else.&lt;/p&gt;
&lt;p&gt;This brings me to:&lt;/p&gt;
&lt;h2 id=&quot;dont-i-need-a-gpu&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dont-i-need-a-gpu&quot; aria-label=&quot;dont i need a gpu permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Don’t I need a GPU?&lt;/h2&gt;
&lt;p&gt;Yes and no. &lt;/p&gt;
&lt;p&gt;You want to train models quickly so you can find out what works. The nightmare scenario is setting a model training, spending the rest of the day hiding from imposter syndrome on Netflix, waking up tomorrow to find it didn’t work, and repeating until running out of either funding or sanity.&lt;/p&gt;
&lt;p&gt;GPUs are unquestionably useful in shortening the cycle. Switching from a standard CPU to a standard gaming GPU might speed up your training by roughly a factor of five. But here are some things which will speed you up much more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Solving the right problem in the first place (see above)&lt;/li&gt;
&lt;li&gt;Using a “dummy” model to check your data pipeline and metrics&lt;/li&gt;
&lt;li&gt;Training for one epoch to make sure your model doesn’t break&lt;/li&gt;
&lt;li&gt;Using live logging like &lt;a href=&quot;https://www.tensorflow.org/tensorboard&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;TensorBoard&lt;/a&gt; to monitor your model and cancel training if it’s going nowhere&lt;/li&gt;
&lt;li&gt;Using “early stopping”, where training is cancelled if a model fails to improve over a set number of epochs, similarly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, train smart not hard.&lt;/p&gt;
&lt;h2 id=&quot;im-ready-for-a-gpu-how-do-i-get-access-to-one&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#im-ready-for-a-gpu-how-do-i-get-access-to-one&quot; aria-label=&quot;im ready for a gpu how do i get access to one permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I’m ready for a GPU. How do I get access to one?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Buy one.&lt;/strong&gt; Departments and supervisors apply for funding to carry out research, and this funding often includes &lt;a href=&quot;&quot;&gt;money for research equipment&lt;/a&gt;. GPUs are useful (sometimes vital) equipment for your research; you may be able to pitch your supervisor or department to buy you one. You should be able to explain how it will help (tensors go brrr) and why the current computing resources aren’t appropriate. It might feel like a lot to ask for as a lowly PhD student, and it might be, but it also might be less of a big deal than you think. If you don’t ask, you’ll never know. But do talk to your supervisor first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Share one&lt;/strong&gt;. Most Physics departments and universities will have compute clusters available to staff and graduate students. They grow organically by accreting hardware bought with grant money for particular projects. IT support can vary from “I’ve had a look at your submission script and fixed it for you, and by the way here’s how to do better logging&lt;em&gt;” to ”&lt;/em&gt;obviously* you do it like &lt;em&gt;this&lt;/em&gt;” to radio silence.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Borrow one&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Google has an excellent free resource called Collab. It is essentially Jupyter Notebook, but running on Google Cloud hardware instead of your computer. You launch a notebook, install the packages you want, off you go. The awkward part is moving data into the cloud so you can use it. One option is using GDrive. GDrive costs £2/month for 100GB and, since it’s also hosted by Google, can be instantly attached to your notebook.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rent one&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;AWS and GCP will both rent you GPUs. They are quite cheap - around $0.40 an hour for “Spot” (i.e. may, rarely, be turned off at any time) reservations. However, you will also need to pay to store your data and probably your environment. This can add up over time and, if you aren’t using the GPUs very much, might well cost more than the GPUs themselves. It’s also the most complicated option to set up. If you want to go on and work in industry as a cloud engineer, it’s a great CV building option, but for a quick project I would avoid it if possible.&lt;/p&gt;
&lt;h2 id=&quot;which-package-should-i-use&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#which-package-should-i-use&quot; aria-label=&quot;which package should i use permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Which package should I use?&lt;/h2&gt;
&lt;p&gt;It doesn’t matter.&lt;/p&gt;
&lt;p&gt;You’ve got (sane) two choices; TensorFlow (by Google) and PyTorch (by Facebook &amp;#x26; friends). They’re very similar. Put briefly: training simple models is easier with TensorFlow, while loading unusual data and debugging are both easier with PyTorch. &lt;/p&gt;
&lt;p&gt;Both will let you write your own GPU-efficient functions in a style so teasingly close to numpy it’ll constantly trip you up:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;np.mean(a)
tf.reduce_mean(a)
torch.mean(a)

np.concat([a, b])
tf.concat([a, b])
torch.cat([a, b])&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Both will let you define models and use them like scikit-learn estimators. TensorFlow is friendlier for this than PyTorch thanks to the Keras module*:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;from tensorflow import keras

model = keras.Sequential([
    keras.layers.Conv2D(...)
    keras.layers.MaxPool(...)
    keras.layers.Dense(...)
])
model.compile(optimizer=&apos;adam&apos;, loss=&apos;binary_crossentropy&apos;)
model.fit(X, y)
preds = model.predict(X)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Told you the deep learning code would be the easy bit.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;PyTorch, on the other hand, requires two tutorials to show you how to &lt;a href=&quot;https://pytorch.org/tutorials/beginner/basics/buildmodel_tutorial.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;define&lt;/a&gt; and &lt;a href=&quot;https://pytorch.org/tutorials/beginner/basics/optimization_tutorial.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;fit&lt;/a&gt; a model. Fitting is a minefield; you should  &lt;strong&gt;absolutely not&lt;/strong&gt; write the training loop for the model yourself. Let other people solve your problem by using the extension package PyTorch Lightning:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;from torch.utils.data import DataLoader
import pytorch_lightning as pl

train_loader = DataLoader(dataset)

trainer = pl.Trainer()
trainer.fit(model, train_loader)
preds = model.predict(train_loader)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ultimately, the most important difference is what your collaborators use.
Sharing tips and debugging help is crucial and much easier if you all use the same framework. &lt;/p&gt;
&lt;p&gt;If you are still not sure - use PyTorch. It’s slightly more popular among computer scientists and so has slightly more of the latest and greatest models.
Now stop worrying about it and go do some science.&lt;/p&gt;
&lt;!-- tf.data.Dataset and tf.keras

TensorFlow used to be tf.add(a, b) and it . 

Stay  away from TFRecords 

There are three different ways to write models

PyTorch, on the other hand

PyTorch has always been eager by default, which made it easier to debug more popular with CS researchers, so pick that if you want the 

Most of the code you write will be numpy and pandas.



If you haven&apos;t, Tensorflow

Tensorflow used to be a 

an originally-independent API for building models that TensorFlow liked so much they [ate it]():

*Shoutout  to... --&gt;</content:encoded></item><item><title><![CDATA[GCR; Permission Denied - Unable to Determine Upload Size]]></title><description><![CDATA[Why this error happens and how to fix it]]></description><link>https://walmsley.dev/posts/gcr-permission-denied-upload-size</link><guid isPermaLink="false">https://walmsley.dev/posts/gcr-permission-denied-upload-size</guid><pubDate>Sun, 22 Sep 2019 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;Google Cloud has &lt;a href=&quot;https://cloud.google.com/compute/docs/containers/deploying-containers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;excellent container support&lt;/a&gt;, including GCR - a private container registry that automatically stores your containers on GCS. But GCR has a weird bug.&lt;/p&gt;
&lt;p&gt;The first time I try to push a new image:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker push $IMAGE_URI&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The upload runs for a few seconds and then fails with the curious error:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;denied: Unable to determine the upload&apos;s size&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What’s going on? &lt;/p&gt;
&lt;p&gt;GCR works by creating a bucket in GCS for your container. For reasons best known to Google, &lt;strong&gt;project owners do not automatically get write access to GCR buckets&lt;/strong&gt;. You need to explicitly give yourself permission.&lt;/p&gt;
&lt;p&gt;To do this, follow &lt;a href=&quot;https://cloud.google.com/container-registry/docs/access-control#granting_users_and_other_projects_access_to_a_registry&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;this guide&lt;/a&gt;. Click the bucket, then permissions, add member. Enter your Google or Service account. Search for and select the role ‘Storage Admin’. &lt;/p&gt;
&lt;p&gt;You should know be able to push to your own GCR. &lt;/p&gt;
&lt;p&gt;Happy coding,&lt;/p&gt;
&lt;p&gt;Mike&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Scaling Galaxy Zoo with Bayesian Neural Networks]]></title><description><![CDATA[Applying active learning to crowdsource labels]]></description><link>https://walmsley.dev/posts/scaling-galaxy-zoo</link><guid isPermaLink="false">https://walmsley.dev/posts/scaling-galaxy-zoo</guid><pubDate>Tue, 21 May 2019 23:46:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This is a technical overview of our &lt;a href=&quot;https://arxiv.org/abs/1905.07424&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;recent paper&lt;/a&gt; (Walmsley 2019) aimed at astronomers. If you’d like an introduction to how machine learning improves Galaxy Zoo, check out this &lt;a href=&quot;https://blog.galaxyzoo.org/2019/05/21/galaxy-zoo-upgrade-better-galaxies-better-science/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I’d love to be able to take &lt;strong&gt;every&lt;/strong&gt; galaxy and say something about it’s morphology. The more galaxies we label, the more specific questions we can answer. When you want to know what fraction of low-mass barred spiral galaxies host AGN, suddenly it really matters that you have a lot of labelled galaxies to divide up&lt;/p&gt;
&lt;p&gt;But there’s a problem: humans don’t scale. Surveys keep getting bigger, but we will always have the same number of volunteers (applying order-of-magnitude astronomer math). &lt;/p&gt;
&lt;p&gt;We’re struggling to keep pace now. When EUCLID (2022), LSST (2023) and WFIRST (2025ish) come online, we’ll start to look silly.&lt;/p&gt;
&lt;figure class=&quot;alignleft is-resized&quot;&gt;
  &lt;img src=&quot;https://galaxyzooblog.files.wordpress.com/2019/05/screen-shot-2019-05-20-at-14.41.25.png&quot; alt=&quot;&quot; class=&quot;wp-image-9572&quot; width=&quot;456&quot; height=&quot;319&quot;&gt;
  &lt;figcaption&gt;Galaxies/day required to keep pace with upcoming surveys now, by 2019 year-end, and by 2022 year-end. Estimates from internal science plan.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To keep up, Galaxy Zoo needs an automatic classifier. Other researchers have used responses that we’ve already collected from volunteers to train classifiers. The best performing of these are convolutional neural networks (CNNs) - a type of deep learning model tailored for image recognition. &lt;strong&gt;But CNNs have a drawback. They don’t easily handle uncertainty.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When learning, they implicitly assume that all labels are equally confident - which is definitely not the case for Galaxy Zoo (more in the section below). And when making (regression) predictions, they only give a ‘best guess’ answer with no error bars.&lt;/p&gt;
&lt;p&gt;In our paper, we use Bayesian CNNs for morphology classification. Our Bayesian CNNs provide two key improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They account for varying uncertainty when learning from volunteer responses&lt;/li&gt;
&lt;li&gt;They predict full posteriors over the morphology of each galaxy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using our Bayesian CNN, we can learn from noisy labels and make reliable predictions (with error bars) for hundreds of millions of galaxies.&lt;/p&gt;
&lt;h3 id=&quot;how-bayesian-convolutional-neural-networks-work&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-bayesian-convolutional-neural-networks-work&quot; aria-label=&quot;how bayesian convolutional neural networks work permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How Bayesian Convolutional Neural Networks Work&lt;/h3&gt;
&lt;p&gt;There’s two key steps to creating Bayesian CNNs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Predict the parameters of a probability distribution, not the label itself&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Training neural networks is much like any other fitting problem: you tweak the model to match the observations. If all the labels are equally uncertain, you can just minimise the difference between your predictions and the observed values. &lt;strong&gt;But for Galaxy Zoo, many labels are more confident than others.&lt;/strong&gt; If I observe that, for some galaxy, 30% of volunteers say “barred”, my confidence in that 30% massively depends on how many people replied - was it 4 or 40?&lt;/p&gt;
&lt;p&gt;Instead, we predict the probability that a typical volunteer will say “Bar”, and minimise how surprised we should be &lt;strong&gt;given the total number of volunteers who replied.&lt;/strong&gt; This way, our model understands that errors on galaxies where many volunteers replied are worse than errors on galaxies where few volunteers replied - letting it learn from every galaxy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Use Dropout to Pretend to Train Many Networks&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Our model now makes probabilistic predictions. But what if we had trained a different model? It would make slightly different probabilistic predictions. We need to &lt;strong&gt;marginalise over the possible models we might have trained&lt;/strong&gt;. To do this, we use dropout. Dropout turns off many random neurons in our model, permuting our network into a new one each time we make predictions.&lt;/p&gt;
&lt;p&gt;Below, you can see our Bayesian CNN in action. Each row is a galaxy (shown to the left). In the central column, our CNN makes a single probabilistic prediction (the probability that a typical volunteer would say “Bar”). We can interpret that as a posterior for the probability that k of N volunteers would say “Bar” - shown in black. On the right, we marginalise over many CNN using dropout. Each CNN posterior (grey) is different, but we can marginalise over them to get the posterior over many CNN (green) - our Bayesian prediction.&lt;/p&gt;
&lt;figure class=&quot;wp-block-image&quot;&gt;
  &lt;img src=&quot;https://galaxyzooblog.files.wordpress.com/2019/05/bar_posteriors_cropped.png&quot; alt=&quot;&quot; class=&quot;wp-image-9573&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Read more about it in &lt;a href=&quot;https://arxiv.org/abs/1905.07424v1&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;the paper&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;active-learning&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#active-learning&quot; aria-label=&quot;active learning permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Active Learning&lt;/h3&gt;
&lt;p&gt;Modern surveys will image hundreds of millions of galaxies - more than we can show to volunteers. Given that, which galaxies should we classify with volunteers, and which by our Bayesian CNN?&lt;/p&gt;
&lt;p&gt;Ideally we would &lt;strong&gt;only show volunteers the images that the model would find most informative.&lt;/strong&gt; The model should be able to ask – hey, these galaxies would be really helpful to learn from– can you label them for me please? Then the humans would label them and the model would retrain. This is active learning.&lt;/p&gt;
&lt;p&gt;In our experiments, applying active learning reduces the number of galaxies needed to reach a given performance level by up to 35-60% (See &lt;a href=&quot;https://arxiv.org/abs/1905.07424v1&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;the paper&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We can use our posteriors to work out which galaxies are most informative&lt;/strong&gt;. Remember that we use dropout to approximate training many models (see above). We show in &lt;a href=&quot;https://arxiv.org/abs/1905.07424&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;the paper&lt;/a&gt; that &lt;strong&gt;informative galaxies are galaxies where those models confidently disagree.&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://galaxyzooblog.files.wordpress.com/2019/05/screen-shot-2019-05-20-at-15.01.22.png&quot; alt=&quot;&quot; class=&quot;wp-image-9576&quot;&gt;
  &lt;figcaption&gt;
    Informative galaxies are galaxies where the each model is confident (entropy H in the posterior from each model is low) but the average prediction over all the models is uncertain (entropy across all averaged posteriors is high). See &lt;a href=&quot;https://arxiv.org/abs/1905.07424&quot;&gt;the paper&lt;/a&gt; for more.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is only possible because we think about labels probabilistically and approximate training many models.&lt;/p&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What galaxies are informative? Exactly the galaxies you would intuitively expect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The model strongly prefers diverse featured galaxies over ellipticals&lt;/li&gt;
&lt;li&gt;For identifying bars, the model prefers galaxies which are better resolved (lower redshift)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;This selection is completely automatic&lt;/strong&gt;. I didn’t realise the lower redshift preference until I looked at the images!&lt;/p&gt;
&lt;p&gt;I’m excited to see what science can be done as we move from morphology catalogs of hundreds of thousands of galaxies to hundreds of millions. &lt;/p&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;p&gt;Mike&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: This post is cross-posted on the official Galaxy Zoo blog &lt;a href=&quot;https://blog.galaxyzoo.org/2019/05/21/scaling-galaxy-zoo-with-bayesian-neural-networks/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;</content:encoded></item></channel></rss>