#!/usr/bin/env python # coding: utf-8 # # Домашняя работа №2 # Шестаков А.В. Майнор по анализу данных 2016 # # **Общая информация** # # **Срок сдачи:** 16 февраля 2016, 23:59 # **Штраф за опоздание:** -0.5 за каждый день # # При отправлении ДЗ на почту указывайте фамилию в названии файла, а тему письма оформляйте в следующем виде: # ** [Майнор ИАД 2016] *{Фамилия}* *{Имя}* ДЗ*{Номер}* ** # # # Сопровождайте ваш код изображеними, комментариями и выводами. # Иммейте ввиду, что на некоторые задачи нет единственного верного и полного ответа. Чем больше информации вы сможете извлечь, аргументированных выводов сформулировать, тем лучше. # # Используйте данный Ipython Notebook при оформлении домашнего задания. # # ## 1. Метод главных компонент при работе с изображениями # Скачайте небольшую [базу](http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html) изображений лиц. В ней содержится по 10 изображений на каждого из 40 субъектов. # # Функция `read_pgm` загружает данные из файла формата pgm в numpy.array размера $112 \times 92$. Значения в этом массиве лежат в интервале $[0, 255]$, значение $0$ соответствует черному цвету, а значение $255$ - белому. # 256 Shades of Grey... # In[ ]: import re import numpy as np import os import matplotlib.pyplot as plt get_ipython().run_line_magic('matplotlib', 'inline') # In[ ]: def read_pgm(filename, byteorder='>'): ''' Return image data from a raw PGM file as numpy array. Format specification: http://netpbm.sourceforge.net/doc/pgm.html ''' with open(filename, 'rb') as f: buffer = f.read() try: header, width, height, maxval = re.search( b"(^P5\s(?:\s*#.*[\r\n])*" b"(\d+)\s(?:\s*#.*[\r\n])*" b"(\d+)\s(?:\s*#.*[\r\n])*" b"(\d+)\s(?:\s*#.*[\r\n]\s)*)", buffer).groups() except AttributeError: raise ValueError("Not a raw PGM file: '%s'" % filename) return np.frombuffer(buffer, dtype='u1' if int(maxval) < 256 else byteorder+'u2', count=int(width)*int(height), offset=len(header) ).reshape((int(height), int(width))) # In[18]: image = read_pgm('att_faces/s1/1.pgm', byteorder='<') image.flags.writeable = True plt.imshow(image, plt.cm.gray) # **Задача 1.** Импортируйте изображения всех 40 субъектов. В результате выполнения этой задачи вы должны получить # # * Матрицу $X$ размера $400 \times 10304,$ $(10304 = 112 \cdot 92)$ # * Массив $y$ длинны $400$ с идентификаторами субъектов от $1$ до $40$ # In[ ]: X = np.empty((400, 10304)) y = np.empty((400, )) att_faces_dir = './att_faces' i = 0 for folder in os.listdir(att_faces_dir): subject_dir = os.path.join(att_faces_dir, folder) if os.path.isdir(subject_dir): for pgm in os.listdir(subject_dir): # Your code here # **Задача 2.** Изобразите "усредненный" портрет субъекта по всей базе # In[ ]: # Your code here # **Задача 3.** Разделите выборку на 2 группы в пропорции 80/20 (должно получиться 320 и 80 изображений): # # * Галерея: часть набора изображений, для которого известен идентификатор субъекта # * Проба: часть набора изображений, для которого необходимо будет определить идентификатор субъекта # # Используйте метод `np.random.choice()`. Сэплирование необходимо произвести без возрата! # In[ ]: # Your code here # **Задача 4.** Идентификация "в лоб" # # Выберите меру расстояния и помощью метода `scipy.spatial.distance.cdist()` посчитайте расстояние между всеми парами изображений галерея-проба. # # Для каждлого изображения из пробы, определите какому субъекту принадлежит ближайшая картинка из галереи. Используйте метод `np.argmin()`. Оцените ошибку идентификаии. # In[ ]: from scipy.spatial import distance # In[ ]: # Your code here # **Задача 4.** Метод главных компонент # # Примените метод главных компонент к набору данных из галереи (Сохраните массивы средних - они вам еще приходятся). # # Определите, сколько компонент достаточно для достижения того же (или лучшего) качаства идентификации. # In[ ]: # Your code here # **Задача 5.** Разложение лица по компонентам # # Мы уже знаем, что для любой матрицы можно расчитать сингулярное разложение: # $$ A = U \Sigma V^\top .$$ (Кстати, проверьте, что `A = u.dot(Sigma).dot(v)`) # # Выполним "разложение" изображения по перым $k$ главным компонентам. Это значит, что надо расчитать матрицу # $$ A' = U \Sigma^{(k)} V^\top ,$$ # где матрица $\Sigma^{(k)}$ получилась как матрица $\Sigma$, в которой все значения, кроме $k$ первых строк заменили на 0. # # Выберите лицо и разложите его на $k=10, 20, 50, 100$ компонент. Изобразите оригинальное изображение и результаты разложения. # In[ ]: # Your code here # ## 2. Метод градиентного спуска # Напомним суть метода градиентого спуска в контексте задачи линейной регрессии. # # Дано описание $n$ объектов по $m$ признакам. Обычно оно выражается в виде матрицы размера $n \times m$: $X = [x^{(i)}_j]^{i=1\dots n}_{j=1\dots m} $. ($x^{(i)}_j$ означает $j$-ый признак $i$-го объекта) # Дана зависимая переменная, которая тоже имеет отношение к этим объекам: $y$ - вектор длины $n$. # # Наша задача, выявить **линейную** зависимость между признаками в $X$ и значениями в $y$: # $$\hat{y} = X\beta \quad \Leftrightarrow \quad \hat{y}^{(i)} = \beta_0 + \beta_1x^{(i)}_1 + \dots$$ # # И сделать это так, чтобы квадрат суммы ошибок наших оценок был минимален: # $$ L(\beta) = \frac{1}{2n}(\hat{y} - y)^{\top}(\hat{y} - y) = \frac{1}{2n}(X\beta - y)^{\top}(X\beta - y) \rightarrow \min$$ $$ \Updownarrow $$ $$ L(\beta_0,\beta_1,\dots) = \frac{1}{2n}\sum^{n}_{i=1}(\hat{y}^{(i)} - y^{(i)})^2 = \frac{1}{2n}\sum^{n}_{i=1}(\beta_0 + \beta_1x^{(i)}_1 + \dots - y^{(i)})^2 \rightarrow \min $$ # # Значение в $X$ и $y$ нам даны. Нам неизвестны только значения коэффициентов $\beta$. Соответственно, нужно найти такие значения $\beta$, что функция $L(\beta) \rightarrow \min.$ # На семинаре мы выяснили, чему равен градиент функции потерь $L(\beta_0, \beta_1):$ # $$ \frac{\partial L}{\partial \beta_0} = \frac{1}{n}\sum^{n}_{i=1}(\beta_0 + \beta_1x^{(i)}_1 - y^{(i)})$$ # $$ \frac{\partial L}{\partial \beta_1} = \frac{1}{n}\sum^{n}_{i=1}(\beta_0 + \beta_1x^{(i)}_1 - y^{(i)})x_1^{(i)}$$ # # Иногда проще это записать в виде матриц: # $$ \frac{\partial L}{\partial \beta} = X^\top(X\beta - y)$$ # # Метод градиентного спуска заключается в итеративном и **одновременном(!!!)** обновлении значений $\beta$ в направлении, противоположному градиенту: # $$ \beta := \beta - \alpha\frac{\partial L}{\partial \beta}$$ # **Задача 1:** Загрузите [данные](http://bit.ly/1gIQs6C) по характеристикам автомобилей Honda Accord. Названия столбцов говорят сами за себя. # # Составьте матрицу $X$, состоящую из единичного столбца и признака "пробег". # Составьте вектор $y$ состоящий из стоимости автомобиля. # # Если для импорта вы используете `pandas`, то через .values из DataFrame можно получить numpy array. # In[ ]: # Your code here # **Задача 2:** Изобразите функционал квадратичной ошибки $L(\beta_0, \beta_1)$ в 3D и его линии уровня # In[ ]: # Your code here # **Задача 3:** Напишите код, реализующий метод градиентного спуска. На вход метод должен принимать исходные данные, максимальное кол-во итераций и коэффициент скорости спуска. # In[ ]: # Your code here # **Задача 4:** Выведите полученные значения коэфициентов $\beta$. Как они интерпретируются? Изобразите на одном графике $[y - \text{"пробег"}]$ точки и полученную прямую. # In[ ]: # Your code here