Lesson-1-pets Benchmarks

Well. I did as told by Jeremy and couldn’t reproduce the results.
Now I am having the same results as @mrandy

The only explanation I can think of is that I wasn’t really running from scratch.

Every time I tried different hyper parameters I’ve just ran again from the line

learn = ConvLearner(data, models.resnet50, metrics=error_rate)

downwards with different hyperparameters.

I thought doing so would redefine the model again from scratch. Correct me if I’m wrong.

The results are achievable though, but now I just have no idea how I achieved them.

Here are the weights saved from the model as shown in the Notebook.
stage-3-50_2nd.pth

If you load the model weights and run learn.validate()you should see the result:
[0.049526975, 0.015302725815408164]

final loss and error_rate

I am frustrated about this. My joy was short-lived.

1 Like

Hey, thanks for checking it out. There is a gap between learn save at cell run-order 16 and learn load at 25, so maybe you did something in the 17-24 range that was the game changer. Can you recall doing anything in that gap that might have given you the big jump? Maybe you stumbled onto a good move that we can try in other models. Whatever you did dropped the error rate way below anything I could think to try.

2 Likes

This man knows how to make things pretty. Did you type the entire markdown table by handle in this small reply box? That would be really impressive.

1 Like

Is there any reason why you specifically used learn.fit instead of learn.fit_one_cycle in the second step?

@ronaldokun I was able to reproduce the 1% error rate (in fact even below 1%) and I am quite sure I found the cause for it.

Each time we create a new ImageDataBunch it generates a new random split of the dataset. What this means is that if you were to create a new ImageDataBunch and reload trained weights you will more than likely end up with a validation set that includes data from the previous training set, so in other words the model has already seen this data and is able to achieve a very low error rate as a result.

In order for the error rate results to be valid we would need to ensure that the validation split is always the same.

To ensure that you always have the same validation split make sure that you don’t forget to re-run np.random.seed(2) (filled in with whatever seed you used) because this seed is not retained after each iteration unless you re-run it.

12 Likes

That is a very convincing explanation!

I thought I was just reloading the learner, but now looking at the run in the notebook I think you are right.

Thank you

1 Like

Only to run with unfrozen layers first with a specific learning rate ( two orders of magnitude below the one I found with learn.lr_find() with the frozen layers ). This is something I saw people doing at kaggle competitions.

The following run with learn.fit_one_cycle() would be the fine-tuning step with cyclic learning rate.

Unfortunately, I can’t recall right now, sorry. This was that kind of executing and changing things without much thought.

1 Like

One doubt: We are running the notebook with np.random.seed(2). This doesn’t ensure the split in the DataBunch is always the same?

3 Likes

Is there a thread/doc somewhere detailing what part of the whole process is reproducible when using the same random seed and what isn’t? I didn’t dig into it yet but at first glance nothing is the same in multiple runs with the same seed.

I intentionally avoid using reproducible runs, because I don’t think it’s a good idea to hide the randomness. However, it is important to use the same validation set each time. That’s why I set the random seed before I create the validation set.

2 Likes

Ok that makes sense, and I agree with your choice of default behaviour. But is there an easy way to force all the (non-CUDA related) randomization to be consistent between runs ? For debug purposes for example.

Yes but you need to re-run this cell block np.random.seed(2) before you re-create the ImageDataBunch otherwise it doesn’t retain the seed on the next iteration.

Thank you to @sgugger for pointing this out in the dev channel!

3 Likes

Have had the same experience (outside of fastai context). Although the respective docs for sklearn say that they obay numpy random seeds, I found that definitely not to be the case (i.e. for random forrest). Not sure how fastai behaves/uses this. Never investigated this further, but I think it has to do with scoping of the variables / context

Well, that explains then. I definitely didn’t run this cell every time.

Thank you very much for the clarification.

Ronaldo

Well, I have finally been able to break the 4% barrier without having to touch “wd” or the like. The only “advanced” thing I did was to enable both of my GPUs using “DataParallel”. I will try to post a link to GitHub once I figure that out later tonight.

In short, of what I changed from original:

bs = 64
np.random.seed(265)
data = ImageDataBunch.from_name_re(path_img, fnames, pat, ds_tfms=get_transforms(), size=320, bs=bs)
learn = create_cnn(data, models.resnet50, metrics=error_rate)
learn.model = torch.nn.DataParallel(learn.model, device_ids=[0, 1])
learn.fit_one_cycle(10, max_lr=slice(1e-3))
learn.unfreeze()
learn.fit_one_cycle(10, max_lr=slice(10e-5, 5e-5))

yielded:
10 0.026167 0.131423 0.036760 (00:44)

learn.validate()
[0.13142301, 0.03675970295158838]

edit Here is the github link to my notebook

3 Likes

@FourMoBro - good job. Try the exact same thing with a single GPU, except make all your learning rates half as big. You should get about the same result. Let us know how you go!

learning rates or batch size to be halved?

Just the learning rates. (You can also try with the same learning rates - now I think of it, actually I think the particular approach you used won’t require any change; but worth experimenting!)