P01

Практичне заняття 1: Налаштування середовища та математичний апарат

  • Курс: Проблеми штучного інтелекту
  • Тиждень: 1
  • Спирається на: Лекція 1
  • Тривалість: 2 академічні години
  • Тип заняття: практична робота під наглядом викладача

Python, NumPy, PyTorch · операції з матрицями й тензорами · автоматичне диференціювання як інструмент


Структура заняття

Блок Час Що відбувається
Організаційний блок 10 хв репозиторій, перевірка середовища, порядок здачі
Завдання 1-2 25 хв масиви й операції у NumPy
Завдання 3 15 хв тензори PyTorch, пристрої, спільна пам'ять
Завдання 4 20 хв автоматичне диференціювання
Завдання 5 10 хв емпіричний ризик і три способи взяти градієнт
git commit і git push 10 хв обов'язкова здача напрацьованого

Це заняття суто інструментальне: воно готує середовище й навички, на які спираються всі наступні практичні. Теорію зворотного поширення похибки тут не розглядаємо, вона належить Лекціям 2 і 5.

Завдання 5 підсумовує заняття й прив'язує його до формалізму Лекції 1. Якщо не встигаєте в аудиторії, завершуйте вдома до дедлайну здачі, це не штрафується.


Результати навчання

Після завершення заняття студент зможе:

  • Відтворити робоче середовище курсу й підтвердити його працездатність відтворюваною перевіркою.
  • Виконувати операції з векторами, матрицями й тензорами у NumPy, свідомо розрізняючи поелементне множення й матричний добуток.
  • Пояснювати правила трансляції розмірностей (broadcasting) і передбачати форму результату до запуску коду.
  • Переносити дані між NumPy і PyTorch, розуміючи, коли масив і тензор поділяють спільну пам'ять.
  • Обчислювати градієнти засобами автоматичного диференціювання й перевіряти їх скінченними різницями.
  • Записати емпіричний ризик простої моделі й обчислити його градієнт аналітично, чисельно та через autograd, отримавши збіжні результати.

Підготовка до заняття

Виконайте до початку заняття: аудиторного часу на встановлення не передбачено.

  1. Python 3.10 або новіший. Перевірте: python3 --version.

  2. Віртуальне середовище й пакети. З кореня вашого репозиторію:

    python3 -m venv .venv
    source .venv/bin/activate          # Windows: .venv\Scripts\activate
    pip install numpy torch matplotlib jupyter
    

    PyTorch із підтримкою GPU встановлюється окремою командою під вашу платформу: візьміть її на pytorch.org/get-started. Підтримка GPU для цього заняття не обов'язкова, але знадобиться з Практичного заняття 6.

  3. Репозиторій. Ви отримаєте запрошення до репозиторію practices-<ваш логін пошти НаУКМА>. Прийміть його й склонуйте репозиторій. Створіть теку P01/.

  4. Повторіть Лекцію 1, зокрема формальну постановку задачі навчання: ризик, емпіричний ризик, функція втрат. Завдання 5 спирається саме на неї.

Якщо запрошення до репозиторію не надійшло, напишіть викладачу практичних до заняття, а не під час нього.


Завдання

Усі файли створюються у теці P01/ вашого репозиторію й нумеруються за порядком: 01_, 02_ і так далі.


1. Перевірка середовища (10 хв)

Файл: P01/01_env_check.py

Напишіть скрипт, який друкує:

  • версію Python, NumPy і PyTorch;
  • доступний обчислювальний пристрій: cuda, mps або cpu;
  • результат найпростішої тензорної операції на цьому пристрої, щоб підтвердити, що він справді працює.

Пристрій визначайте явно, а не припускайте:

import torch

device = (
    "cuda" if torch.cuda.is_available()
    else "mps" if torch.backends.mps.is_available()
    else "cpu"
)

Зафіксуйте зерно генератора випадкових чисел (numpy.random.default_rng(0), torch.manual_seed(0)) і поясніть у коментарі, чому відтворюваність важлива для порівняння результатів між запусками.


2. Вектори, матриці та операції NumPy (15 хв)

