Quickstart

This page follows fastai's quickstart page by quickly showing a few learning tasks. More will be added here as they are added to the library.

FastAI.jl's learning tasks all use the same basic steps and code:

  • create a data container

  • create a learning task

  • create learner

  • fit the model

  • make predictions or view results

In this quick start, we'll show these steps for a wide range of difference applications and datasets. As you'll see, the code in each case is extremely similar, despite the very different models and data being used.


			
			
			
			using
			
			 

	
			FastAI
			,
			
			 
			FastVision
			,
			
			 
			FastTabular
			,
			
			 
			FastMakie
			,
			
			 
			Metalhead
			
			

			
			import
			
			 
			CairoMakie
			;
			 
			
			
			CairoMakie
			.
			
			activate!
			(
			
			type
			=
			
			"
			png
			"
			)

Computer vision

Classification

Single-label

Let's train a model to classify images in the ImageNette dataset, a subset of ImageNet with 10 classes. The following lines download the dataset, prepare a data preprocessing pipeline and create a model suitable for classification that is ready to train:


			
			
			
			
			data
			,
			 
			blocks
			 
			=
			 
			
			load
			(
			
			

	
			datarecipes
			(
			)
			[
			
			"
			imagenette2-320
			"
			]
			)
			

			
			task
			 
			=
			 
			

	
			ImageClassificationSingle
			(
			blocks
			,
			 
			
			size
			=
			
			(
			256
			,
			 
			256
			)
			)
			

			
			learner
			 
			=
			 
			

	
			tasklearner
			(
			task
			,
			 
			data
			,
			 
			
			callbacks
			=
			
			[
			

	
			ToGPU
			(
			)
			,
			 
			

	
			Metrics
			(

	
			accuracy
			)
			]
			,
			 
			
			backbone
			=
			
			
			
			ResNet
			(
			34
			)
			.
			
			layers
			[
			
			1
			:
			
			end
			-
			1
			]
			)

			Learner()

With this, we can start training! Let's train for 10 epochs (i.e. iterations through the whole dataset) and a maximum learning rate of 0.004:


			
			
			

	
			fitonecycle!
			(
			learner
			,
			 
			10
			,
			 
			0.004
			)

			Epoch 1 TrainingPhase(): 100%|██████████████████████████| Time: 0:03:20m
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   1.0 │ 2.00719 │  0.32779 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 1 ValidationPhase(): 100%|████████████████████████| Time: 0:00:15
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   1.0 │ 2.10231 │  0.37191 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 2 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:09
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   2.0 │ 1.81599 │  0.42517 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 2 ValidationPhase(): 100%|████████████████████████| Time: 0:00:06
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   2.0 │ 2.50382 │  0.47347 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 3 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:11
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   3.0 │ 1.50171 │  0.52674 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 3 ValidationPhase(): 100%|████████████████████████| Time: 0:00:06
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   3.0 │ 1.31716 │  0.57614 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 4 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:09
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   4.0 │ 1.22013 │  0.61345 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 4 ValidationPhase(): 100%|████████████████████████| Time: 0:00:06
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   4.0 │ 1.02075 │  0.65426 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 5 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:10
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   5.0 │ 1.01926 │   0.6719 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 5 ValidationPhase(): 100%|████████████████████████| Time: 0:00:06
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   5.0 │ 1.03147 │  0.66908 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 6 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:13
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   6.0 │ 0.90075 │    0.705 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 6 ValidationPhase(): 100%|████████████████████████| Time: -1:-59:-53
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   6.0 │ 0.84108 │  0.73292 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 7 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:20
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   7.0 │ 0.79412 │  0.74507 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 7 ValidationPhase(): 100%|████████████████████████| Time: 0:00:06
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   7.0 │ 0.84146 │   0.7309 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 8 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:14
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   8.0 │ 0.69101 │  0.77818 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 8 ValidationPhase(): 100%|████████████████████████| Time: 0:00:07
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   8.0 │ 0.92366 │  0.69921 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 9 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:13
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   9.0 │ 0.55766 │  0.81549 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 9 ValidationPhase(): 100%|████████████████████████| Time: 0:00:06
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   9.0 │ 0.69418 │   0.7792 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 10 TrainingPhase(): 100%|█████████████████████████| Time: 0:01:09
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │  10.0 │ 0.43443 │  0.85947 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 10 ValidationPhase(): 100%|███████████████████████| Time: 0:00:06
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │  10.0 │ 0.58856 │  0.81417 │
└─────────────────┴───────┴─────────┴──────────┘

