{ "cells": [ { "cell_type": "markdown", "id": "4f26dc3c", "metadata": {}, "source": [ "Lecture 09: Machine Learning 3 (exercises)" ] }, { "cell_type": "markdown", "id": "293ce49e", "metadata": {}, "source": [ "# EX: Semantic classification of satellite image" ] }, { "cell_type": "markdown", "id": "ffa45a51", "metadata": {}, "source": [ "
\n", "This exercise has been developed by Andreas Ley and Ronny Hänsch (TU-Berlin) in the framework of the GEO.X 2017 Autumn school.
\n", "
\n", "The exercise is designed to implement the classification of a satellite image (Sentinel-2) into semantic labels defining land use: forest, fields, urban, water.
\n", "
\n", "The exercise is split into 2 parts: the first part implements a PCA analysis on the image crops in order to reduce dimensionality, and the second part uses the outputs of the PCA and implement a SVM to classify the pixels into different land use classes.\n", "
\n", "
\n", "
\n", "
\n", "
" ] }, { "cell_type": "code", "execution_count": null, "id": "3cd830e8", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "4be3257c", "metadata": {}, "source": [ "
\n", "Description of the dataset:
\n", "
\n", "Part 1: In the first part of the exercise, you will use the file s2_training_data.npz. It contains image crops of a Sentinel-2 multispectral image, and some semantic labels of land use.
\n", "
\n", " The file can be loaded using numpy.load(), and contains 2 parts:
\n", " \n", "
" ] }, { "cell_type": "markdown", "id": "437fbe4a", "metadata": {}, "source": [ "
\n", "Part 2: In the second part of the exercise, in addition to the training data you will be using two other files:
\n", " \n", "
" ] }, { "cell_type": "markdown", "id": "5d1501cf", "metadata": {}, "source": [ "## PART 1 (PCA)" ] }, { "cell_type": "markdown", "id": "11365973", "metadata": {}, "source": [ "### load data" ] }, { "cell_type": "markdown", "id": "58768f3a", "metadata": {}, "source": [ "
\n", " Load the data using numpy.load(). Store the \"data\" in a variable named \"train_X\", anf the \"labels\" in a variable named \"train_Y\". Explore the shape of these arrays.\n", "
" ] }, { "cell_type": "markdown", "id": "16d58d9b", "metadata": {}, "source": [ "### inspect image crops" ] }, { "cell_type": "markdown", "id": "0cea9518", "metadata": {}, "source": [ "
\n", " Use the function below to look at the (RGB-part) of individual crops.
Take a look at the first crop of each class (remember: crops 1-5k contain forest, crops 5-10k contain fields, crops 10-15k are urban areas, and crops 15-20k are water).\n", "
" ] }, { "cell_type": "code", "execution_count": 4, "id": "34651307", "metadata": {}, "outputs": [], "source": [ "def show_raw_image(img):\n", " img2 = np.log(img[[2,1,0],:,:])\n", "\n", " img2[0,:,:] = img2[0,:,:].copy() * 1.05303 + -6.32792\n", " img2[1,:,:] = img2[1,:,:].copy() * 1.74001 + -10.8407\n", " img2[2,:,:] = img2[2,:,:].copy() * 1.20697 + -6.73016\n", "\n", " img2 = np.clip(img2 / 6 + 0.5, 0.0, 1.0)\n", "\n", " plt.imshow(np.transpose(img2, (1, 2, 0)))\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": 5, "id": "8c7b96cb", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPsAAAD4CAYAAAAq5pAIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAPvElEQVR4nO3dXYxc9XnH8e9vZncN2G5tl5IQjApUCIlGlUAWIkmVRqVEDkU4F70AJa3bREJcpIUqVWKE1Nw2TZs2VVEjFNJSFcFFgMaKoMWiiapIwQq45i0mQCgFBwdomwI2L96ZeXoxx3QzmV3vPudlp/3/PtJqZ/ecs/9nz5zfnHn7z6OIwMz+/+utdwFm1g2H3awQDrtZIRx2s0I47GaFmOtysE0bN8bWbVvWvF29VwxUY9vuRwxGnY+qddhHWVqH01Odwy+7bfYa+fGP/5ujx45N3bzTsG/dtoVPX3/dmrdbXMwGAOivQ9jVT287HBxNDrohPWY/Wa8inzz1ctfp3Ib8vs0aDPLbDke5/3M+eaf7z75087LLfDferBAOu1khaoVd0k5J35f0jKQ9TRVlZs1Lh13jB6Y3Ax8BLgSukXRhU4WZWbPqnNkvAZ6JiGcj4jhwJ7CrmbLMrGl1wn4W8MKSnw9XvzOzGVQn7NNe0/qpVxUlXSvpIUkPHTt6rMZwZlZHnbAfBs5e8vN24MXJlSLilojYERE7Nm7aWGM4M6ujTti/C5wv6VxJC8DVwN5myjKzpqXfQRcRA0mfAv4J6ANfjYgnGqvMzBpV6+2yEXEvcG9DtZhZi/wOOrNCOOxmheh01hsBMUrM+VONWW/DYX7TXnJ+Yo0pkdkZc/0a8zD7yZv84ejt/Jij3KGnyB+yg2Fu+lqdeZO9uVy9MXgrOeLyx4HP7GaFcNjNCuGwmxXCYTcrhMNuVgiH3awQDrtZIRx2s0I47GaFcNjNCuGwmxXCYTcrhMNuVohuZ70hpPk1b9VTft7RiHxvsP463BaOP5U7s12NQZPT3sQp6SGPR2424gbysxh763BqGwzeTG13fLSY2i48683MHHazQjjsZoWo0+vtbEnflHRI0hOSrm+yMDNrVp0n6AbApyPigKTNwMOS9kXE9xqqzcwalD6zR8SRiDhQXX4dOIR7vZnNrEYes0s6B7gI2N/E3zOz5tUOu6RNwF3ADRHx2pTl/9vY8ZgbO5qtl1ph1/gdMncBt0fE3dPW+YnGjhvd2NFsvdR5Nl7ArcChiPhicyWZWRvqnNk/APwW8GuSDlZfVzRUl5k1rE4X129Tr1mGmXXI76AzK4TDblaITqe4CuglejT2emufFnvCYDHbIA9Gc7lGgHVEL/nIKPLNL2OYnR+bH7OXbNYZdf5P1ZkHnKP0FOvmjz2f2c0K4bCbFcJhNyuEw25WCIfdrBAOu1khHHazQjjsZoVw2M0K4bCbFcJhNyuEw25WCIfdrBCdznoLgqHW3phvOMjPdGIuf3s2TDbXU2xIj5k2WkhvqvncYZDsBzkeMznrjV6NQ3ax+1lv0cs1ouynG1guP2vSZ3azQjjsZoVw2M0K0USTiL6kf5X0jSYKMrN2NHFmv55xnzczm2F1O8JsB34D+Eoz5ZhZW+qe2f8C+Ax1PnnQzDpRp/3TlcDLEfHwSdZzY0ezGVC3/dNVkp4D7mTcBurvJ1dyY0ez2ZAOe0TcGBHbI+Ic4GrgnyPi441VZmaN8uvsZoVo5L3xEfEt4FtN/C0za4fP7GaFcNjNCtHpFFfINREcDt5Mj9fr5aebSrlpo+p13xCy1phxPLddjWm1I+XqHY3y01T7o9zbQers22zA0r02V+Azu1khHHazQjjsZoVw2M0K4bCbFcJhNyuEw25WCIfdrBAOu1khHHazQjjsZoVw2M0K4bCbFaLzWW/qrf32ZX6+nx5vwyn5z70bDt9Obbc4XL65XmtqdFmMUa6J4OIoOVsOiORMMkV+BlqvN58bs9f99dmL3JhaYTOf2c0K4bCbFcJhNytE3fZPWyR9TdKTkg5Jel9ThZlZs+o+Qfcl4B8j4jc1/gyn0xqoycxakA67pJ8BPgj8DkBEHAfyT8+aWavq3I0/D3gF+JuqP/tXJLm/k9mMqhP2OeBi4K8j4iLgGLBnciU3djSbDXXCfhg4HBH7q5+/xjj8P8GNHc1mQ53Gjj8CXpB0QfWry4DvNVKVmTWu7rPxvwfcXj0T/yzwu/VLMrM21Ap7RBwEdjRTipm1ye+gMyuEw25WiE6nuAoxl5jiejzyZarGvygWc9spN2W0DtW53VZu27l+fuqxIrePQvkxF5J9KEVuamwdC8l/s7fC/vGZ3awQDrtZIRx2s0I47GaFcNjNCuGwmxXCYTcrhMNuVgiH3awQDrtZIRx2s0I47GaFcNjNCtFtY0cJ9U9Z82a9xfwssiDfCDA7w0rKjyl1P8OqN8o1EezVqTU55kj5TysfJRs7zteIyeLwrfS2GUEsu8xndrNCOOxmhXDYzQpRt7HjH0h6QtLjku6QtPYH5GbWiXTYJZ0F/D6wIyLeC/SBq5sqzMyaVfdu/BxwqqQ5xh1cX6xfkpm1oU5HmB8Cfwo8DxwBXo2I+5sqzMyaVedu/FZgF3Au8B5go6SPT1nvncaOR93Y0Wzd1Lkb/+vAv0XEKxGxCNwNvH9ypaWNHTe5saPZuqkT9ueBSyWdJkmMGzseaqYsM2tancfs+xm3aT4APFb9rVsaqsvMGla3sePngM81VIuZtcjvoDMrhMNuVohuGzsq6PXX3iwx2QMQgKPH3kxvu7CQ2z2q0YiSXn4KZ9ZofkNqu7nIT98czp2a3PDt9JijUW67N0f5l4z7kZvKm7b8DFef2c1K4bCbFcJhNyuEw25WCIfdrBAOu1khHHazQjjsZoVw2M0K4bCbFcJhNyuEw25WCIfdrBDdNnYM0UvMCOvXmPY2IL9t9pYwIjm9ChgNOp4lBSyMcg0PR/P5GWhBcsZcjWMhFleYEraCwTA/pnq5MfPc2NGseA67WSEcdrNCnDTskr4q6WVJjy/53TZJ+yQ9XX3f2m6ZZlbXas7sfwvsnPjdHuCBiDgfeKD62cxm2EnDHhH/AvzXxK93AbdVl28DPtpsWWbWtOxj9ndFxBGA6vsZzZVkZm1o/Qk6N3Y0mw3ZsL8k6UyA6vvLy63oxo5msyEb9r3A7urybuDrzZRjZm1ZzUtvdwDfAS6QdFjSJ4E/Bi6X9DRwefWzmc2wk75RPSKuWWbRZQ3XYmYt8jvozArhsJsVovPGjn2tvXHh3Fw/PeYw6kwxzE1V7fdzjRIBGOSmfs7P15kam2t+ORrmr5cF5fbRYG4hPSbJXTQY5afyDka5428hfQwt/0/6zG5WCIfdrBAOu1khHHazQjjsZoVw2M0K4bCbFcJhNyuEw25WCIfdrBAOu1khHHazQjjsZoXovLEjkZi1FIP0kL25/O1Zj9wMq57y9Y56uXp7vVPTY2b1ajQtHCWbX/YX8rPeRsdz18v8XH4W44Z+7nrRQm7fqudZb2bFc9jNCuGwmxUi29jxC5KelPSopHskbWm1SjOrLdvYcR/w3oj4ZeAp4MaG6zKzhqUaO0bE/RHvPEX+ILC9hdrMrEFNPGb/BHBfA3/HzFpUK+ySbgIGwO0rrPNOY8fX3djRbN2kwy5pN3Al8LGI5T+veWljx81u7Gi2blLvoJO0E/gs8KsR8UazJZlZG7KNHf8K2Azsk3RQ0pdbrtPMaso2dry1hVrMrEV+B51ZIRx2s0J0O8VVgNZ++zIi1+xwvG1+GmaPYWq7yHYQJF/vSIvpMbMU8+lth7kZrvQXc9cJwCiOprbbsGFzesxIHO8Ag7dyzTZXeGHMZ3azUjjsZoVw2M0K4bCbFcJhNyuEw25WCIfdrBAOu1khHHazQjjsZoVw2M0K4bCbFcJhNytEp7PeAgjWPt1plJ+4xnCQnF4FDEZvp7br99NDQi9X7xtv52cGZkXkzxVKzgxcmM83sOz1T8ttF/lZjMeOH09tNxfJWYye9WZmDrtZIRx2s0KkGjsuWfaHkkLS6e2UZ2ZNyTZ2RNLZwOXA8w3XZGYtSDV2rPw58Bmo8SFvZtaZ1GN2SVcBP4yIRxqux8xasubX2SWdBtwEfHiV618LXAuwbevWtQ5nZg3JnNl/ETgXeETSc4x7sx+Q9O5pKy9t7Lhpkxs7mq2XNZ/ZI+Ix4IwTP1eB3xER/9FgXWbWsGxjRzP7Pybb2HHp8nMaq8bMWuN30JkVwmE3K4RWagTX+GDSK8C/L7P4dGCWnuSbtXpg9mpyPStbj3p+ISJ+ftqCTsO+EkkPRcSO9a7jhFmrB2avJtezslmrx3fjzQrhsJsVYpbCfst6FzBh1uqB2avJ9axspuqZmcfsZtauWTqzm1mLHHazQnQedkk7JX1f0jOS9kxZLkl/WS1/VNLFLdZytqRvSjok6QlJ109Z50OSXpV0sPr6o7bqqcZ7TtJj1VgPTVne2f6pxrtgyf9+UNJrkm6YWKfVfTTto9EkbZO0T9LT1fep86dPdrw1WM8XJD1ZXSf3SNqyzLYrXr+tiojOvoA+8APgPGABeAS4cGKdK4D7AAGXAvtbrOdM4OLq8mbgqSn1fAj4Rof76Dng9BWWd7Z/lrn+fsT4jRud7SPgg8DFwONLfvcnwJ7q8h7g85njrcF6PgzMVZc/P62e1Vy/bX51fWa/BHgmIp6NiOPAncCuiXV2AX8XYw8CWySd2UYxEXEkIg5Ul18HDgFntTFWgzrbP1NcBvwgIpZ7F2QrYvpHo+0Cbqsu3wZ8dMqmqzneGqknIu6PiEH144OMP+dhpnQd9rOAF5b8fJifDtdq1mmcpHOAi4D9Uxa/T9Ijku6T9EstlxLA/ZIerj7lZ9K67J/K1cAdyyzrch8BvCsijsD4Rpsln7GwxHrtq08wvvc1zcmu39Z02v4Jpvb8mXztbzXrNErSJuAu4IaIeG1i8QHGd1uPSroC+Afg/BbL+UBEvCjpDGCfpCerM8k75U7ZpvXXTyUtAFcBN05Z3PU+Wq31OJZuAgbA7cuscrLrtzVdn9kPA2cv+Xk78GJincZImmcc9Nsj4u7J5RHxWkQcrS7fC8y3+Tn5EfFi9f1l4B7Gd0WX6nT/LPER4EBEvDS5oOt9VHnpxMOX6vvLU9bp+ljaDVwJfCyqB+iTVnH9tqbrsH8XOF/SudWZ4mpg78Q6e4Hfrp51vhR49cTdtaZJEnArcCgivrjMOu+u1kPSJYz32X+2VM9GSZtPXGb8pM9kc47O9s+Ea1jmLnyX+2iJvcDu6vJu4OtT1lnN8dYISTuBzwJXRcQby6yzmuu3PV0/I8j42eSnGD9LelP1u+uA66rLAm6ulj/G+PPt2qrlVxjfrXsUOFh9XTFRz6eAJxg/k/sg8P4W6zmvGueRasx13T9L6jqNcXh/dsnvOttHjG9kjgCLjM/WnwR+DngAeLr6vq1a9z3AvSsdby3V8wzj5wdOHEdfnqxnueu3qy+/XdasEH4HnVkhHHazQjjsZoVw2M0K4bCbFcJhNyuEw25WiP8B8AfYUSMS300AAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "for i in range(0,4):\n", " show_raw_image(train_X[5000*i])" ] }, { "cell_type": "markdown", "id": "3fe7bbc2", "metadata": {}, "source": [ "### compress image crops" ] }, { "cell_type": "markdown", "id": "6b5ecb1c", "metadata": {}, "source": [ "
\n", " The data train_X contains the raw values which span a large range. To compress them into a more “gaussian” shape, compute the logarithm of them.\n", "
" ] }, { "cell_type": "markdown", "id": "2e300814", "metadata": {}, "source": [ "### build function to compute principal components of image crops\n", "The following tasks will implement a function \"compute_mean_PCs(X)\" which takes image crops as inputs, and returns the mean image, Eigen images (principal components reshaped into images), and Eigen values." ] }, { "cell_type": "markdown", "id": "24f855a9", "metadata": {}, "source": [ "#### compute mean crop, and mean-free crops" ] }, { "cell_type": "markdown", "id": "aba7264f", "metadata": {}, "source": [ "
\n", " Compute the mean image crop, and name the resulting array \"mean\".
\n", " Subtract this \"mean\" from all crops, and name the resulting array \"mean_free\".
\n", "
\n", " Hint: The mean image should be an array of shape (4, 15, 15), and the mean free crops should be an array of shape (20000, 4, 15, 15)).\n", "
" ] }, { "cell_type": "markdown", "id": "6c976079", "metadata": {}, "source": [ "#### vectorize the mean-free crops" ] }, { "cell_type": "markdown", "id": "779b4846", "metadata": {}, "source": [ "
\n", " Flatten the crops into vectors so that you get a numpy array of shape (20000, 4 * 15 * 15).
\n", "
\n", " Hint: use \"np.reshape\".\n", "
" ] }, { "cell_type": "markdown", "id": "33d785bc", "metadata": {}, "source": [ "#### compute the covariance matrix" ] }, { "cell_type": "markdown", "id": "59df1944", "metadata": {}, "source": [ "
\n", " Compute the covariance matrix. This should be a matrix of size 900x900 (900 = 4 * 15 * 15).
\n", "
\n", " Start by defining a matrix of zeros with shape (900,900). Loop over all 20000 crops, and for each crop compute the outer product np.outer(u, v) of the mean-free vector with itself (i.e., u = v = vectorized crop). Accumulate (sum) the outer products together and finally divide by the total number of used crops. (To speed up development, consider using only every 10th crop).
\n", "
\n", " NB: the outer product $u \\otimes v$ is equivalent to a matrix multiplication $u \\cdot v^T$\n", "
" ] }, { "cell_type": "markdown", "id": "83ffc370", "metadata": {}, "source": [ "#### compute Eigen values & Eigen vectors of the covariance matrix" ] }, { "cell_type": "markdown", "id": "07014a41", "metadata": {}, "source": [ "
\n", " Compute the Eigen values \"eig_val\" and Eigen vectors \"eig_vec\" of the covariance matrix using np.linalg.eig().
\n", "
\n", " Sort them by importance (decreasing Eigen values) using the following code:
\n", "
" ] }, { "cell_type": "markdown", "id": "c6897a99", "metadata": {}, "source": [ "#### reshape Eigen vectors into Eigen images" ] }, { "cell_type": "markdown", "id": "35724666", "metadata": {}, "source": [ "
\n", " Reshape the 900 eigen vectors back into the images, i.e. with shape (900, 4, 15, 15), and name this variable \"principal_components\".
\n", "
\n", " Note that the matrix eig_vec contains the Eigen vectors in its rows (not columns as you might expect), so you'll need to transpose the matrix before reshaping it.\n", "
" ] }, { "cell_type": "markdown", "id": "1b435396", "metadata": {}, "source": [ "#### merge into function \"compute_mean_PCs\"" ] }, { "cell_type": "markdown", "id": "fe4d5266", "metadata": {}, "source": [ "
\n", " Merge steps 1.4.1 to 1.4.4 into a single function \"compute_mean_PCs\".
\n", "
\n", " The function will take the image crops as inputs (i.e., variable \"train_X\"), and will return the mean image (i.e., variable \"mean\"), the Eigen images (principal components reshaped into images, i.e., variable \"principal_components\"), and Eigen values (i.e., variable \"eig_val\").\n", "
" ] }, { "cell_type": "markdown", "id": "ac9e2bf2", "metadata": {}, "source": [ "### run \"compute_mean_PCs\" and plot Eigen values" ] }, { "cell_type": "markdown", "id": "df1f5e61", "metadata": {}, "source": [ "
\n", " Run \"compute_mean_PCs\" on the satellite data, and plot the returned Eigen values.
\n", "
\n", " Look at the first 64 principal components (or the RGB part thereof) using the following function:\n", "
" ] }, { "cell_type": "code", "execution_count": 22, "id": "34479fa6", "metadata": {}, "outputs": [], "source": [ "def show_first_principal_components(pcs):\n", "\n", " f, axarr = plt.subplots(8,8)\n", " for i in range(0,8):\n", " for j in range(0,8):\n", " img2 = pcs[i*8+j, [2,1,0], :, :]\n", " img2 = np.clip(img2 * 10 + 0.5, 0.0, 1.0)\n", " axarr[i,j].imshow(np.transpose(img2, (1, 2, 0)))\n", "\n", " plt.show()" ] }, { "cell_type": "markdown", "id": "87e8eae6", "metadata": {}, "source": [ "### compute features" ] }, { "cell_type": "markdown", "id": "ad982f90", "metadata": {}, "source": [ "
\n", " Write a function \"compute_features(X, mean, principal_components, count)\" that takes crops \"X\", subtracts the mean, and projects them onto the first \"count\" principal components.
\n", "
\n", " The returned array should have a shape (X.shape[0], count), containing the coefficients (which we will use as features in next week's exercise).
\n", "
\n", " Hint: the projection is done using the dot product.\n", "
" ] }, { "cell_type": "markdown", "id": "507a557f", "metadata": {}, "source": [ "### reconstruct image" ] }, { "cell_type": "markdown", "id": "34e2bcb4", "metadata": {}, "source": [ "
\n", " Write a function \"reconstruct_image(feature, mean, principal_components)\" that restores a crop given a feature/coefficient vector.
\n", "
\n", " Use the following code to compare, side by side, original image crops and reconstructions:\n", "
" ] }, { "cell_type": "markdown", "id": "f772b856", "metadata": {}, "source": [ "```python\n", "# Code to compare, side by side, original image crops and reconstructions: \n", "for i in range(0,4): \n", " img = np.concatenate((train_X[5000*i+0,:,:,:], reconstruct_image(train_features[5000*i+0,:], mean, principal_components)), 2);\n", " img = np.concatenate((img,np.concatenate((train_X[5000*i+1,:,:,:], reconstruct_image(train_features[5000*i+1,:], mean, principal_components)), 2)), 1);\n", " img = np.concatenate((img,np.concatenate((train_X[5000*i+2,:,:,:], reconstruct_image(train_features[5000*i+2,:], mean, principal_components)), 2)), 1);\n", " img = np.concatenate((img,np.concatenate((train_X[5000*i+3,:,:,:], reconstruct_image(train_features[5000*i+3,:], mean, principal_components)), 2)), 1);\n", " img = np.concatenate((img,np.concatenate((train_X[5000*i+4,:,:,:], reconstruct_image(train_features[5000*i+4,:], mean, principal_components)), 2)), 1);\n", " show_raw_image(np.exp(img))\n", "```" ] }, { "cell_type": "markdown", "id": "1af4bf05", "metadata": {}, "source": [ "## PART 2 (SVM classification)" ] }, { "cell_type": "markdown", "id": "1540874c", "metadata": {}, "source": [ "### (optional) define functions developed in part 1" ] }, { "cell_type": "markdown", "id": "9edfc932", "metadata": {}, "source": [ "
\n", " The datasets contain 5k crops per class. Each crop is 15x15 pixels in size with 4 channels per pixel. The label of the central pixel is given in a separate array. Since the input dimensionality of each crop is quite high (4x15x15 = 900), we want to compress it using PCA.
\n", " The following function have been developped in the 1st part of the exercice.\n", "
" ] }, { "cell_type": "markdown", "id": "0f07f28b", "metadata": {}, "source": [ "### run PCA on training_data" ] }, { "cell_type": "markdown", "id": "23deb622", "metadata": {}, "source": [ "
\n", " Use the functions implemented for the PCA exercise to compute the mean and principal components on the training data (s2_training_data.npz).
\n", " Compute a 16-dimensional feature vector for each training sample by using the \"compute_features\" function.\n", "
" ] }, { "cell_type": "markdown", "id": "e1915902", "metadata": {}, "source": [ "### train a SVM on PCA features" ] }, { "cell_type": "markdown", "id": "d3fa7895", "metadata": {}, "source": [ "
\n", " Train a support vector machine on the computed features and the corresponding labels. Use sklearn.svm.SVC().
\n", "
\n", " Use default kernel (RBF), and set the following parameters: gamma=0.001, C=100.\n", "
" ] }, { "cell_type": "code", "execution_count": 41, "id": "270675e9", "metadata": {}, "outputs": [], "source": [ "# Options:\n", "#\n", "# kernel : {'linear', 'poly', 'rbf', 'sigmoid', 'precomputed'}, default='rbf'\n", "#\n", "# C : float, default=1.0\n", "# Regularization parameter. The strength of the regularization is\n", "# inversely proportional to C. Must be strictly positive. The penalty\n", "# is a squared l2 penalty.\n", "#\n", "# gamma : {'scale', 'auto'} or float, default='scale'\n", "# Kernel coefficient for 'rbf', 'poly' and 'sigmoid'.\n", "# - if ``gamma='scale'`` (default) is passed then it uses\n", "# 1 / (n_features * X.var()) as value of gamma,\n", "# - if 'auto', uses 1 / n_features." ] }, { "cell_type": "markdown", "id": "aa34039e", "metadata": {}, "source": [ "### compute the training accuracy of the classifier" ] }, { "cell_type": "markdown", "id": "c5f462d2", "metadata": {}, "source": [ "
\n", " Compute the accuracy on the training dataset using the function testAccuracy() defined above.\n", "
" ] }, { "cell_type": "markdown", "id": "3eb63d67", "metadata": {}, "source": [ "### load test dataset and evaluate classifier" ] }, { "cell_type": "markdown", "id": "3451b503", "metadata": {}, "source": [ "
\n", " 1. Load the test dataset from the file \"s2_testing_data.npz\".
\n", " 2. Compute features for it as well (remember to compute the logarithm of the data first) and evaluate the classifier on the test dataset by testing it's accuracy.
\n", " 3. Optional: try out the training accuracy for 16, 32, and 256 principal components. What is the test accuracy for those? How long does training/inference take (roughly)?\n", "
" ] }, { "cell_type": "markdown", "id": "51f52097", "metadata": {}, "source": [ "### classify pixels in application dataset" ] }, { "cell_type": "markdown", "id": "1004d454", "metadata": {}, "source": [ "
\n", " 1. Load the image s2_application_data.npz and plot using show_raw_image().
\n", " Have a look at it: can you spot the forest, urban, field, and water regions?
\n", "
\n", " 2. Compute features on the training dataset with 64 components, and train SVM classifier with these features.
\n", "
\n", " 3. Classify the image pixels into the four semantic classes (Forest, Field, Urban, Water):
\n", "
\n", " Use a \"sliding window\" approach where you crop a window of 15x15 pixels from the source image, that you will use to infer the label of the central pixel. To do so, compute the crop features, and use these to \"predict\" the pixel class with your SVM classifier. Store the predicted pixel value in an array \"application_labels\" (shape = (application_X.shape[1]-15, application_X.shape[2]-15)). Then shift the crop by one pixel and repeat these steps in order to classify the next pixel. Continue sliding the crop across the entire image in order to classify the entire image.
\n", "Note: compute_features expects an array of crops instead of a single crop which means that you need to turn your crop into an array containing just one crop.
\n", "
\n", " 4. Render the final label map with: plt.imshow(application_labels).
\n", " Is the classifier able to correctly label the different regions (forest, urban, field, water) you spotted in the image?
\n", " \n", "
" ] } ], "metadata": { "kernelspec": { "display_name": "base", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": { "height": "calc(100% - 180px)", "left": "10px", "top": "150px", "width": "282.883px" }, "toc_section_display": true, "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 5 }