Файл: P01/02_numpy_basics.py

  1. Створіть матрицю A розміру 4×3 і матрицю B розміру 3×5 з випадковими числами.
  2. Обчисліть матричний добуток A @ B. Перед запуском запишіть у коментарі очікувану форму результату, потім перевірте.
  3. Покажіть на власному прикладі різницю між A * A і A @ A.T: що означає кожна операція й чому форми результатів різні.
  4. Обчисліть середнє значення матриці A трьома способами: по всій матриці, по рядках і по стовпцях. Поясніть у коментарі, що саме робить аргумент axis.
  5. Пастка трансляції. Візьміть вектор v довжини 3 і вектор w довжини 4. Спробуйте A + v і A + w. Один вираз спрацює, другий викине помилку. Поясніть обидва результати через правила трансляції розмірностей, а не через текст повідомлення про помилку.

3. Тензори PyTorch і спільна пам'ять (15 хв)

Файл: P01/03_torch_tensors.py

  1. Перетворіть масив NumPy на тензор двома способами: torch.from_numpy(arr) і torch.tensor(arr).
  2. Змініть один елемент вихідного масиву NumPy. Надрукуйте обидва тензори.
  3. Поясніть спостережену різницю у коментарі. Один зі способів створює тензор, що поділяє пам'ять із масивом, другий копіює дані. Визначте, який саме, і сформулюйте, коли ця різниця може призвести до помилки в реальному коді.
  4. Перенесіть тензор на доступний пристрій через .to(device) і назад на cpu. Спробуйте виконати операцію між тензором на пристрої й тензором на cpu; зафіксуйте, що станеться.
  5. Покажіть різницю між float32 і float64: створіть той самий тензор обох типів, порівняйте element_size() і результат ділення, де проявляється похибка округлення.

Типовий тип у PyTorch це float32, а у NumPy float64. Мовчазне перетворення між ними стає джерелом розбіжностей у результатах, тому тип варто задавати явно.


4. Автоматичне диференціювання (20 хв)

Файл: P01/04_autograd.py

На цьому кроці autograd цікавить нас як інструмент: що саме він обчислює й як переконатися, що обчислює правильно. Механізм зворотного поширення розбирається на Лекціях 2 і 5.

  1. Створіть скалярний тензор x зі значенням 2.0 і requires_grad=True.

  2. Обчисліть y = x**3 + 5*x, викличте y.backward(), надрукуйте x.grad.

  3. Виведіть похідну аналітично на папері й запишіть її в коментарі. Порівняйте з отриманим значенням.

  4. Повторіть для функції двох змінних, наприклад f(x, y) = x**2 * y + sin(y), і перевірте обидві часткові похідні.

  5. Перевірка скінченними різницями. Реалізуйте функцію

    def numeric_grad(f, x, eps=1e-5):
        return (f(x + eps) - f(x - eps)) / (2 * eps)
    

    і порівняйте її результат із x.grad. Підберіть eps так, щоб розбіжність була найменшою, і поясніть у коментарі, чому надто мале eps погіршує результат.

  6. Загорніть обчислення у with torch.no_grad(): і покажіть, що градієнт більше не накопичується. Поясніть, навіщо цей режим потрібен.

Градієнти у PyTorch накопичуються: другий виклик backward() додасться до наявного x.grad. Перед новим обчисленням викликайте x.grad = None або x.grad.zero_(). Це джерело помилок, які не падають, а тихо дають неправильні числа.


5. Емпіричний ризик і три способи взяти градієнт (10 хв)

Файл: P01/05_empirical_risk.py

Це завдання прив'язує інструменти заняття до формалізму Лекції 1.

Візьміть лінійну модель з одним параметром, h(x) = w·x, і квадратичну функцію втрат. Емпіричний ризик на вибірці з n точок:

  1. Згенеруйте 50 точок за правилом y = 3x + ε, де ε це невеликий гаусів шум.
  2. Обчисліть у точці w = 0.5 трьома способами й переконайтеся, що вони збігаються:
    • явним циклом по точках;
    • векторизованою операцією NumPy без циклу;
    • тензорною операцією PyTorch.
  3. Обчисліть у тій самій точці трьома способами:
    • аналітично (виведіть формулу самостійно й запишіть її в коментарі);
    • скінченними різницями з попереднього завдання;
    • через backward().
  4. Надрукуйте всі три значення поруч і зафіксуйте розбіжність між ними.
  5. Побудуйте графік для w від 0 до 6 і позначте на ньому точку мінімуму. Збережіть як P01/risk_curve.png.

