Skip to content

Commit

Permalink
[guide] Remove ambiguity lib vs. executable (tracel-ai#1649)
Browse files Browse the repository at this point in the history
  • Loading branch information
syl20bnr authored Apr 26, 2024
1 parent b7ab19a commit 1f8b5d3
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 84 deletions.
1 change: 1 addition & 0 deletions burn-book/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ authors = [
"Louis Fortier-Dubois",
"Dilshod Tadjibaev",
"Guillaume Lagrange",
"Sylvain Benner",
]
language = "en"
multilingual = false
Expand Down
10 changes: 9 additions & 1 deletion burn-book/src/basic-workflow/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@ train a simple convolutional neural network model on the MNIST dataset and prepa
For clarity, we sometimes omit imports in our code snippets. For more details, please refer to the
corresponding code in the `examples/guide` [directory](https://github.com/tracel-ai/burn/tree/main/examples/guide).
We reproduce this example in a step-by-step fashion, from dataset creation to modeling and training
in the following sections. It is recommended to use the capabilities of your IDE or editor to
in the following sections. It is recommended to use the capabilities of your IDE or text editor to
automatically add the missing imports as you add the code snippets to your code.

<div class="warning">

Be sure to checkout the git branch corresponding to the version of Burn you are using to follow
this guide.

The current version of Burn is `0.14` and the corresponding branch to checkout is `main`.
</div>

The code for this demo can be executed from Burn's base directory using the command:

```bash
Expand Down
67 changes: 10 additions & 57 deletions burn-book/src/basic-workflow/backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,74 +7,21 @@ entrypoint of our program, namely the `main` function defined in `src/main.rs`.
```rust , ignore
use burn::optim::AdamConfig;
use burn::backend::{Autodiff, Wgpu, wgpu::AutoGraphicsApi};
use guide::model::ModelConfig;
use crate::model::ModelConfig;

fn main() {
type MyBackend = Wgpu<AutoGraphicsApi, f32, i32>;
type MyAutodiffBackend = Autodiff<MyBackend>;

let device = burn::backend::wgpu::WgpuDevice::default();
guide::training::train::<MyAutodiffBackend>(
crate::training::train::<MyAutodiffBackend>(
"/tmp/guide",
guide::training::TrainingConfig::new(ModelConfig::new(10, 512), AdamConfig::new()),
crate::training::TrainingConfig::new(ModelConfig::new(10, 512), AdamConfig::new()),
device,
);
}
```

<details>
<summary><strong>🦀 Packages, Crates and Modules</strong></summary>

You might be wondering why we use the `guide` prefix to bring the different modules we just
implemented into scope. Instead of including the code in the current guide in a single file, we
separated it into different files which group related code into _modules_. The `guide` is simply the
name we gave to our _crate_, which contains the different files. Below is a brief explanation of the
different parts of the Rust module system.

A **package** is a bundle of one or more crates that provides a set of functionality. A package
contains a `Cargo.toml` file that describes how to build those crates. Burn is a package.

A **crate** is a compilation unit in Rust. It could be a single file, but it is often easier to
split up crates into multiple _modules_ and possibly multiple files. A crate can come in one of two
forms: a binary crate or a library crate. When compiling a crate, the compiler first looks in the
crate root file (usually `src/lib.rs` for a library crate or `src/main.rs` for a binary crate). Any
module declared in the crate root file will be inserted in the crate for compilation. For this demo
example, we will define a library crate where all the individual modules (model, data, training,
etc.) are listed inside `src/lib.rs` as follows:

```
pub mod data;
pub mod inference;
pub mod model;
pub mod training;
```

A **module** lets us organize code within a crate for readability and easy reuse. Modules also allow
us to control the _privacy_ of items. The `pub` keyword used above, for example, is employed to make
a module publicly available inside the crate.

The entry point of our program is the `main` function, defined in the `examples/guide.rs` file. The
file structure for this example is illustrated below:

```
guide
├── Cargo.toml
├── examples
│ └── guide.rs
└── src
├── data.rs
├── inference.rs
├── lib.rs
├── model.rs
└── training.rs
```

The source for this guide can be found in our
[GitHub repository](https://github.com/tracel-ai/burn/tree/main/examples/guide) which can be used to
run this basic workflow example end-to-end.\

</details><br>

In this example, we use the `Wgpu` backend which is compatible with any operating system and will
use the GPU. For other options, see the Burn README. This backend type takes the graphics api, the
float type and the int type as generic arguments that will be used during the training. By leaving
Expand All @@ -87,6 +34,12 @@ the model (the number of digit classes is 10 and the hidden dimension is 512), t
configuration which in our case will be the default Adam configuration, and the device which can be
obtained from the backend.

When running the example, we can see the training progression through a basic CLI dashboard:
You can now train your freshly created model with the command:

```console
cargo run --release
```

When running the example, you should see the training progression through a basic CLI dashboard:

<img title="a title" alt="Alt text" src="./training-output.png">
15 changes: 15 additions & 0 deletions burn-book/src/basic-workflow/inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,18 @@ Finally we can init the model with the configuration and the record. For simplic
same batcher used during the training to pass from a MnistItem to a tensor.

By running the infer function, you should see the predictions of your model!

Add the call to `infer` to the `main.rs` file after the `train` function call:

```rust , ignore
crate::inference::infer::<MyBackend>(
artifact_dir,
device,
burn::data::dataset::vision::MnistDataset::test()
.get(42)
.unwrap(),
);
```

The number `42` is the index of the image in the MNIST dataset. You can explore and verify them using
this [MNIST viewer](https://observablehq.com/@davidalber/mnist-viewer).
9 changes: 9 additions & 0 deletions burn-book/src/basic-workflow/model.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ As [mentioned previously](../getting-started.md#creating-a-burn-application), th
your `guide` project directory with a `Cargo.toml` and a `src/main.rs` file.

In the `Cargo.toml` file, add the `burn` dependency with `train`, `wgpu` and `vision` features.
Then run `cargo build` to build the project and import all the dependencies.

```toml
[package]
Expand Down Expand Up @@ -158,6 +159,14 @@ There are two major things going on in this code sample.

</details><br>

Note that each time you create a new file in the `src` directory you also need to add explicitly this
module to the `main.rs` file. For instance after creating the `model.rs`, you need to add the following
at the top of the main file:

```rust , ignore
mod model;
```

Next, we need to instantiate the model for training.

```rust , ignore
Expand Down
78 changes: 75 additions & 3 deletions burn-book/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,86 @@ For the sake of simplicity, the subsequent chapters of this book will all use th

</div>

## Running examples
## Explore examples

In the [next chapter](./basic-workflow) you'll have the opportunity to implement the whole Burn
`guide` example yourself in a step by step manner.

Many additional Burn examples are available in the
[examples](https://github.com/tracel-ai/burn/tree/main/examples) directory. To run an example, please refer
to its README.md for the specific command to execute.
[examples](https://github.com/tracel-ai/burn/tree/main/examples) directory. Burn examples are
organized as library crates with one or more examples that are executable binaries. An example
can then be executed using the following cargo command line in the root of the Burn repository:

```bash
cargo run --example <example name>
```

To learn more about crates and examples, read the Rust section below.

<details>
<summary><strong>🦀 About Rust crates</strong></summary>

Each Burn example is a **package** which are subdirectories of the `examples` directory. A package
is composed of one or more **crates**.

A package is a bundle of one or more crates that provides a set of functionality. A package
contains a `Cargo.toml` file that describes how to build those crates.

A crate is a compilation unit in Rust. It could be a single file, but it is often easier to
split up crates into multiple **modules**.

A module lets us organize code within a crate for readability and easy reuse. Modules also allow
us to control the _privacy_ of items. For instance the `pub(crate)` keyword is employed to make
a module publicly available inside the crate. In the snippet below there are four modules declared,
two of them are public and visible to the users of the crates, one of them is public inside the crate
only and crate users cannot see it, at last one is private when there is no keyword.
These modules can be single files or a directory with a `mod.rs` file inside.

```rust, ignore
pub mod data;
pub mod inference;
pub(crate) mod model;
mod training;
```

A crate can come in one of two forms: a **binary crate** or a **library crate**. When compiling a crate,
the compiler first looks in the crate root file (`src/lib.rs` for a library crate and `src/main.rs`
for a binary crate). Any module declared in the crate root file will be inserted in the crate for
compilation.

All Burn examples are library crates and they can contain one or more executable examples that
uses the library. We even have some Burn examples that uses the library crate of other examples.

The examples are unique files under the `examples` directory. Each file produces an executable file
with the same name. Each example can then be executed with `cargo run --example <executable name>`.

Below is an file tree of a typical Burn example package:

```
examples/burn-example
├── Cargo.toml
├── examples
│ ├── example1.rs
│ ├── example2.rs
│ └── ...
└── src
├── lib.rs
├── module1.rs
├── module2.rs
└── ...
```

</details><br>

For more information on each example, see their respective `README.md` file.

<div class="warning">

Note that some examples use the
[`datasets` library by HuggingFace](https://huggingface.co/docs/datasets/index) to download the
datasets required in the examples. This is a Python library, which means that you will need to
install Python before running these examples. This requirement will be clearly indicated in the
example's README when applicable.

</div>

36 changes: 13 additions & 23 deletions examples/guide/examples/guide.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
use burn::{
backend::{wgpu::AutoGraphicsApi, Autodiff, Wgpu},
data::dataset::Dataset,
optim::AdamConfig,
};
use guide::{model::ModelConfig, training::TrainingConfig};
//
// Note: If you are following the Burn Book guide this file can be ignored.
//
// This example file is added only for convenience and consistency so that
// the guide example can be executed like any other examples using:
//
// cargo run --release --example guide
//
use std::process::Command;

fn main() {
type MyBackend = Wgpu<AutoGraphicsApi, f32, i32>;
type MyAutodiffBackend = Autodiff<MyBackend>;

let device = burn::backend::wgpu::WgpuDevice::default();
let artifact_dir = "/tmp/guide";
guide::training::train::<MyAutodiffBackend>(
artifact_dir,
TrainingConfig::new(ModelConfig::new(10, 512), AdamConfig::new()),
device.clone(),
);
guide::inference::infer::<MyBackend>(
artifact_dir,
device,
burn::data::dataset::vision::MnistDataset::test()
.get(42)
.unwrap(),
);
Command::new("cargo")
.args(["run", "--bin", "guide"])
.status()
.expect("guide example should run");
}
6 changes: 6 additions & 0 deletions examples/guide/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
//
// Note: If you are following the Burn Book guide this file can be ignored.
//
// This lib.rs file is added only for convenience so that the code in this
// guide can be reused.
//
pub mod data;
pub mod inference;
pub mod model;
Expand Down
31 changes: 31 additions & 0 deletions examples/guide/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
mod data;
mod inference;
mod model;
mod training;

use crate::{model::ModelConfig, training::TrainingConfig};
use burn::{
backend::{wgpu::AutoGraphicsApi, Autodiff, Wgpu},
data::dataset::Dataset,
optim::AdamConfig,
};

fn main() {
type MyBackend = Wgpu<AutoGraphicsApi, f32, i32>;
type MyAutodiffBackend = Autodiff<MyBackend>;

let device = burn::backend::wgpu::WgpuDevice::default();
let artifact_dir = "/tmp/guide";
crate::training::train::<MyAutodiffBackend>(
artifact_dir,
TrainingConfig::new(ModelConfig::new(10, 512), AdamConfig::new()),
device.clone(),
);
crate::inference::infer::<MyBackend>(
artifact_dir,
device,
burn::data::dataset::vision::MnistDataset::test()
.get(42)
.unwrap(),
);
}

0 comments on commit 1f8b5d3

Please sign in to comment.