295 lines
7.6 KiB
Plaintext
295 lines
7.6 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "raw",
|
|
"id": "e1f9a8a0",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"skip_exec: true\n",
|
|
"---"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "1528f88b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from fastai.vision.all import *"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9d21b9fe",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Catalyst with fastai\n",
|
|
"\n",
|
|
"> Incrementally adding fastai goodness to your Catalyst training"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "44d30357",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Catalyst code"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6218b472",
|
|
"metadata": {},
|
|
"source": [
|
|
"We're going to use the MNIST training code from Catalyst's README (as at August 2020), converted to a module.\n",
|
|
"\n",
|
|
":::{.callout-note}\n",
|
|
"\n",
|
|
"The source script for `migrating_catalyst` is in the `examples` subdirectory of this folder if you checked out the `fastai` repo from git, or can be downloaded from [here](https://github.com/fastai/fastai/blob/master/nbs/examples/migrating_catalyst.py) if you're using an online viewer such as Colab.\n",
|
|
"\n",
|
|
":::"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "b73ac9b0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from migrating_catalyst import *"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "51342873",
|
|
"metadata": {},
|
|
"source": [
|
|
"To use it in fastai, we first convert the Catalyst dict into a `DataLoaders` object:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "a53ee0ce",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"data = DataLoaders(loaders['train'], loaders['valid']).cuda()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e4e5883e",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Using callbacks"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e06c568a",
|
|
"metadata": {},
|
|
"source": [
|
|
"In the Catalyst code, a training loop is defined manually, which is where the input tensor is flattened. In fastai, there's no need to define your own training loop - you can insert your own code into any part of the training process by using a callback, which can even modify data, gradients, the loss function, or anything else in the training loop:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "244bb2d8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"@before_batch_cb\n",
|
|
"def cb(self, xb, yb): return (xb[0].view(xb[0].size(0), -1),),yb"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "221452f2",
|
|
"metadata": {},
|
|
"source": [
|
|
"The Catalyst example also modifies the training loop to add metrics, but you can pass these directly to your `Learner` in fastai:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "bf60e413",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"metrics=[accuracy,top_k_accuracy]\n",
|
|
"learn = Learner(data, model, loss_func=F.cross_entropy, opt_func=Adam,\n",
|
|
" metrics=metrics, cbs=cb)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "088216aa",
|
|
"metadata": {},
|
|
"source": [
|
|
"You can now fit your model. fastai supports many schedulers. We recommend using 1cycle:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2db56fc7",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: left;\">\n",
|
|
" <th>epoch</th>\n",
|
|
" <th>train_loss</th>\n",
|
|
" <th>valid_loss</th>\n",
|
|
" <th>accuracy</th>\n",
|
|
" <th>top_k_accuracy</th>\n",
|
|
" <th>time</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0.230145</td>\n",
|
|
" <td>0.292590</td>\n",
|
|
" <td>0.924700</td>\n",
|
|
" <td>0.995000</td>\n",
|
|
" <td>00:13</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"learn.fit_one_cycle(1, 0.02)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "c413a891",
|
|
"metadata": {},
|
|
"source": [
|
|
"As you can see, migrating from Catalyst allowed us to replace 17 lines of code (in `CustomRunner`) with just 3 lines, and doesn't require you to change any of your existing data pipelines, optimizers, loss functions, models, etc. Once you've made this change, you can then benefit from fastai's rich set of callbacks, transforms, visualizations, and so forth.\n",
|
|
"\n",
|
|
"Note that fastai is very different from Catalyst, in that it is much more than just a training loop (although we're only using the training loop in this example) - it is a complete framework including GPU-accelerated transformations, end-to-end inference, integrated applications for vision, text, tabular, and collaborative filtering, and so forth. You can use any part of the framework on its own, or combine them together, as described in the [fastai paper](https://arxiv.org/abs/2002.04688)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "1f55011b",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Changing the model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a4372555",
|
|
"metadata": {},
|
|
"source": [
|
|
"Instead of using callbacks, in this case you can also simply change the model. Here we pull the `view()` out of the training loop, and into the model, using fastai's `Flatten` layer:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "1e2de138",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"model = nn.Sequential(\n",
|
|
" Flatten(),\n",
|
|
" torch.nn.Linear(28 * 28, 10))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "7cefe22b",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can now create a `Learner` and train without using any callbacks:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2c49581d",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: left;\">\n",
|
|
" <th>epoch</th>\n",
|
|
" <th>train_loss</th>\n",
|
|
" <th>valid_loss</th>\n",
|
|
" <th>accuracy</th>\n",
|
|
" <th>top_k_accuracy</th>\n",
|
|
" <th>time</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0.230051</td>\n",
|
|
" <td>0.292577</td>\n",
|
|
" <td>0.924800</td>\n",
|
|
" <td>0.995100</td>\n",
|
|
" <td>00:11</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"learn = Learner(data, model, loss_func=F.cross_entropy, opt_func=Adam, metrics=metrics)\n",
|
|
"learn.fit_one_cycle(1, 0.02)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "107dc10c",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"metadata": {
|
|
"jupytext": {
|
|
"split_at_heading": true
|
|
},
|
|
"kernelspec": {
|
|
"display_name": "python3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|