Введение в анализ данных¶
Домашнее задание 5. Компьютерное зрение & генеративные модели¶
Правила, прочитайте внимательно:
- Выполненную работу нужно отправить телеграм-боту
@thetahat_ds25_bot
. Для начала работы с ботом каждый раз отправляйте/start
. Дождитесь подтверждения от бота, что он принял файл. Если подтверждения нет, то что-то не так. Работы, присланные иным способом, не принимаются. - Дедлайн см. в боте. После дедлайна работы не принимаются кроме случаев наличия уважительной причины.
- Прислать нужно ноутбук в формате
ipynb
. Если вы строите интерактивные графики, их стоит прислать в формате html. - Следите за размером файлов. Бот не может принимать файлы весом более 20 Мб. Если файл получается больше, заранее разделите его на несколько.
- Выполнять задание необходимо полностью самостоятельно. При обнаружении списывания всем участникам списывания дается штраф -2 балла к итоговой оценке за семестр.
- Решения, размещенные на каких-либо интернет-ресурсах, не принимаются. Кроме того, публикация решения в открытом доступе может быть приравнена к предоставлении возможности списать.
- Обратите внимание на правила использования ИИ-инструментов при решении домашнего задания.
- Код из рассказанных на занятиях ноутбуков можно использовать без ограничений.
- Для выполнения задания используйте этот ноутбук в качестве основы, ничего не удаляя из него. Можно добавлять необходимое количество ячеек.
- Комментарии к решению пишите в markdown-ячейках.
- Выполнение задания (ход решения, выводы и пр.) должно быть осуществлено на русском языке.
- Решение проверяется системой ИИ-проверки
ThetaGrader. Результат проверки валидируется и исправляется человеком, после чего комментарии отправляются студентам.
- Если код будет не понятен проверяющему, оценка может быть снижена.
- Никакой код из данного задания при проверке запускаться не будет. Если код студента не выполнен, недописан и т.д., то он не оценивается.
- Код из рассказанных на занятиях ноутбуков можно использовать без ограничений.
Важно!!! Правила заполнения ноутбука:
- Запрещается удалять имеющиеся в ноутбуке ячейки, менять местами положения задач.
- Сохраняйте естественный линейный порядок повествования в ноутбуке сверху-вниз.
- Отвечайте на вопросы, а также добавляйте новые ячейки в предложенных местах, которые обозначены
<...>
. - В markdown-ячейка, содержащих описание задачи, находятся специальные отметки, которые запрещается модифицировать.
- При нарушении данных правил работа может получить 0 баллов.
Баллы за задание:
- Задача 1 — 120 баллов
- Задача 2 — 80 баллов
- Задача 3 — 30 баллов
Баллы учитываются в факультативной части курса и не влияют на оценку по основной части.
# Bot check
# HW_ID: fpmi_ad5
# Бот проверит этот ID и предупредит, если случайно сдать что-то не то.
# Status: not final
# Перед отправкой в финальном решении удали "not" в строчке выше.
# Так бот проверит, что ты отправляешь финальную версию, а не промежуточную.
# Никакие значения в этой ячейке не влияют на факт сдачи работы.
# При необходимости установите библиотеки, например, раскомментируйте строку ниже
# !pip install torchinfo
import warnings
from typing import Union
import seaborn as sns
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
from torchvision import transforms
sns.set(font_scale=1, style="darkgrid", palette="Set2")
warnings.simplefilter("ignore")
device = "cuda" if torch.cuda.is_available() else "cpu"
print(device)
Перед выполнением задания обязательно посмотрите презентацию и ноутбук про сверточные сети и классификацию, а так же презентацию и ноутбук про перенос стиля и генеративные сети.
❗ Весь код работы с библиотекой PyTorch необходимо написать самостоятельно, без использования ИИ-инструментов. Но можно использовать код из ноутбуков, рассказанных на занятии. Можно использовать ИИ-инструменты для написания технического кода (например, построение графиков), оформления ранее написанного кода и в качестве справки. Выводы необходимо делать самостоятельно.
Задача 1. Классификация MNIST¶
В данной задаче вам нужно провести сравнительный анализ сверточных нейросетей с различными параметрами на датасета рукописных цифр MNIST. С этим датасетом вы уже познакомились в предыдущем задании. Классификация в MNIST значительно проще, чем в CIFAR, рассмотренном на занятии, поэтому ваша задача — достичь на валидации хотя бы одной из моделей точности 97%. Вы можете свободно использовать код с занятия.
Использования слоев с семинара (свертка, pooling) более чем достаточно для достижения 97% точности на тесте. Также не делайте сеть глубокой.
Тестируйте работоспособность кода на CPU с небольшим количеством итераций. Если все работает, и хочется ускорить процесс, переходите на GPU.
Следуйте указаниям ниже.
Загрузим датаcет из torchvision.datasets
.
# Данные для обучения
train_dataset = torchvision.datasets.MNIST(
root="./data", train=True, download=True, transform=transforms.ToTensor()
)
# Данные для тестирования
val_dataset = torchvision.datasets.MNIST(
root="./data", train=False, download=True, transform=transforms.ToTensor()
)
# Классы объектов в датасете
num_classes = 10
classes_list = [str(i) for i in range(num_classes)]
Визуализируйте несколько картинок с соответствующими метками из датасета.
...
Создайте генераторы батчей.
...
Эксперимент 1. Создайте хотя бы 5 сверточных нейросетей с разным количеством линейных и сверточных слоев. Должен присутствовать хотя бы 1 сверточный слой и хотя бы 1 линейный слой. Для каждой посмотрите количество параметров с помощью torchinfo.summary
.
...
Обучите сети, используя функцию потерь nn.CrossEntropyLoss
и оптимизатор torch.optim.SGD
с дефолтными параметрами.
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(simple_cnn.parameters())
...
Постройте график лосса и график accuracy, где сравниваются все модели (на train и на val). Нужная функция есть в семинаре.
...
Сделайте вывод. Как количество разных слоев влияет на качество и время обучения?
Вывод по эксперименту 1:
...
Эксперимент 2. Теперь выберите лучший вариант, зафиксируйте это количество сверточных и линейных слоев и обучите хотя бы 4 сверточных нейросети, варьируя размеры ядер сверток. Например, в разном порядке поставьте ядра 3x3, 5x5.
...
Постройте график лосса и график accuracy, где сравниваются все модели этого эксперимента (на train и на val).
...
Сделайте вывод. Как размеры ядер влияют на качество и время обучения?
Вывод по эксперименту 2:
...
Анализ лучшей модели. Выберите лучшую конфигурацию из всех по accuracy на валидации. Она должна быть не меньше 97%.
...
Проведите еще один проход валидации выбранной моделью по всему датасету. В нем посчитайте точность по каждому классу и соберите информацию о неправильных предсказаниях. Равномерна ли точность по отношению к классам? Покажите 10-20 примеров, на которых нейросеть выдала неправильную метку. Что можно о них сказать?
...
Ответ:
...
Вывод по всей задаче:
...
На первом занятии мы рассматривали классификацию с помощью KNN, который показал высокую точность — 99%. Возникает вопрос: зачем нам изучать более сложные методы, если простой KNN может работать так же хорошо или даже лучше? Но здесь есть обман. В чем он заключается?
Для ответа на вопрос вспомните, с чем мы работали на первом занятии.
...
Задача 2. Визуализиция сверточных слоев¶
Обучите модель, состоящую как минимум из 4 сверточных слоев, на датасете MNIST. Количество выходных каналов в каждом сверточном слое должно быть равно 32, а точность на тестовых данных должна достигать 97%. Для создания модели будет удобно использовать torch.nn.Sequential
.
...
Визуализируйте веса свертки на первом слое. Поскольку веса имеют размерность $(32, 1, K_1, K_2)$, т.к. входное изображение имеет один канал, вам необходимо отобразить 32 изображения (по количеству выходных каналов) фильтрами размера $K_1 \times K_2$.
Совет. Здесь и далее серии из 32 картинок визуализируйте в виде сетки с помощью plt.subplots(4, 8, figsize=...)
. Не забывайте указывать параметр cmap='gray'
.
...
Какую функцию они могут нести? Для ответа на вопрос вспомните фильтры, рассмотренные на семинаре.
...
Для одного произвольного изображения из датасета MNIST визуализируйте выходы всех слоев нейросети, включая активацию и пуллинг, вплоть до операции Flatten
, но не включая её. Каждый выход будет иметь размерность $(32, H_i, W_i)$. Таким образом, для каждого слоя необходимо создать $32$ изображения размером $H_i \times W_i$.
...
Какие выводы можно сделать о том, как работает ваша сверточная сеть?
...
Визуализируйте, какие объекты, подаваемые на вход нейросети, в наибольшей степени активируют нейроны в сверточных слоях. Для этого оптимизируйте изображение, чтобы максимизировать выход нейрона.
Ниже представлен шаблон функции, которая находит изображение, максимально усиливающее реакцию нейрона. Пример можно посмотреть в презентации с занятия.
# При реализации запрещено пользоваться ИИ-инструментами.
def visualize_filter(
model: nn.Module,
layer_index: int,
target_kernel: int,
learning_rate: float = 1,
steps: int = 10_000,
image_size: int = 28,
device: Union[str, torch.device] = "cpu",
) -> torch.Tensor:
"""Визуализирует фильтр сверточного слоя нейронной сети путем оптимизации
входного изображения, которое максимизирует активацию заданного фильтра.
Параметры:
model (nn.Module): Модель нейронной сети, содержащая целевой сверточный слой.
layer_index (int): Индекс целевого сверточного слоя в модели (по порядку в model.children()).
target_kernel (int): Индекс фильтра в целевом слое для визуализации.
learning_rate (float, optional): Скорость обучения для оптимизатора. По умолчанию 1.
steps (int, optional): Количество шагов оптимизации. По умолчанию 10000.
image_size (int, optional): Размер стороны квадратного входного изображения. По умолчанию 28.
device (str|torch.device, optional): Устройство для вычислений ('cpu' или 'cuda'). По умолчанию "cpu".
Возвращает:
torch.Tensor: Оптимизированное изображение (тензор формы [1, C, H, W]),
которое максимизирует активацию целевого фильтра.
"""
model.eval().to(device) # Переводим модель в режим оценки
# Инициализируем изображение случайным шумом
input_img = torch.randn(..., requires_grad=True, device=device)
# Обратите внимание, что в данном случае мы оптимизируем не модель, а входную картинку
optimizer = optim.SGD(...)
# Функция потерь: максимизируем активацию нужного ядра свертки
for step in range(steps):
# Пропускаем изображение через модель
output = ... # Выход заданного сверточного слоя
loss = ... # Минимизируемая функция
# Обратное распространение
...
# Ограничиваем значения пикселей в разумных пределах
input_img.data = torch.clamp(input_img.data, -1, 1)
# Логируем лосс
if step % 500 == 0:
print(f"Step {step}/{steps}, Loss: {loss.item():.4f}")
# Преобразуем оптимизированное изображение
img = ...
return img
...
Сделайте выводы о том, как с глубиной слоя меняется способность нейрона видеть различные паттерны на изображении.
...
Задача 3. Перенос стиля¶
Данную задачу, возможно, проще сделать в Google Colab.
В данной задаче вы потренируетесь в работе с картинками и составлением промптов. Используя код с семинара, проведите перенос стиля на хотя бы 3 своих примерах.
Заметьте, что в примерах с семинара в качестве картинок стиля и контента использовались картинки среднего разрешения. Если возникают проблемы, например:
- оптимизация останавливается на 0-й эпохе и не создает картинку;
- loss в какой-то момент стал nan;
- нехватка RAM;
то либо уменьшите разрешение ваших картинок, либо попробуйте картинку полегче.
...
Теперь для каждой пары контекст-стиль попытайтесь сгенерировать картинку с таким контекстом и стилем с помощью диффузионной модели, рассмотренной на семинаре, задав нужный промпт.
...
Вывод:
...