Let's save the model for later use or deployment:


			
			
			

	
			savetaskmodel
			(
			
			"
			./quickstart_clf.jld2
			"
			,
			 
			task
			,
			 
			
			learner
			.
			
			model
			)

And now, look at some example model predictions on the validation dataset:


			
			
			

	
			showoutputs
			(
			task
			,
			 
			learner
			)

Segmentation

Segmentation is similar to classfication, but instead of assigning one class to an image, we try to classify every single pixel in an image. The CamVid dataset consists of images taken in traffic with pixel labels for various relevant image parts like the street, sky, sidewalk etc.


			
			
			
			
			data
			,
			 
			blocks
			 
			=
			 
			
			load
			(
			
			

	
			datarecipes
			(
			)
			[
			
			"
			camvid
			"
			]
			)
			

			
			task
			 
			=
			 
			

	
			ImageSegmentation
			(
			blocks
			)
			

			
			learner
			 
			=
			 
			

	
			tasklearner
			(
			task
			,
			 
			data
			,
			 
			
			callbacks
			=
			
			[
			

	
			ToGPU
			(
			)
			]
			,
			 
			
			backbone
			=
			
			
			
			ResNet
			(
			34
			)
			.
			
			layers
			[
			
			1
			:
			
			end
			-
			1
			]
			)

			Learner()

			
			
			

	
			fitonecycle!
			(
			learner
			,
			 
			10
			,
			 
			0.1
			)

			Epoch 1 TrainingPhase(): 100%|██████████████████████████| Time: 0:04:49
┌───────────────┬───────┬─────────┐
│         Phase │ Epoch │    Loss │
├───────────────┼───────┼─────────┤
│ TrainingPhase │   1.0 │ 2.40698 │
└───────────────┴───────┴─────────┘
Epoch 1 ValidationPhase(): 100%|████████████████████████| Time: 0:00:10
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   1.0 │ 3.26103 │
└─────────────────┴───────┴─────────┘
Epoch 2 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:05
┌───────────────┬───────┬─────────┐
│         Phase │ Epoch │    Loss │
├───────────────┼───────┼─────────┤
│ TrainingPhase │   2.0 │ 1.27837 │
└───────────────┴───────┴─────────┘
Epoch 2 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   2.0 │ 2.25442 │
└─────────────────┴───────┴─────────┘
Epoch 3 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:05
┌───────────────┬───────┬─────────┐
│         Phase │ Epoch │    Loss │
├───────────────┼───────┼─────────┤
│ TrainingPhase │   3.0 │ 1.20744 │
└───────────────┴───────┴─────────┘
Epoch 3 ValidationPhase(): 100%|████████████████████████| Time: 0:00:01
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   3.0 │ 1.50661 │
└─────────────────┴───────┴─────────┘
Epoch 4 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:05
┌───────────────┬───────┬─────────┐
│         Phase │ Epoch │    Loss │
├───────────────┼───────┼─────────┤
│ TrainingPhase │   4.0 │ 1.17844 │
└───────────────┴───────┴─────────┘
Epoch 4 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   4.0 │ 1.34925 │
└─────────────────┴───────┴─────────┘
Epoch 5 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:05
┌───────────────┬───────┬─────────┐
│         Phase │ Epoch │    Loss │
├───────────────┼───────┼─────────┤
│ TrainingPhase │   5.0 │ 1.10546 │
└───────────────┴───────┴─────────┘
Epoch 5 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   5.0 │ 1.15682 │
└─────────────────┴───────┴─────────┘
Epoch 6 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:05
┌───────────────┬───────┬─────────┐
│         Phase │ Epoch │    Loss │
├───────────────┼───────┼─────────┤
│ TrainingPhase │   6.0 │ 1.07065 │
└───────────────┴───────┴─────────┘
Epoch 6 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   6.0 │ 1.59546 │
└─────────────────┴───────┴─────────┘
Epoch 7 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:05
┌───────────────┬───────┬────────┐
│         Phase │ Epoch │   Loss │
├───────────────┼───────┼────────┤
│ TrainingPhase │   7.0 │ 1.0559 │
└───────────────┴───────┴────────┘
Epoch 7 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   7.0 │ 1.08011 │
└─────────────────┴───────┴─────────┘
Epoch 8 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:05
┌───────────────┬───────┬─────────┐
│         Phase │ Epoch │    Loss │
├───────────────┼───────┼─────────┤
│ TrainingPhase │   8.0 │ 0.99461 │
└───────────────┴───────┴─────────┘
Epoch 8 ValidationPhase(): 100%|████████████████████████| Time: 0:00:01
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   8.0 │ 1.13413 │
└─────────────────┴───────┴─────────┘
Epoch 9 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:05
┌───────────────┬───────┬─────────┐
│         Phase │ Epoch │    Loss │
├───────────────┼───────┼─────────┤
│ TrainingPhase │   9.0 │ 0.95487 │
└───────────────┴───────┴─────────┘
Epoch 9 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │   9.0 │ 1.19755 │
└─────────────────┴───────┴─────────┘
Epoch 10 TrainingPhase(): 100%|█████████████████████████| Time: 0:00:05
┌───────────────┬───────┬────────┐
│         Phase │ Epoch │   Loss │
├───────────────┼───────┼────────┤
│ TrainingPhase │  10.0 │ 0.9283 │
└───────────────┴───────┴────────┘
Epoch 10 ValidationPhase(): 100%|███████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┐
│           Phase │ Epoch │    Loss │
├─────────────────┼───────┼─────────┤
│ ValidationPhase │  10.0 │ 0.95868 │
└─────────────────┴───────┴─────────┘

			
			
			

	
			savetaskmodel
			(
			
			"
			./quickstart_segmentation.jld2
			"
			,
			 
			task
			,
			 
			
			learner
			.
			
			model
			)

