diff --git a/nx/exercises/exercises-1-20.livemd b/nx/exercises/exercises-1-20.livemd
new file mode 100644
index 0000000000..812d3a5197
--- /dev/null
+++ b/nx/exercises/exercises-1-20.livemd
@@ -0,0 +1,508 @@
+# Exercises: 1-20
+
+```elixir
+Mix.install([{:nx, "~> 0.6"}])
+```
+
+## Introduction
+
+Inspired by the Python notebook [100 Numpy Exercises](https://www.kaggle.com/code/utsav15/100-numpy-exercises/notebook).
+
+## 1-10
+
+**1. Install `Nx` in a Livebook. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Mix.install([{:nx, "~> 0.6"}])
+ ```
+
+
+
+
+
+
+**2. Create a 1-D tensor of 10 zeros. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.broadcast(0, {10})
+ ```
+
+
+
+
+
+
+**3. Find the number of elements in `tensor`. (★☆☆)**
+
+```elixir
+tensor = Nx.tensor([[1, 2, 3], [4, 5, 6]])
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.size(tensor)
+ ```
+
+
+
+
+
+
+**4. Find the number of bytes of memory in `tensor`. (★☆☆)**
+
+```elixir
+tensor = Nx.tensor([[1, 2, 3], [4, 5, 6]])
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.byte_size(tensor)
+ ```
+
+
+
+
+
+
+**5a. Use `Nx.sum/2` to find the sum of all elements of `tensor`. (★☆☆)**
+
+```elixir
+tensor = Nx.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.sum(tensor)
+ ```
+
+
+
+
+
+
+**5b. Read the [documentation for `Nx.sum/2`](https://hexdocs.pm/nx/Nx.html#sum/2) then provide the correct option to sum across the _rows_. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.sum(tensor, axes: [1])
+ ```
+
+
+ Tip: You can also hover over a function inside Livebook code cells to display its documentation.
+
+
+
+
+
+
+
+**6. Create a tensor of zeros of size 10 but where the fifth value is 1. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ zeros = Nx.broadcast(0, {10})
+ index = Nx.tensor([4])
+ Nx.indexed_put(zeros, index, 1)
+ ```
+
+
+
+
+
+
+**7. Create a 3x3 tensor with values ranging from 0 to 8. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.iota({3, 3})
+ ```
+
+
+
+
+
+
+**8. Create a tensor with values ranging from 10 to 49. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution 1
+
+
+ ```elixir
+ Nx.iota({39})
+ |> Nx.add(10)
+ ```
+
+
+
+
+
+
+
+ Example solution 2
+
+
+ ```elixir
+ Nx.linspace(10, 49, n: 39, type: :s64)
+ ```
+
+
+
+
+
+
+**9. Reverse `tensor` (first element becomes last). (★☆☆)**
+
+```elixir
+tensor = Nx.tensor([2, 4, 6, 8])
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.reverse(tensor)
+ ```
+
+
+
+
+
+
+**10a. Given an initial `tensor`, build a "mask" of non-zero elements. That is, build a second tensor with the same shape as the original, but that has a 1 wherever the original has a non-zero element and a 0 elsewhere. (★☆☆)**
+
+```elixir
+tensor = Nx.tensor([1, 2, 0, 0, 4, 0])
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ mask = Nx.not_equal(tensor, 0)
+ ```
+
+
+
+
+
+
+**10b. Use the mask from 10a to replace each 0 from `tensor` with -1. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.select(mask, tensor, -1)
+ ```
+
+
+
+
+## 11-20
+
+**11. Create a 3x3 identity tensor. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.eye(3)
+ ```
+
+
+
+
+
+
+**12. Create a 3x3x3 tensor with random values. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ key = Nx.Random.key(0)
+ {random, _} = Nx.Random.normal(key, shape: {3, 3, 3})
+ random
+ ```
+
+
+
+
+
+
+**13. Create a random 10x10 tensor then find its minimum and maximum values. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ key = Nx.Random.key(0)
+ {tensor, _} = Nx.Random.normal(key, shape: {10, 10})
+
+ %{
+ min: Nx.reduce_min(tensor),
+ max: Nx.reduce_max(tensor)
+ }
+ ```
+
+
+
+
+
+
+**14. Create a random 1D tensor of size 30 then find its mean. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ key = Nx.Random.key(0)
+ {tensor, _} = Nx.Random.normal(key, shape: {30})
+
+ Nx.mean(tensor)
+ ```
+
+
+
+
+
+
+**15. Create a 4x4 tensor with 1 on the border and 0 inside. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.broadcast(1, {4, 4})
+ |> Nx.put_slice([1, 1], Nx.broadcast(0, {2, 2}))
+ ```
+
+
+
+
+
+
+**16. Add a border of 0 around `tensor` (end result will be a 5x5 tensor). (★☆☆)**
+
+```elixir
+tensor = Nx.broadcast(1, {3, 3})
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.pad(tensor, 0, [{1, 1, 0}, {1, 1, 0}])
+ ```
+
+
+
+
+
+
+**17. Determine the results of the following expressions. (★☆☆)**
+
+```elixir
+nan = Nx.Constants.nan()
+Nx.multiply(0, nan)
+Nx.equal(nan, nan)
+Nx.greater(nan, nan)
+Nx.subtract(nan, nan)
+
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```
+ #Nx.Tensor<
+ f32
+ NaN
+ >
+ #Nx.Tensor<
+ u8
+ 0
+ >
+ #Nx.Tensor<
+ u8
+ 0
+ >
+ #Nx.Tensor<
+ f32
+ NaN
+ >
+ ```
+
+
+
+
+
+
+**18. Create a 5x5 tensor with values 1,2,3,4 just below the diagonal. (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.tensor([1, 2, 3, 4])
+ |> Nx.make_diagonal(offset: -1)
+ ```
+
+
+
+
+
+
+**19. Create a 8x8 tensor of 0 and 1 in a checkerboard pattern with 0 as the first element using [`Nx.tile`](https://hexdocs.pm/nx/Nx.html#tile/2). (★☆☆)**
+
+```elixir
+# Add your solution here.
+```
+
+
+ Example solution
+
+
+ ```elixir
+ Nx.tensor([[0, 1], [1, 0]])
+ |> Nx.tile([4, 4])
+ ```
+
+
+
+
+
+
+**20. Produce the same checkerboard pattern from exercise 19, but _without_ using `Nx.tile`. (★☆☆)**
+
+```elixir
+# Add your solution here.
+# Hint: try using `Nx.iota` in combination with `Nx.remainder`.
+```
+
+
+ Example solution 1
+
+
+ ```elixir
+ t = Nx.iota({8, 1})
+
+ Nx.transpose(t)
+ |> Nx.add(t)
+ |> Nx.remainder(2)
+ ```
+
+
+
+
+
+
+
+ Example solution 2
+
+
+ ```elixir
+ Nx.iota({9, 9})
+ |> Nx.remainder(2)
+ |> Nx.slice([0, 0], [8, 8])
+ ```
+
+
+
diff --git a/nx/mix.exs b/nx/mix.exs
index 672378f71c..dfdea2ee2e 100644
--- a/nx/mix.exs
+++ b/nx/mix.exs
@@ -60,6 +60,7 @@ defmodule Nx.MixProject do
source_url_pattern: "#{@source_url}/blob/v#{@version}/nx/%{path}#L%{line}",
before_closing_body_tag: &before_closing_body_tag/1,
extras: [
+ "exercises/exercises-1-20.livemd",
"guides/intro-to-nx.livemd",
"guides/vectorization.livemd",
"CHANGELOG.md"
@@ -112,6 +113,10 @@ defmodule Nx.MixProject do
Nx.Defn.Token,
Nx.Defn.Tree
]
+ ],
+ groups_for_extras: [
+ Exercises: ~r"exercises/",
+ Guides: ~r"guides/"
]
]
end