# Getting Started

Burn is a deep learning framework in the Rust programming language. Therefore, it goes without
saying that one must understand the basic notions of Rust. Reading the first chapters of the
[Rust Book](https://doc.rust-lang.org/book/) is recommended, but don't worry if you're just starting
out. We'll try to provide as much context and reference to external resources when required. Just
look out for the **🦀 Rust Note** indicators.

## Installing Rust

For installation instructions, please refer to the
[installation page](https://doc.rust-lang.org/book/ch01-01-installation.html). It explains in
details the most convenient way for you to install Rust on your computer, which is the very first
thing to do to start using Burn.

## Creating a Burn application

Once Rust is correctly installed, create a new Rust application by using Rust's build system and
package manager Cargo. It is automatically installed with Rust.

<details>
<summary><strong>🦀 Cargo Cheat Sheet</strong></summary>

[Cargo](https://doc.rust-lang.org/cargo/) is a very useful tool to manage Rust projects because it
handles a lot of tasks. More precisely, it is used to compile your code, download the
libraries/packages your code depends on, and build said libraries.

Below is a quick cheat sheet of the main `cargo` commands you might use throughout this guide.

| Command             | Description                                                                                  |
| ------------------- | -------------------------------------------------------------------------------------------- |
| `cargo new` _path_  | Create a new Cargo package in the given directory.                                           |
| `cargo add` _crate_ | Add dependencies to the Cargo.toml manifest file.                                            |
| `cargo build`       | Compile the local package and all of its dependencies (in debug mode, use `-r` for release). |
| `cargo check`       | Check the local package for compilation errors (much faster).                                |
| `cargo run`         | Run the local package binary.                                                                |

For more information, check out
[Hello, Cargo!](https://doc.rust-lang.org/book/ch01-03-hello-cargo.html) in the Rust Book.

</details><br>

In the directory of your choice, run the following:

```console
cargo new my_burn_app
```

This will initialize the `my_burn_app` project directory with a `Cargo.toml` file and a `src`
directory with an auto-generated `main.rs` file inside. Head inside the directory to check:

```console
cd my_burn_app
```

Then, add Burn as a dependency:

```console
cargo add burn --features wgpu
```

Finally, compile the local package by executing the following:

```console
cargo build
```

That's it, you're ready to start! You have a project configured with Burn and the WGPU backend,
which allows to execute low-level operations on any platform using the GPU.

<div class="warning">

When using one of the `wgpu` backends, you may encounter compilation errors related to recursive
type evaluation. This is due to complex type nesting within the `wgpu` dependency chain.

To resolve this issue, add the following line at the top of your `main.rs` or `lib.rs` file:

```rust
#![recursion_limit = "256"]
```

The default recursion limit (128) is often just below the required depth (typically 130-150) due to
deeply nested associated types and trait bounds.

</div>

## Writing a code snippet

The `src/main.rs` was automatically generated by Cargo, so let's replace its content with the
following:

```rust, ignore
use burn::tensor::{Device, Tensor};

fn main() {
    let device = Device::wgpu(Default::default());
    // Creation of two tensors, the first with explicit values and the second one with ones, with the same shape as the first
    let tensor_1 = Tensor::<2>::from_data([[2., 3.], [4., 5.]], &device);
    let tensor_2 = Tensor::<2>::ones_like(&tensor_1);

    // Print the element-wise addition (done with the WGPU backend) of the two tensors.
    println!("{}", tensor_1 + tensor_2);
}
```

<details>
<summary><strong>🦀 Use Declarations</strong></summary>

To bring any of the Burn module or item into scope, a `use` declaration is added.

In the example above, we wanted to bring the `Tensor` and `Device` structs into scope with the
following:

```rust, ignore
use burn::tensor::{Device, Tensor};
```

This is pretty self-explanatory in this case. But, the same declaration could be written as a
shortcut to simultaneously binding of multiple paths with a common prefix:

```rust, ignore
use burn::tensor::{Device, Tensor};
```

In this example, the common prefix is pretty short and there are only two items to bind locally.
Therefore, the first usage with two `use` declarations might be preferred. But know that both
examples are valid. For more details on the `use` keyword, take a look at
[this section](https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html)
of the Rust Book or the
[Rust reference](https://doc.rust-lang.org/reference/items/use-declarations.html).

</details><br>

<details>
<summary><strong>🦀 Generic Data Types</strong></summary>

If you're new to Rust, you're probably wondering why we had to use `Tensor::<2>::...`.
That's because the `Tensor` struct is [generic](https://doc.rust-lang.org/book/ch10-01-syntax.html)
over multiple concrete data types. More specifically, a `Tensor` has two generic parameters: the number of dimensions (rank) and the
tensor kind (which defaults to `Float`). Here, we only specify the rank. For more details on the `Tensor` struct, take a look at
[this section](./building-blocks/tensor.md).

Most of the time when generics are involved, the compiler can infer the generic parameters
automatically. In this case, the compiler needs a little help. This can usually be done in one of
two ways: providing a type annotation or binding the generic parameter via the _turbofish_ `::<>`
syntax. In the example above we used the so-called _turbofish_ syntax, but we could have used type
annotations instead like this:

```rust, ignore
let tensor_1: Tensor<2> = Tensor::from_data([[2., 3.], [4., 5.]], &device);
let tensor_2 = Tensor::ones_like(&tensor_1);
```

You probably noticed that we provided a type annotation for the first tensor only and yet this
example still works. That's because the compiler (correctly) inferred that `tensor_2` had the same
generic parameters. The same could have been done in the original example, but specifying the
parameters for both is more explicit.

</details><br>

By running `cargo run`, you should now see the result of the addition:

```console
Tensor {
  data:
[[3.0, 4.0],
 [5.0, 6.0]],
  shape:  [2, 2],
  device:  DefaultDevice,
  backend:  "wgpu",
  kind:  "Float",
  dtype:  "f32",
}
```

While the previous example is somewhat trivial, the upcoming basic workflow section will walk you
through a much more relevant example for deep learning applications.

## Using `prelude`

Burn comes with a variety of things in its core library. When creating a new model or using an
existing one for inference, you may need to import every single component you used, which could be a
little verbose.

To address it, a `prelude` module is provided, allowing you to easily import commonly used structs
and macros as a group:

```rust, ignore
use burn::prelude::*;
```

which is equal to:

```rust, ignore
use burn::{
    config::Config,
    module::Module,
    nn,
    tensor::{
        Bool, Device, DeviceIndex, DeviceKind, ElementConversion, Float, Int, Shape, SliceArg,
        Tensor, TensorData, cast::ToElement, s,
    },
};
```

<div class="warning">

For the sake of simplicity, the subsequent chapters of this book will all use this form of importing
except in the [Building Blocks](./building-blocks) chapter, as explicit importing aids users in
grasping the usage of particular structures and macros.

</div>
