Climate-Resilient Crops · Data Tutorial

Deep Learning on Leaf Images

By the end of this practical you will be able to:

0 Teaching a computer to look at a leaf

A grower walking through a tomato greenhouse can spot a sick plant at a glance. Doing that at the scale of a whole breeding programme, thousands of plants, several times per season, is a different problem. This is where image-based phenotyping comes in: a camera on a drone, a robot or a phone takes the pictures, and a model decides which leaves look diseased.

In this practical you will train such a model yourself. It runs in your browser, on real photographs of tomato leaves. But the real lesson is not "how do I train a model". That turns out to be the easy part, about ten lines of code. The lesson is how do I find out whether I should trust it. You will meet a model with 90% accuracy that is completely worthless, and a model that learns the wrong thing so convincingly that only careful evaluation reveals it.

How this differs from last week's mechanistic model

In the mechanistic modelling practical you simulated a gene regulatory network. There, we supplied the biology: "ABA activates ABF2", "ANAC019 represses ICS1". Those rules were the input, written down by researchers after years of experiments, and the computer only worked out their consequences over time.

Deep learning turns this around completely. Nobody tells the model what a diseased leaf looks like. Nobody writes down "brown lesions with a yellow halo mean Septoria leaf spot". Instead we hand over a pile of photographs, each labelled healthy or infected, and the model works out the rules itself by looking for whatever distinguishes one pile from the other.

The trade-off, and the theme of this practical. A mechanistic model can only ever be as right as the biology you put into it, but you can read it, argue with it, and point at the step you disagree with. A deep learning model can pick up patterns nobody thought to encode, and it needs no theory at all, but you cannot look inside and see what it decided to pay attention to. It might have learned the disease. It might have learned something else entirely that happened to come along with the disease in your photos. Keep that possibility in mind; you will run into it in step 7.
❓ Questions
  • Name one research question about plant resilience where you would rather build a mechanistic model, and one where you would rather train a model on data. What makes the difference?
  • The model you are about to train never receives any information about tomato biology. Is that a strength or a weakness? Argue both sides.

1 The data, and what the model actually sees

We use the PlantVillage dataset: photographs of single tomato leaves against a grey background, each one labelled by a plant pathologist. There is one healthy category and nine disease categories: bacterial spot, early blight, late blight, leaf mold, Septoria leaf spot, spider mites, target spot, yellow leaf curl virus and mosaic virus.

We are going to group all nine diseases together into a single infected class, so the model has to answer one binary question: healthy, or not? We could equally well have trained it to name the specific disease. That is a nine-way problem, and a harder one.

label 0, healthy label 1, infected

Every image has been shrunk to 64 × 64 pixels, which is the size the model works with.

A photograph is only numbers

This is the single most important idea in this section, and it is worth slowing down for. The model has no eyes. It never sees a leaf, a lesion or a colour. What arrives at its input is a grid of numbers, and nothing else.

Each of the 64 × 64 pixels stores three numbers: how much red, how much green and how much blue that pixel contains. A camera records those as whole numbers from 0 to 255, and before feeding them to the model we divide by 255 so everything sits between 0 and 1.

Hover over the leaf below. The panel on the right shows you the actual numbers stored in the small square you are pointing at. This is, quite literally, the model's entire view of the world.

Move your mouse over the leaf. The white square marks the 6×6 patch shown on the right.

Put together: one leaf photo is 64 × 64 × 3 = 12,288 numbers. That is what a single training example is. Everything the model ever learns about tomato disease, it has to extract from patterns in lists of 12,288 numbers, paired with a label that says 0 or 1.
❓ Questions
  • What do these numbers represent exactly? Explain what a single number in this grid means, and what the three numbers per pixel are for.
  • The original photographs are far larger than 64 × 64. What do we lose by shrinking them, and why might we do it anyway?
  • All of these photos were taken against the same plain grey background under similar lighting. Is that helpful or harmful for the model we are about to build?

2 Splitting the data: train and test

Before we train anything, we have to hold some data back. This is one of the most important habits in the whole of machine learning, so it is worth being precise about why.

A model that has already seen a photo can score well on it simply by having memorised it. Memorising tells you nothing about the next leaf, and the next leaf is the entire point: you want a model that works on plants it has never encountered. So we cut the dataset in two. The model learns from the training set, and is judged on the test set (also called the validation set), which it never learns from. Any number you quote about a model's performance should come from data it did not train on.

Below you control how big each half is. Watch what the split does to the number of images the model gets to learn from, and to the number of images your performance estimate is based on.

Notice the tension. Give more data to training and the model has more to learn from, but your test set shrinks and your estimate of how good it is becomes noisier. Give more to testing and you get a more reliable estimate of a weaker model. Somewhere around 80/20 is a common compromise, but there is nothing magic about it.
❓ Questions
  • Why do we split the data into train and test data?
  • List some things that should be taken into consideration when splitting data into train and test.
  • Suppose several photos in the dataset are different leaves from the same plant. Why is it a problem if some end up in training and others in testing?
  • You report your model's accuracy to a colleague. Which of the two numbers on this page should you quote, and why does the other one not count?