Питання для роздумів (відповіді у P01/README.md, по кілька речень на кожне):

  • Чому векторизована реалізація швидша за цикл, хоча виконує ту саму кількість арифметичних операцій?
  • Три оцінки градієнта дали різні числа. Яка з них точна за побудовою, яка наближена принципово через сам метод, і яка математично точна, але обмежена розрядністю чисел? Найважливіше: автоматичне диференціювання не є чисельним, поясніть, чим воно відрізняється від скінченних різниць.
  • Градієнт у точці w = 0.5 виявився від'ємним. Що це говорить про напрям, у якому треба змінювати w, щоб зменшити ризик, і чому знак саме такий?

Домашнє завдання та відео

Дедлайн: за 24 години до початку Практичного заняття 2 за вашим розкладом.

  1. Завершіть завдання, які не встигли в аудиторії (зазвичай це завдання 5).
  2. Запишіть Loom-відео до 5 хвилин і покладіть посилання на нього у P01/video.txt.

Що має бути на відео

Відео підтверджує, що код написали й розумієте ви. П'ять хвилин це мало, тому показуйте головне, а не все підряд.

  • Запуск. Коротко покажіть, що 01_env_check.py і 05_empirical_risk.py справді працюють, разом із графіком ризику.
  • Пастка трансляції (завдання 2). Поясніть, чому A + v спрацював, а A + w ні. Обґрунтуйте правилами трансляції розмірностей.
  • Спільна пам'ять (завдання 3). Покажіть різницю між двома способами створення тензора й назвіть ситуацію, у якій вона призведе до помилки.
  • Автоматичне диференціювання (завдання 4). Назвіть значення, яке дав backward(), і вашу аналітичну похідну. Поясніть, чим автоматичне диференціювання відрізняється від скінченних різниць.
  • Знак градієнта (завдання 5). Скажіть, у який бік треба змінювати w, щоб зменшити ризик, і чому знак саме такий.

Вимоги до запису

  • Ваш голос і екран. Обличчя не обов'язкове.
  • Українською.
  • До 5 хвилин. Після шостої хвилини відео не переглядається.
  • Посилання відкривається без авторизації: перевірте його в режимі анонімного перегляду браузера.

Пояснення, а не переказ. Зачитування коментарів із коду вголос не є поясненням. На відео має звучати причина: чому результат саме такий, а не лише який він. Робочий код без розуміння на відео прирівнюється до невиконаної роботи, як того вимагає розділ силабуса про використання інструментів ШІ.


Здача

  1. Усі файли лежать у теці P01/ вашого репозиторію practices-<логін>.
  2. P01/README.md містить відповіді на питання для роздумів і перелік того, що не вдалося завершити, якщо таке є.
  3. P01/video.txt містить посилання на Loom-відео.
git add P01/
git commit -m "P01: середовище, NumPy, PyTorch, autograd"
git push

Незавершена робота, здана вчасно з переліком того, що не вийшло, оцінюється вище за мовчазну відсутність файлів.

Запізнення. Кожна розпочата доба після дедлайну знижує оцінку за заняття на 25%. Через три доби робота не приймається без попереднього узгодження. Узгоджувати перенесення треба до дедлайну, а не після нього.


Критерії оцінювання

Складова Вага
Участь у занятті та коміт наприкінці пари 15%
Завдання 1-3: середовище, NumPy, тензори PyTorch 20%
Завдання 4: autograd і перевірка скінченними різницями 20%
Завдання 5: емпіричний ризик і три способи взяти градієнт 20%
Пояснення в коментарях і відповіді в README.md 10%
Пояснення й демонстрація у Loom-відео (до 5 хв) 15%
Разом 100%

Пояснення оцінюються нарівні з кодом. Робочий код без коментаря, що показує розуміння, отримує неповний бал: на захисті потрібно вміти пояснити кожен результат.

Відсутнє відео коштує більше за власні 15%. Решта складових оцінюється за тим, що викладач бачить у репозиторії, і без вашого пояснення сумнівні місця тлумачаться не на вашу користь.

За силабусом усі 16 практичних занять разом складають 40% підсумкової оцінки.


Що далі

Практичне заняття 2 реалізує градієнтний спуск та його варіації «з нуля». Завдання 5 цього заняття дає йому вихідну точку: там ви обчислили градієнт емпіричного ризику в одній точці, далі ви побудуєте з цього ітеративний метод і порівняєте траєкторії збіжності.