Skip to content

Commit d24cdf8

Browse files
committed
adjustments to the slides
1 parent 32e81bd commit d24cdf8

File tree

3 files changed

+32
-23
lines changed

3 files changed

+32
-23
lines changed

README.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ In this exercise, we will take a closer look at the mechanics of Principal Compo
44

55
### Task 1: Principal Component Analysis
66

7-
In this task, we will implement all the necessary steps to perform a PCA and visualize how much of the original information content of an image remains after the image features are projected into a lower dimensional space. To achieve this, we will treat each row of the input image as an individual data sample, with the features represented by the RGB values in each column. We then apply PCA to these samples to obtain the principal components, project each sample onto the first _k_ principal components, and then back into the original space. The example image we use has _531 rows x 800 columns x 3 color values_, resulting in 531 samples with 2400 features each.
7+
In this task, we will implement all the necessary steps to perform a PCA and visualize how much of the original information content of an image remains after the image features are projected into a lower dimensional space.
88

99
Navigate to `src/ex1_pca.py` and have a look at the `__main__` function :
1010

@@ -13,13 +13,13 @@ Navigate to `src/ex1_pca.py` and have a look at the `__main__` function :
1313

1414
> Note: You can also use ``plt.imshow()`` followed by ``plt.savefig(your_path)`` as a simple way to save the image. Do not forget to ``plt.close()`` your plot afterwards, because we will export a fair amount of images in this exercise.
1515
16-
3. Reshape the image array into a 2D-array of shape $(n,m)$, where $n$ = `num_rows` and $m$ = `num_columns * num_channels`, such that each row of this new array represents all pixel values of the corresponding image row.
16+
3. Reshape the image array into a 2D-array of shape $(d,n)$, where $d$ = `num_rows` is the number of features and $n$ = `num_columns * num_channels` would represent our examples.
1717

1818
Now we will implement the functions to perform a PCA transform and an inverse transform on our 2D array. First implement the function `pca_transform`:
1919

