Three main APIs¶
All deep learning training workflows involve the following three essential components, each mapping to a critical API in FastEstimator.
Data pipeline: extracts data from disk/RAM, performs transformations. ->
fe.Pipeline
Network: performs trainable and differentiable operations. ->
fe.Network
Training loop: combines the data pipeline and network in an iterative process. ->
fe.Estimator
Any deep learning task can be constructed by following the 3 main steps:
Image Classification Example¶
Step 1 - Pipeline¶
We use FastEstimator dataset API to load the MNIST dataset. Please check out Tutorial 2 for more details about the dataset API. In this case our data preprocessing involves:
- Expand image dimension from (28,28) to (28, 28, 1) for convenience during convolution operations.
- Rescale pixel values from [0, 255] to [0, 1].
Please check out Tutorial 3 for details about Operator
and Tutorial 4 for Pipeline
.
import fastestimator as fe
from fastestimator.dataset.data import mnist
from fastestimator.op.numpyop.univariate import ExpandDims, Minmax
train_data, eval_data = mnist.load_data()
pipeline = fe.Pipeline(train_data=train_data,
eval_data=eval_data,
batch_size=32,
ops=[ExpandDims(inputs="x", outputs="x"), Minmax(inputs="x", outputs="x")])
Step 2 - Network¶
The model definition can be either from tf.keras.Model
or torch.nn.Module
, for more info about network definitions, check out Tutorial 5. The differentiable operations during training are listed as follows:
- Feed the preprocessed images to the network and get prediction scores.
- Calculate
CrossEntropy
(loss) between prediction scores and ground truth. - Update the model by minimizing
CrossEntropy
.
For more info about Network
and its operators, check out Tutorial 6.
from fastestimator.architecture.tensorflow import LeNet
# from fastestimator.architecture.pytorch import LeNet # One can also use a pytorch model
from fastestimator.op.tensorop.loss import CrossEntropy
from fastestimator.op.tensorop.model import ModelOp, UpdateOp
model = fe.build(model_fn=LeNet, optimizer_fn="adam")
network = fe.Network(ops=[
ModelOp(model=model, inputs="x", outputs="y_pred"),
CrossEntropy(inputs=("y_pred", "y"), outputs="ce"),
UpdateOp(model=model, loss_name="ce")
])
Step 3 - Estimator¶
We define the Estimator
to connect the Network
to the Pipeline
, and compute accuracy as a validation metric. Please see Tutorial 7 for more about Estimator
and Traces
.
from fastestimator.trace.metric import Accuracy
from fastestimator.trace.io import BestModelSaver
import tempfile
traces = [Accuracy(true_key="y", pred_key="y_pred"),
BestModelSaver(model=model, save_dir=tempfile.mkdtemp(), metric="accuracy", save_best_mode="max")]
estimator = fe.Estimator(pipeline=pipeline,
network=network,
epochs=2,
traces=traces)
Start Training¶
estimator.fit()
______ __ ______ __ _ __ / ____/___ ______/ /_/ ____/____/ /_(_)___ ___ ____ _/ /_____ _____ / /_ / __ `/ ___/ __/ __/ / ___/ __/ / __ `__ \/ __ `/ __/ __ \/ ___/ / __/ / /_/ (__ ) /_/ /___(__ ) /_/ / / / / / / /_/ / /_/ /_/ / / /_/ \__,_/____/\__/_____/____/\__/_/_/ /_/ /_/\__,_/\__/\____/_/ FastEstimator-Start: step: 1; logging_interval: 100; num_device: 0; FastEstimator-Train: step: 1; ce: 2.308363; FastEstimator-Train: step: 100; ce: 0.32775605; steps/sec: 76.05; FastEstimator-Train: step: 200; ce: 0.09257892; steps/sec: 73.5; FastEstimator-Train: step: 300; ce: 0.34083164; steps/sec: 76.4; FastEstimator-Train: step: 400; ce: 0.1040692; steps/sec: 74.74; FastEstimator-Train: step: 500; ce: 0.021515703; steps/sec: 77.2; FastEstimator-Train: step: 600; ce: 0.06389343; steps/sec: 76.94; FastEstimator-Train: step: 700; ce: 0.081933156; steps/sec: 76.56; FastEstimator-Train: step: 800; ce: 0.04755495; steps/sec: 75.82; FastEstimator-Train: step: 900; ce: 0.09036083; steps/sec: 76.68; FastEstimator-Train: step: 1000; ce: 0.076977566; steps/sec: 73.93; FastEstimator-Train: step: 1100; ce: 0.006916199; steps/sec: 74.92; FastEstimator-Train: step: 1200; ce: 0.116034895; steps/sec: 72.66; FastEstimator-Train: step: 1300; ce: 0.0036065953; steps/sec: 73.45; FastEstimator-Train: step: 1400; ce: 0.1516164; steps/sec: 73.41; FastEstimator-Train: step: 1500; ce: 0.066313066; steps/sec: 73.17; FastEstimator-Train: step: 1600; ce: 0.1330988; steps/sec: 71.1; FastEstimator-Train: step: 1700; ce: 0.08547261; steps/sec: 70.95; FastEstimator-Train: step: 1800; ce: 0.024575546; steps/sec: 72.46; FastEstimator-Train: step: 1875; epoch: 1; epoch_time: 26.76 sec; Eval Progress: 1/312; Eval Progress: 104/312; steps/sec: 222.3; Eval Progress: 208/312; steps/sec: 213.34; Eval Progress: 312/312; steps/sec: 210.13; FastEstimator-BestModelSaver: Saved model to /var/folders/3r/h9kh47050gv6rbt_pgf8cl540000gn/T/tmpz8b4p4k4/model_best_accuracy.h5 FastEstimator-Eval: step: 1875; epoch: 1; accuracy: 0.9874; ce: 0.042314235; max_accuracy: 0.9874; since_best_accuracy: 0; FastEstimator-Train: step: 1900; ce: 0.018547835; steps/sec: 51.8; FastEstimator-Train: step: 2000; ce: 0.02083261; steps/sec: 72.46; FastEstimator-Train: step: 2100; ce: 0.0013426461; steps/sec: 72.69; FastEstimator-Train: step: 2200; ce: 0.03557183; steps/sec: 72.89; FastEstimator-Train: step: 2300; ce: 0.016057294; steps/sec: 71.61; FastEstimator-Train: step: 2400; ce: 0.019565197; steps/sec: 72.94; FastEstimator-Train: step: 2500; ce: 0.008084664; steps/sec: 70.73; FastEstimator-Train: step: 2600; ce: 0.047113482; steps/sec: 71.11; FastEstimator-Train: step: 2700; ce: 0.01939332; steps/sec: 73.15; FastEstimator-Train: step: 2800; ce: 0.0058479137; steps/sec: 70.8; FastEstimator-Train: step: 2900; ce: 0.0133756; steps/sec: 70.4; FastEstimator-Train: step: 3000; ce: 0.00542433; steps/sec: 66.53; FastEstimator-Train: step: 3100; ce: 0.0123183625; steps/sec: 66.0; FastEstimator-Train: step: 3200; ce: 0.0035992165; steps/sec: 67.31; FastEstimator-Train: step: 3300; ce: 0.029546442; steps/sec: 68.5; FastEstimator-Train: step: 3400; ce: 0.07383997; steps/sec: 71.68; FastEstimator-Train: step: 3500; ce: 0.0014300543; steps/sec: 71.02; FastEstimator-Train: step: 3600; ce: 0.00060256035; steps/sec: 69.73; FastEstimator-Train: step: 3700; ce: 0.034662727; steps/sec: 68.65; FastEstimator-Train: step: 3750; epoch: 2; epoch_time: 27.18 sec; Eval Progress: 1/312; Eval Progress: 104/312; steps/sec: 203.92; Eval Progress: 208/312; steps/sec: 202.22; Eval Progress: 312/312; steps/sec: 208.36; FastEstimator-BestModelSaver: Saved model to /var/folders/3r/h9kh47050gv6rbt_pgf8cl540000gn/T/tmpz8b4p4k4/model_best_accuracy.h5 FastEstimator-Eval: step: 3750; epoch: 2; accuracy: 0.9896; ce: 0.03458583; max_accuracy: 0.9896; since_best_accuracy: 0; FastEstimator-Finish: step: 3750; model_lr: 0.001; total_time: 57.84 sec;
Inferencing¶
After training, we can do inferencing on new data with Pipeline.transform
and Netowork.transform
. Please checkout Tutorial 8 for more details. \
import numpy as np
data = eval_data[0]
data = pipeline.transform(data, mode="eval")
data = network.transform(data, mode="eval")
print("Ground truth class is {}".format(data["y"][0]))
print("Predicted class is {}".format(np.argmax(data["y_pred"])))
img = fe.util.BatchDisplay(title="x", image=data["x"])
img.show()
Ground truth class is 7 Predicted class is 7