As with all other tasks, let's have a look at some model outputs:


			
			
			

	
			showoutputs
			(
			task
			,
			 
			learner
			)

Tabular data

FastAI.jl also supports training models to understand tabular data.

Classification

Let's train a model on the Adult dataset that classifies, based on the other attributes, whether a person earns a salary below or above 50k. Since the dimensionality of the data and the model are quite small, this will run fast enough on a CPU, so we don't need to use the ToGPU callback.


			
			
			
			
			data
			,
			 
			blocks
			 
			=
			 
			
			load
			(
			
			

	
			datarecipes
			(
			)
			[
			
			"
			adult_sample/clf_salary
			"
			]
			)
			

			
			task
			 
			=
			 
			

	
			TabularClassificationSingle
			(
			blocks
			,
			 
			data
			)
			

			
			learner
			 
			=
			 
			

	
			tasklearner
			(
			task
			,
			 
			data
			
			;
			 
			
			callbacks
			=
			
			[
			

	
			Metrics
			(

	
			accuracy
			)
			]
			,
			 
			

	
			batchsize
			=
			128
			)

			┌ Warning: There is a missing value present for category 'occupation' which will be removed from Categorify dict
└ @ DataAugmentation /home/lorenz/.julia/dev/DataAugmentation/src/rowtransforms.jl:108

			Learner()

			
			
			

	
			fitonecycle!
			(
			learner
			,
			 
			5
			,
			 
			0.1
			)

			Epoch 1 TrainingPhase(): 100%|██████████████████████████| Time: 0:01:00
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   1.0 │ 0.37418 │  0.82691 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 1 ValidationPhase(): 100%|████████████████████████| Time: 0:00:04
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   1.0 │ 0.31771 │  0.85111 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 2 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:01
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   2.0 │ 0.33603 │  0.84142 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 2 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   2.0 │ 0.31734 │  0.85845 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 3 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:01
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   3.0 │ 0.33076 │   0.8466 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 3 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   3.0 │ 0.30928 │  0.85607 │
└─────────────────┴───────┴─────────┴──────────┘
Epoch 4 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:01
┌───────────────┬───────┬───────┬──────────┐
│         Phase │ Epoch │  Loss │ Accuracy │
├───────────────┼───────┼───────┼──────────┤
│ TrainingPhase │   4.0 │ 0.322 │  0.84691 │
└───────────────┴───────┴───────┴──────────┘
Epoch 4 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬────────┬──────────┐
│           Phase │ Epoch │   Loss │ Accuracy │
├─────────────────┼───────┼────────┼──────────┤
│ ValidationPhase │   4.0 │ 0.3056 │  0.86124 │
└─────────────────┴───────┴────────┴──────────┘
Epoch 5 TrainingPhase(): 100%|██████████████████████████| Time: 0:00:01
┌───────────────┬───────┬─────────┬──────────┐
│         Phase │ Epoch │    Loss │ Accuracy │
├───────────────┼───────┼─────────┼──────────┤
│ TrainingPhase │   5.0 │ 0.31348 │  0.85295 │
└───────────────┴───────┴─────────┴──────────┘
Epoch 5 ValidationPhase(): 100%|████████████████████████| Time: 0:00:00
┌─────────────────┬───────┬─────────┬──────────┐
│           Phase │ Epoch │    Loss │ Accuracy │
├─────────────────┼───────┼─────────┼──────────┤
│ ValidationPhase │   5.0 │ 0.30139 │  0.86165 │
└─────────────────┴───────┴─────────┴──────────┘