20-
4. Compute the mean vector over the features of the input matrix. The resulting mean vector should have the size $(1,m)$.
20+
4. Compute the mean vector over the features of the input matrix. The resulting mean vector should have the size $(d,1)$.
2121
5. Center the data by subtracting the mean from the 2D image array.
22-
6. Compute the covariance matrix of the centered data. (Hint: `numpy.cov`, set `rowvar=False` in order to compute the covariances on features.)
22+
6. Compute the covariance matrix of the centered data. (Hint: `numpy.cov`.)
2323
7. Perform the eigendecomposition of the covariance matrix. (Hint: `numpy.linalg.eigh`)
2424
8. Sort eigenvalues in descending order and eigenvectors by their descending eigenvalues.
2525
9. Return sorted eigenvalues, eigenvectors, centered data and the mean vector.
@@ -42,12 +42,15 @@ Go back to the `__main__` function and implement the following TODOs:
4242
17. Loop through a range of all possible values of the number of components. It is sufficient to use the step size of 10 to speed up the process. To monitor the progress of the loop, you can create a progress bar using [the very handy Python package tqdm](https://github.com/tqdm/tqdm).
4343

4444
17.1. Perform PCA using the previously implemented `pca_transform` function.
45+
4546
17.2. Apply the `pca_inverse_transform` function to project the image to lower-dimensional space using the current number of components and reconstruct the image from this reduced representation.
47+
4648
17.3. Bring the resulting array back into the original image shape and save it in the ``output`` folder as an image called ``pca_k.png``, where _k_ is replaced with the number of components used to create the image.
4749

4850
> Note: You should again cast the image back to the uint8 dtype.
4951
5052
17.4. Compute the cumulative explained variance ratio for the current number of components using the `expl_var` function and store it in a list for later plotting.
53+
5154
17.5. We would also like to quantify how closely our created image resembles the original one. Use ``skimage.metrics.structural_similarity`` to compute a perceptual similarity score (SSIM) between the original and the reconstructed image and also store it in another list for later plotting. As we deal with RGB images, you have to pass `channel_axis=2` to the SSIM function.
5255

5356
18. Plot the cumulative explained variances of each principal component against the number of components.
@@ -61,7 +64,7 @@ We have seen that a significantly reduced feature dimensionality is often suffic
6164

6265
We start in the the `__main__` function.
6366

64-
1. Load the dataset from ``sklearn.datasets.fetch_lfw_people`` in the same way as for Task 2 of Day 06 and get access to the data.
67+
1. Load the dataset from ``sklearn.datasets.fetch_lfw_people`` in the same way as for Task 2 of Day 05 and get access to the data.
6568
2. Split the data 80:20 into training and test data. Use `random_state=42` in the split function.
6669
3. Use the `StandardScaler` from `sklearn.preprocessing` on the train set and scale both the train and the test set.
6770

@@ -80,7 +83,7 @@ Implement the `pca_train` function to train a model on preprocessed data:
8083
10. Call the `train_fun` function, which is passed as an argument, to train a model on the transformed PCA features.
8184
11. The function should return a tuple containing two elements: the PCA decomposition object and the trained model.
8285

83-
12. Import or paste your cv_svm function from Task 2 of Day 06 above the code. Utilize it together with the computed number of required components to call `pca_train` in the `__main__` function. This will allow us to train the model with the reduced feature set. Use the `time` function from the `time` module to measure and print the duration of this process for evaluation.
86+
12. Import or paste your cv_svm function from Task 2 of Day 05 above the code. Utilize it together with the computed number of required components to call `pca_train` in the `__main__` function. This will allow us to train the model with the reduced feature set. Use the `time` function from the `time` module to measure and print the duration of this process for evaluation.
8487

8588
13. To evaluate the model on the test set, we need to perform the same transform on the test data, as we did on the training data. Use the `PCA.transform` of your PCA decomposition object to do this.
8689
14. Now we can compute and print the accuracy of our trained model on the test set.
@@ -106,13 +109,19 @@ Implement the `gs_pca` function, which utilizes a grid search approach to determ
106109
21. Next, initialize the variables to keep track of the best mean accuracy score and the corresponding number of PCA components found 22. Iterate through the specified list of PCA component values.
107110

108111
22.1. Create an outer 5-fold cross-validation loop, iterating through the 5 splits while obtaining the training and testing indices for each split.
112+
109113
22.1.1. Generate the current training and testing sets from the given data based on these indices.
114+
110115
22.1.2. Scale the generated data fitting the `StandardScaler` on the training set and scale the training and test sets.
116+
111117
22.1.3. Instantiate a PCA object with the same parameters as before and transform the training data.
118+
112119
22.1.4. Now is the time to call our function `cv_svm` and perform the inner cross-validation to tune hyperparameters. In order to save you the time, we have determined that the following parameters consistently yield the best results: C=10 and kernel='rbf'. Therefore, you can skip the inner cross-validation step and proceed to create and train your classifier with these predefined parameters.
120+
113121
22.1.5. Predict the labels on the test data and compute the accuracy score for each fold.
114122

115123
22.2. Calculate the mean accuracy score across the folds.
124+
116125
22.3. If the mean accuracy score for the current number of PCA components is higher than the best score seen so far, update the best score and the best number components.
117126
23. The function should return the number of PCA components that yielded the highest mean accuracy score during the grid search. This represents the optimal number of components for feature dimensionality reduction.
118127

src/ex1_pca.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@
1212

1313

1414
def pca_transform(
15-
img_rows: np.ndarray,
15+
img_cols: np.ndarray,
1616
) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
1717
"""Perform a PCA transformation on the input matrix.
1818
1919
Args:
20-
img_rows (np.ndarray): Rows of flattened image data (size n x m).
20+
img_cols (np.ndarray): Rows of flattened image data (size d x n).
2121
2222
Returns:
2323
tuple: Instances of the Principal Component Analysis:
24-
np.ndarray (m x 1): The eigenvalues sorted in descending order.
25-
np.ndarray (m x m): The eigenvectors sorted according to the order of the eigenvalues.
26-
np.ndarray (n x m): The zero-meaned data matrix.
27-
np.ndarray (1 x m): The vector of the feature means of the input matrix.
24+
np.ndarray (d x 1): The eigenvalues sorted in descending order.
25+
np.ndarray (d x d): The eigenvectors sorted according to the order of the eigenvalues.
26+
np.ndarray (d x n): The zero-meaned data matrix.
27+
np.ndarray (d x 1): The vector of the feature means of the input matrix.
2828
"""
2929
# 4. compute mean for each feature
3030
# TODO

tests/test_ex1_pca.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@
1010

1111
# sample image for testing
1212
image = load_sample_image("flower.jpg")
13-
image_rows = np.reshape(image, (image.shape[0], -1)).T
13+
img_cols = np.reshape(image, (image.shape[0], -1))#.T
1414

1515

1616
def test_pca_transform():
1717
"""Test the PCA transformation of the image."""
1818
custom_eigenvalues, custom_eigenvectors, centered_data, mean_vector = pca_transform(
19-
image_rows
19+
img_cols
2020
)
2121

2222
# use sklearn's PCA for same transformation
2323
sklearn_pca = PCA(svd_solver="full")
24-
sklearn_pca.fit(image_rows)
24+
sklearn_pca.fit(img_cols.T)
2525
sklearn_eigenvalues = sklearn_pca.explained_variance_
2626

2727
# check if eigenvalues are approximately equal
@@ -36,26 +36,26 @@ def test_pca_transform():
3636
abs(dot_product), 0
3737
), f"Eigenvectors {i} and {j} are not orthogonal."
3838

39-
assert len(centered_data) == len(image_rows)
40-
assert len(mean_vector) == image_rows.shape[1]
39+
assert len(centered_data) == len(img_cols)
40+
assert len(mean_vector) == img_cols.shape[0]
4141

4242

4343
def test_pca_inverse_transform():
4444
"""Test the inverse PCA transformation."""
4545
n_components = 10
46-
_, custom_eigenvectors, centered_data, mean_vector = pca_transform(image_rows)
46+
_, custom_eigenvectors, centered_data, mean_vector = pca_transform(img_cols)
4747
custom_reconstructed_data = pca_inverse_transform(
4848
centered_data, custom_eigenvectors, mean_vector, n_components
4949
)
5050

5151
# use sklearn's PCA for same transformation
52-
sklearn_pca = PCA(n_components=n_components)
53-
sklearn_pca.fit(image_rows)
52+
sklearn_pca = PCA(svd_solver="full",n_components=n_components)
53+
sklearn_pca.fit(img_cols.T)
5454
sklearn_reconstructed_data = sklearn_pca.inverse_transform(
55-
sklearn_pca.transform(image_rows)
56-
)
55+
sklearn_pca.transform(img_cols.T)
56+
).T
5757

58-
assert custom_reconstructed_data.shape == image_rows.shape
58+
assert custom_reconstructed_data.shape == img_cols.shape
5959
# check if results are approximately equal
6060
np.testing.assert_allclose(
6161
custom_reconstructed_data, sklearn_reconstructed_data, rtol=5

0 commit comments

Comments
 (0)