3 The best model ever

Before you build your own, let me offer you mine. I have developed a classifier and it reaches roughly 90% accuracy on the test set. Ninety percent, on a real biological problem, with no effort on your part. Press the button and see for yourself.

❓ Questions, before you read any further
  • Do you trust this model? Would you be willing to deploy it in a greenhouse?
  • What would you want to know before deciding? Write down what you would ask for.

Answer those before scrolling on. The rest of this step works through what you should have asked for.

First question: how many of each class are there?

Accuracy is just the fraction of images the model gets right. That single number hides something important, and the something is the class distribution: how many of each kind of leaf there are in the first place. Drag the slider to change how many healthy leaves are in the dataset, and watch what happens to my model's accuracy.

In the full PlantVillage tomato set only about 9% of the leaves are healthy, because the dataset was built to study diseases. Real field data is often skewed the same way, and sometimes skewed the other way if most of your crop is fine. Either way, the number to beat is not 50%. It is whatever you get by always guessing the most common class.

Second question: which leaves does it get right?

Overall accuracy averages over both classes, so a model can be excellent on one and hopeless on the other without the single number ever showing it. Split the score by class and look again.

Third question: what kind of mistakes does it make?

The confusion matrix lays out all four possible outcomes instead of collapsing them into one number. Each leaf is either truly healthy or truly infected (the two rows), and the model either called it healthy or infected (the two columns). Every leaf lands in exactly one of the four boxes. The two boxes on the diagonal are the correct answers, and the two off it are the two different ways of being wrong.

Confusion matrix on the test set

Fourth question: does it rank the leaves sensibly?

There is one more angle, and it takes a little more explaining, so let's build it up slowly.

A classifier does not really answer "healthy" or "infected". It produces a score, and we compare that score against a cut-off to get an answer. Change the cut-off and you get a different set of answers from exactly the same model. So judging a model at one cut-off only tells you about that one choice.

The ROC curve gets around this by trying every possible cut-off and plotting two things at each one:

Both are things you want to trade off against each other. Catching more infections always means raising more false alarms, and the curve shows you the exchange rate. A model that is good at telling the classes apart can catch a lot of infections while raising few false alarms, so its curve bulges towards the top left. A model with no ability to discriminate can only buy catches by accepting an equal share of false alarms, so its curve runs along the diagonal. That diagonal is drawn dashed on the plot below as a reference for "no better than guessing".

The area under the curve, the AUROC, compresses that into one number: 1.0 is a perfect ranker, 0.5 is a coin flip.

ROC curve on the test set

More background on these two: thresholding and the confusion matrix and ROC and AUC.

❓ Questions
  • Does the class distribution change your view on the model's accuracy score?
  • Explain what both visualisations show exactly.
  • Based on these evaluations, does the model provide useful predictions?
  • Can you say, in one sentence, what rule this model is using to make its predictions?
  • Look back at what you wrote down earlier. Did you ask for the right things, and would you still deploy it?

4 Training a real network

Now let's train an actual neural network and see whether it can beat that. What follows is not a demonstration or a replay. The network really is built and trained in your browser, on your machine, from the images above. That is also why it takes a few seconds.

You do not need to know the internals to follow what happens. Training works like this: the network starts with random settings and therefore guesses randomly. We show it a training image, it produces a number between 0 and 1, and we compare that with the true label. If it was wrong, every internal setting is nudged a little in the direction that would have made the answer better. Then the next image. One full pass through all the training images is called an epoch.

The model we use is a small convolutional network, the variety designed for images, which looks for local patterns like edges, spots and patches of colour rather than treating each of the 12,288 numbers as unrelated.

One thing to fix before you start

Your dataset is currently about 10% healthy, because that is what step 3 needed in order to make its point. That is a bad setting to train on. If nine out of ten training images are infected, the laziest thing the network can do is answer "infected" almost every time, and that already scores well. You will have built your own version of the model you just rejected.

So before training, raise the healthy fraction. This is the same slider as in step 3, repeated here for convenience.

Currently at 10% healthy. Training here will probably collapse into predicting "infected" for nearly everything. Raise the slider and watch the difference, or train it at 10% first to see the collapse for yourself.

Now train it

More epochs means more passes over the data and a better-fitted model, up to the point where it starts memorising. Watch the curves rather than trusting a fixed number: you want to train until the test curve stops improving.

Not trained yet.

Loss, how wrong the model is. Lower is better.

Accuracy over the same run. Higher is better.

Why two lines on each chart? The solid line is measured on the training images, the dashed line on the test images the model never learns from. When the training line keeps improving while the test line stalls or gets worse, the model has started memorising its training set rather than learning something general. That is overfitting, and the test line is the only place you can see it.

What does the network actually output?