As with every task, we can visualize some model predictions. Since it fits the data better, we use the ShowText visualization backend here instead of the default ShowMakie used above.


			
			
			

	
			showoutputs
			(
			task
			,
			 
			learner
			,
			 
			
			backend
			=
			

	
			ShowText
			(
			)
			)

			┌─────────────────────────────────────────────────────────────┬──────────────────────────────────┐
│ Encoded sample                                              │ Output                           │
├─────────────────────────────────────────────────────────────┼──────────────────────────────────┤
│ ┌──────────────────────┬──────────────────────────────────┐ │          ┌                    ┐  │
│ │ EncodedTableRow(...) │          ┌                    ┐  │ │    >=50k ┤■■■■■■■■■■■■■ 0.871    │
│ │                      │    >=50k ┤■■■■■■■■■■■■■■■ 1.0    │ │     <50k ┤■■ 0.129               │
│ │                      │     <50k ┤ 0.0                   │ │          └                    ┘  │
│ │                      │          └                    ┘  │ │                                  │
│ └──────────────────────┴──────────────────────────────────┘ │                                  │
│                                                             │                                  │
├─────────────────────────────────────────────────────────────┼──────────────────────────────────┤
│ ┌──────────────────────┬──────────────────────────────────┐ │          ┌                    ┐  │
│ │ EncodedTableRow(...) │          ┌                    ┐  │ │    >=50k ┤■■■■■■■ 0.357          │
│ │                      │    >=50k ┤ 0.0                   │ │     <50k ┤■■■■■■■■■■■■■ 0.643    │
│ │                      │     <50k ┤■■■■■■■■■■■■■■■ 1.0    │ │          └                    ┘  │
│ │                      │          └                    ┘  │ │                                  │
│ └──────────────────────┴──────────────────────────────────┘ │                                  │
│                                                             │                                  │
├─────────────────────────────────────────────────────────────┼──────────────────────────────────┤
│ ┌──────────────────────┬──────────────────────────────────┐ │          ┌                    ┐  │
│ │ EncodedTableRow(...) │          ┌                    ┐  │ │    >=50k ┤ 0.0303                │
│ │                      │    >=50k ┤ 0.0                   │ │     <50k ┤■■■■■■■■■■■■■■ 0.97    │
│ │                      │     <50k ┤■■■■■■■■■■■■■■■ 1.0    │ │          └                    ┘  │
│ │                      │          └                    ┘  │ │                                  │
│ └──────────────────────┴──────────────────────────────────┘ │                                  │
│                                                             │                                  │
├─────────────────────────────────────────────────────────────┼──────────────────────────────────┤
│ ┌──────────────────────┬──────────────────────────────────┐ │          ┌                    ┐  │
│ │ EncodedTableRow(...) │          ┌                    ┐  │ │    >=50k ┤■■ 0.107               │
│ │                      │    >=50k ┤ 0.0                   │ │     <50k ┤■■■■■■■■■■■■■ 0.893    │
│ │                      │     <50k ┤■■■■■■■■■■■■■■■ 1.0    │ │          └                    ┘  │
│ │                      │          └                    ┘  │ │                                  │
│ └──────────────────────┴──────────────────────────────────┘ │                                  │
│                                                             │                                  │
└─────────────────────────────────────────────────────────────┴──────────────────────────────────┘