Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 7 additions & 18 deletions content/tutorial-svd.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ You can check that the above works by doing some tests; for example, inquiring
about maximum and minimum values for this array:

```{code-cell}
img_array.max(), img_array.min()
img_array.min(), img_array.max()
```

or checking the type of data in the array:
Expand All @@ -142,12 +142,6 @@ It is possible to use methods from linear algebra to approximate an existing set

+++

To proceed, import the linear algebra submodule from NumPy:

```{code-cell}
from numpy import linalg
```

In order to extract information from a given matrix, we can use the SVD to obtain 3 arrays which can be multiplied to obtain the original matrix. From the theory of linear algebra, given a matrix $A$, the following product can be computed:

$$U \Sigma V^T = A$$
Expand Down Expand Up @@ -183,7 +177,8 @@ plt.show()
Now, applying the [linalg.svd](https://numpy.org/devdocs/reference/generated/numpy.linalg.svd.html#numpy.linalg.svd) function to this matrix, we obtain the following decomposition:

```{code-cell}
U, s, Vt = linalg.svd(img_gray)
import numpy as np
U, s, Vt = np.linalg.svd(img_gray)
```

**Note** If you are using your own image, this command might take a while to run, depending on the size of your image and your hardware. Don't worry, this is normal! The SVD can be a pretty intensive computation.
Expand All @@ -206,8 +201,6 @@ s @ Vt
results in a `ValueError`. This happens because having a one-dimensional array for `s`, in this case, is much more economic in practice than building a diagonal matrix with the same data. To reconstruct the original matrix, we can rebuild the diagonal matrix $\Sigma$ with the elements of `s` in its diagonal and with the appropriate dimensions for multiplying: in our case, $\Sigma$ should be 768x1024 since `U` is 768x768 and `Vt` is 1024x1024. In order to add the singular values to the diagonal of `Sigma`, we will use the [fill_diagonal](https://numpy.org/devdocs/reference/generated/numpy.fill_diagonal.html) function from NumPy:

```{code-cell}
import numpy as np

Sigma = np.zeros((U.shape[1], Vt.shape[0]))
np.fill_diagonal(Sigma, s)
```
Expand All @@ -221,7 +214,7 @@ Now, we want to check if the reconstructed `U @ Sigma @ Vt` is close to the orig
The [linalg](https://numpy.org/devdocs/reference/routines.linalg.html#module-numpy.linalg) module includes a `norm` function, which computes the norm of a vector or matrix represented in a NumPy array. For example, from the SVD explanation above, we would expect the norm of the difference between `img_gray` and the reconstructed SVD product to be small. As expected, you should see something like

```{code-cell}
linalg.norm(img_gray - U @ Sigma @ Vt)
np.linalg.norm(img_gray - U @ Sigma @ Vt)
```

(The actual result of this operation might be different depending on your architecture and linear algebra setup. Regardless, you should see a small number.)
Expand Down Expand Up @@ -280,22 +273,18 @@ img_array.shape
```

so we need to permutate the axis on this array to get a shape like `(3, 768, 1024)`. Fortunately, the [numpy.transpose](https://numpy.org/devdocs/reference/generated/numpy.transpose.html#numpy.transpose) function can do that for us:
```
np.transpose(x, axes=(i, j, k))
```
indicates that the axis will be reordered such that the final shape of the transposed array will be reordered according to the indices `(i, j, k)`.

Let's see how this goes for our array:

```{code-cell}
# The values in the tuple indicate the original dim, and the order the new axis
# so axis 2 -> 0, 0 -> 1, and 1 -> 2
img_array_transposed = np.transpose(img_array, (2, 0, 1))
img_array_transposed.shape
```

Now we are ready to apply the SVD:

```{code-cell}
U, s, Vt = linalg.svd(img_array_transposed)
U, s, Vt = np.linalg.svd(img_array_transposed)
```

Finally, to obtain the full approximated image, we need to reassemble these matrices into the approximation. Now, note that
Expand Down
Loading