The network does not answer "healthy" or "infected". Its final output is a single number between 0 and 1 for each image. Here are its raw outputs for ten test images:

The number under each leaf is the network's raw output; the line below it is the true label.

❓ Questions
  • What do these predicted numbers represent?
  • Look at an image where the number is close to 0.5. What does that tell you, and what would you want to happen to such a case in practice?
  • Run the training again with more epochs. What happens to the two lines on each chart, and what does the gap between them mean?

5 Turning outputs into decisions

To get from a number between 0 and 1 to an actual decision, we need a threshold: above it we call the leaf infected, below it we call it healthy. Nothing forces that threshold to be 0.5. Choosing it is a decision about which mistake you would rather make, and it is yours to make, not the model's.

Note what the threshold does and does not change. Sliding it moves cases between the boxes of the confusion matrix, so accuracy, precision and recall all move with it. The ROC curve does not move at all: it already summarises every threshold at once. That is exactly why AUROC is a useful way to compare two models before you have decided how you want to use them.
❓ Questions
  • Which confusion matrix is more useful? The one on the train dataset or the test dataset?
  • What effect does changing the threshold have on the confusion matrix?
  • Would you prefer this deep learning model over the model you tested earlier? Why?
  • Imagine this model screens incoming plant material at a quarantine station, where letting a diseased plant through is far worse than a false alarm. Which way would you move the threshold, and what does it cost you?

6 Looking at the mistakes

Numbers tell you how often the model is wrong. Looking at the images tells you why. This is one of the most useful habits you can pick up: whenever a model disappoints you, go and look at the cases it got wrong. Each group below corresponds to one box of the confusion matrix, and the groups re-sort themselves as you move the threshold.

❓ Questions
  • Look at the false negatives, the infected leaves the model called healthy. Can you see, by eye, why these were hard?
  • Move the threshold up and down. Which group grows, which shrinks, and can you get both error groups to be empty at once?
  • If you had budget to photograph 200 more leaves, which kind would you go and collect, based on what you see here?

7 When the data lies to you

Here is a story that happens more often than anyone would like. A grower photographs the healthy part of the field in the morning and walks over to the infected part later in the day, when the light has changed. Nobody notices; the photos all look fine. But every healthy photo is now slightly darker than every infected one.

Let's simulate exactly that. In the training set we darken every healthy leaf a little. And because the model will be used by other growers whose habits differ, in the test set we darken the infected ones instead. Nothing about the leaves themselves has changed. Only the lighting has.

Training set, healthy leaves darkened

Test set, infected leaves darkened

❓ Question, commit to an answer before you press the button
  • How do you think this will affect the model's performance on the training set, and on the test set?
Not trained yet.

Loss. Watch the two lines pull apart.

Accuracy on the training set against the test set.

Confusion matrix on the test set (threshold 0.5)

❓ Questions
  • What do you think of the model performance?
  • How would you explain these results?
  • An AUROC below 0.5 is a strange thing to see. What does it mean about the model's ranking, and how could that come about here?
  • Nothing in the training run itself looked wrong. What would have had to happen for someone to catch this before deployment?
  • Could you think of one or more method(s) to mitigate this?

8 Fixing it with image augmentation

The model latched onto brightness because, in its training set, brightness was a perfectly reliable clue. One way to take that clue away is image augmentation. Before each pass we randomly mess with the training images: mirror them, brighten or darken them, nudge their contrast. The labels stay the same.

Crucially, this is re-rolled every epoch, so the model never sees the same version of an image twice. Press the button below a few times to see different random versions of the same training leaves.

The same confounded training leaves as in step 7, randomly flipped, brightened/darkened and contrast-adjusted.

Augmented images are harder to learn from, so this model usually needs more epochs than the others before it catches up. If the improvement looks disappointing, train it for longer before concluding that augmentation did not work.

Not trained yet.

Loss. Compare the gap with the one in step 7.

Accuracy on the training set against the test set.

Where are its mistakes now?

The same confusion matrix and threshold slider as in step 5, this time on the augmented model. Compare the shape of the errors against step 7. A model that has stopped leaning on brightness should spread its mistakes around rather than piling them all into one box.

Train the model above to see its confusion matrix.

Test-set ROC curves compared. Train the step 7 model first so there is something to compare against.

❓ Questions
  • Explain how image augmentation aids generalisability.
  • Augmentation did not add a single new photograph. Where, then, did the improvement come from?
  • Is augmentation a complete fix here? Compare this model against the one you trained in step 4 on clean data, and explain the difference that remains.
  • We randomly changed brightness, contrast and left–right mirroring. Why would randomly rotating leaves by 180° be fine here, but randomly changing the colour from green to brown be a terrible idea?
  • If you have extra time, pick one or more of these to investigate:
    • How is model performance changed if you shrink the dataset or change the class distribution (the slider in step 3)?
    • Could this classifier be applied to a species other than tomato? What would you need to check first?
    • Can you think of, or find, other evaluation metrics that would be useful here?

✓ Check your understanding