This tutorial explains the quickstart examples and some core abstractions FastAI.jl is built on.
On the quickstart page, we showed how to train models on common tasks in a few lines of code like these:
using
FastAI
data
,
blocks
=
load
(
datarecipes
(
)
[
"
imagenette2-160
"
]
)
task
=
ImageClassificationSingle
(
blocks
)
learner
=
tasklearner
(
task
,
data
,
callbacks
=
[
ToGPU
(
)
]
)
fitonecycle!
(
learner
,
10
)
showoutputs
(
task
,
learner
)
Each of the five lines encapsulates one part of the deep learning pipeline to give a high-level API while still allowing customization. Let's have a closer look.
data
,
blocks
=
load
(
datarecipes
(
)
[
"
imagenette2-160
"
]
)
((mapobs(loadfile, ObsView{FileDataset{typeof(identity), String}} with 13394 observations; batched=:auto), mapobs(parentname, ObsView{FileDataset{typeof(identity), String}} with 13394 observations; batched=:auto)), (Image{2}(), Label{String}(["n01440764", "n02102040", "n02979186", "n03000684", "n03028079", "n03394916", "n03417042", "n03425413", "n03445777", "n03888257"])))
This line downloads and loads the
ImageNette
image classification dataset, a small subset of ImageNet with 10 different classes.
data
is a
data container that can be used to load individual observations, here of images and the corresponding labels. We can use
getobs(data, i)
to load the
i
-th observation and
numobs
to find out how many observations there are.
blocks
describe the format of the data that you want to use for learning. For supervised training tasks, they are a tuple of
(inputblock, targetblock)
. Since we want to do image classification, the input block is
Image{2}()
, representing a 2-dimensional image and the target block is
Label(classes)
, representing the class the image belongs to.
blocks
(Image{2}(), Label{String}(["n01440764", "n02102040", "n02979186", "n03000684", "n03028079", "n03394916", "n03417042", "n03425413", "n03445777", "n03888257"]))
task
=
ImageClassificationSingle
(
blocks
)
SupervisedTask(Image{2} -> Label{String})
The next line defines a learning task which encapsulates the data preprocessing pipeline and other logic related to the task.
ImageClassificationSingle
is a simple wrapper around
BlockTask
which takes in blocks and data processing steps, so-called
encodings. Using it, we can replace the above line with
task
=
BlockTask
(
(
Image
{
2
}
(
)
,
Label
(
classes
)
)
,
(
ProjectiveTransforms
(
(
128
,
128
)
)
,
ImagePreprocessing
(
)
,
OneHot
(
)
)
)
Based on the blocks and encodings, the learning task can derive lots of functionality:
data processing
visualization
constructing task-specific models from a backbone
creating a loss function
learner
=
tasklearner
(
task
,
data
,
callbacks
=
[
ToGPU
(
)
,
Metrics
(
accuracy
)
]
)
Learner()
Next we create a
Learner
that encapsulates everything needed for training, including:
parallelized training and validation data loaders using
taskdataloaders
a loss function using
tasklossfn
a task-specific model using
taskmodel
The customizable, expanded version of the code looks like this:
dls
=
taskdataloaders
(
data
,
task
)
model
=
taskmodel
(
task
,
Models
.
xresnet18
(
)
)
lossfn
=
tasklossfn
(
task
)
learner
=
Learner
(
model
,
dls
,
Adam
(
)
,
lossfn
,
ToGPU
(
)
,
Metrics
(
accuracy
)
)
At this step, we can also pass in any number of
callbacks
to customize the training. Here
ToGPU
ensures an available GPU is used, and
Metrics
adds additional metrics to track during training.
fitonecycle!
(
learner
,
10
)
Training now is quite simple. You have several options for high-level training schedules:
lrfind
to run a learning rate finder
finetune!
for when you're using a pretrained backbone
fitonecycle!
for when you're training a model from scratch
showoutputs
(
task
,
learner
)
Finally, the last line visualizes the predictions of the trained model. It takes some samples from the training data loader, runs them through the model and decodes the outputs. How each piece of data is visualized is also inferred through the blocks in the learning task.
The following page links back here: