Lecture 1
Introduction to Computer Vision
Что такое CV и где он в AI, история от Hubel & Wiesel до AlexNet, почему deep learning «взорвался» в 2012 и как устроен курс.
Что такое Computer Vision
ОпределениеComputer Vision = building artificial systems that process, perceive, and reason about visual data (изображения, видео).
Deep Learning = hierarchical learning algorithms with many «layers», (very) loosely inspired by the brain. Это часть Machine Learning (systems that learn from data and experience), а ML часть Artificial Intelligence. CV пересекается с ML/DL; рядом NLP, Speech Recognition, Robotics. Этот курс = пересечение CV и Deep Learning.
История: таймлайн
| Год | Что | Почему важно |
| 1958 | Perceptron (Frank Rosenblatt) | Один из первых алгоритмов, обучающихся на данных. Железо: веса в потенциометрах, камера 20×20 = 400 пикселей, распознавал буквы. Сегодня это linear classifier. |
| 1959 | Hubel & Wiesel | Нейроны зрительной коры кошки: simple cells (ориентация света), complex cells (ориентация + движение), hypercomplex (движение с конечной точкой). Иерархия от простого к сложному. |
| 1963 | Larry Roberts | Block world: original picture → differentiated picture (края) → feature points. |
| 1969 | Minsky & Papert | Perceptron не может выучить XOR → разочарование в нейросетях. |
| 1970s | David Marr | Stages of visual representation: input image → primal sketch (edges, blobs, bars) → 2½-D sketch (surface orientation, depth) → 3-D model. |
| 1970s | Recognition via parts | Generalized Cylinders (Brooks & Binford, 1979), Pictorial Structures (Fischler & Elschlager, 1973). |
| 1980 | Neocognitron (Fukushima) | Модель по Hubel & Wiesel: чередование simple cells (≈ convolution) и complex cells (≈ pooling). Похожа на AlexNet, но не было алгоритма обучения. |
| 1986 | Backprop (Rumelhart, Hinton, Williams) | Вычисление градиентов в нейросетях; впервые обучили многослойные перцептроны. |
| 1986 | Canny edge detector | Recognition via edge detection (1980s). Тот самый cv2.Canny. |
| 1997 | Normalized Cuts (Shi & Malik) | Recognition via grouping (1990s), сегментация. |
| 1998 | LeNet (LeCun et al.) | Backprop + архитектура как у Neocognitron → распознавание рукописных цифр, использовалось NEC для чеков. Очень похоже на современные ConvNets. |
| 1999 | SIFT (David Lowe) | Recognition via matching (2000s): ключевые точки, устойчивые к масштабу и повороту. |
| 2001 | Viola & Jones | Face detection, одно из первых успешных применений ML к зрению. |
| 2000s | PASCAL VOC | Challenge: airplane, train, person… |
| 2006 | «Deep Learning» | Hinton & Salakhutdinov и др. пробуют обучать всё более глубокие сети; ещё не мейнстрим. |
| 2009 | ImageNet (Deng et al.) | 1000 классов, 1 431 167 изображений; Image Classification Challenge. |
| 2012 | AlexNet (Krizhevsky, Sutskever, Hinton) | Deep learning goes mainstream: резкое падение ошибки на ImageNet. |
| 2018 | Turing Award | Yoshua Bengio, Geoffrey Hinton, Yann LeCun. |
Между 1980-ми и 2000-ми был AI Winter.
Почему deep learning взлетел в 2012
Три причиныData (ImageNet, миллионы размеченных изображений) + Computation (GPU: GigaFLOPs per dollar у GPU растут намного быстрее, чем у CPU; AlexNet обучен на GeForce GTX 580) + Algorithms (backprop, ConvNets, ReLU).
2012 – сейчас: ConvNets везде
- Image classification и image retrieval (AlexNet).
- Object detection (Faster R-CNN, Ren et al. 2015) и image segmentation.
- Video classification, activity recognition, pose recognition, игры Atari.
- Image captioning («A cat sitting on a suitcase on the floor»), DeepDream, style transfer (Gatys et al. 2016).
Но CV ещё далёк от человека: сети не понимают контекст и юмор картинки (пример Karpathy с весами). При этом CV улучшает жизнь: медицина, автопилоты, помощь незрячим.
Курс
- Philosophy: thorough and detailed (писать с нуля, отлаживать, обучать сети), practical (PyTorch, TensorFlow), state of the art.
- First half: Fundamentals — fully-connected, convolutional, recurrent networks; как обучать и отлаживать.
- Second half: Applications — detection, segmentation, 3D vision, video, attention / Transformers, vision & language, generative models (GANs, VAEs).
- Optional textbook: Deep Learning by Goodfellow, Bengio, Courville (free online).
Lecture 2
Image Classification
Задача классификации, semantic gap и его причины, data-driven approach, датасеты, Nearest Neighbor и kNN, distance metrics, hyperparameters, train/val/test и cross-validation, curse of dimensionality.
Задача
Image classification: input = image, output = одна метка из фиксированного набора категорий (cat, bird, deer, dog, truck). Core task компьютерного зрения.
Semantic gapЧеловек видит кошку, а компьютер видит большую сетку чисел от 0 до 255, например 800 × 600 × 3 (3 канала RGB). Между пикселями и смыслом «кошка» огромный разрыв.
Challenges (почему это трудно)
- Viewpoint variation
- Камера сдвинулась → все пиксели изменились, а объект тот же.
- Intraclass variation
- Кошки бывают очень разными внутри одного класса.
- Fine-grained categories
- Maine Coon vs Ragdoll vs American Shorthair: классы очень похожи.
- Background clutter
- Объект сливается с фоном.
- Illumination changes
- Свет, тени, ночь меняют пиксели.
- Deformation
- Кошка принимает любые позы.
- Occlusion
- Объект частично закрыт.
Классификатор должен быть invariant ко всему этому. Применения: medical imaging, galaxy classification, whale recognition. Классификация = building block для других задач: object detection (классифицировать регионы: background / horse / person), image captioning (классифицировать следующее слово), игра в Go (классифицировать ход).
Data-driven approach
В отличие от сортировки, алгоритм «кошка» нельзя запрограммировать вручную (искать края и углы не работает). Поэтому:
- Collectдатасет изображений и меток
- Trainклассификатор с помощью ML:
train(images, labels) → model
- Evaluateна новых изображениях:
predict(model, test_images) → labels
Датасеты
| Датасет | Классы | Размер | Изображения |
| MNIST | 10 (цифры 0–9) | 50k train, 10k test | 28×28 grayscale. «Drosophila of CV»: результаты часто не переносятся на сложные данные. |
| CIFAR-10 | 10 | 50k train (5k/класс), 10k test (1k/класс) | 32×32 RGB → 32·32·3 = 3072 чисел. Используется в домашках. |
| CIFAR-100 | 100 (20 superclasses × 5) | 50k train (500/класс), 10k test (100/класс) | 32×32 RGB |
| ImageNet | 1000 | ~1.3M train, 50k val, 100k test (метки test секретны) | Разного размера, обычно resize до 256×256. Метрика: top-5 accuracy (одна из 5 предсказанных меток верна). |
| MIT Places | 365 сцен | ~8M train, 18.25k val, 328.5k test | resize до 256×256 |
| Omniglot | 1623 символа из 50 алфавитов | 20 изображений на класс | для few-shot learning |
Nearest Neighbor
Train: просто запомнить все данные и метки. Predict: найти самое похожее обучающее изображение и вернуть его метку.
L1 (Manhattan) distance
d₁(I₁, I₂) = Σₚ |I₁ᵖ − I₂ᵖ|
Сумма модулей разностей пикселей. Зависит от выбора осей координат.
L2 (Euclidean) distance
d₂(I₁, I₂) = √(Σₚ (I₁ᵖ − I₂ᵖ)²)
Не зависит от поворота осей.
СложностьTrain: O(1). Predict: O(N). Это плохо: медленное обучение терпимо, а предсказание должно быть быстрым. Есть быстрые приближённые методы (например, FAISS).
Decision boundary = граница между областями классов. У 1-NN она шумная и зависит от outliers.
k-Nearest Neighbors
Вместо метки одного ближайшего соседа берём majority vote из K ближайших. Больше K → глаже границы, меньше влияние outliers. При K > 1 возможны ничьи, их надо как-то разрешать. С подходящей метрикой kNN работает с любыми данными (например, сравнение статей по tf-idf).
Hyperparameters
K и distance metric — hyperparameters: выбираются до обучения и не выучиваются из данных. Зависят от задачи, надо пробовать.
| Идея | Вердикт |
| #1 Выбрать то, что лучше всего на всех данных | BAD: K = 1 всегда идеален на train. |
| #2 Split train / test, выбрать лучшее на test | BAD: не знаем, как модель поведёт себя на новых данных (test «подсмотрен»). |
| #3 Split train / validation / test: выбираем на val, оцениваем на test | Better! |
| #4 Cross-validation: делим на folds, каждый fold по очереди validation, усредняем | Полезно для маленьких датасетов, в deep learning используется редко (дорого). |
Главное правилоHyperparameters выбирать на validation set; запускать на test set только один раз в самом конце.
Пример 5-fold cross-validation для k: каждая точка = один fold, линия через среднее, бары = std; лучший k ≈ 7.
Universal approximation и curse of dimensionality
При N → ∞ nearest neighbor может представить любую(*) функцию. Но curse of dimensionality: для равномерного покрытия пространства нужно экспоненциально много точек: 4 точки в 1D, 4² в 2D, 4³ в 3D. Число бинарных изображений 32×32: 2^(32·32) ≈ 10³⁰⁸, а элементарных частиц во Вселенной ≈ 10⁹⁷.
Почему kNN на пикселях почти не используют
- Очень медленно на test time.
- Distance metrics на пикселях неинформативны: boxed, shifted и tinted версии одной картинки имеют одинаковое L2 до оригинала.
- Зато kNN на ConvNet features работает хорошо (например, image captioning через ближайших соседей).
Lecture 3
Linear Classifiers
Score и sign, геометрия w и b, perceptron, logistic regression, SVM, LDA, multiclass (one-vs-rest, softmax), loss functions (SVM, cross-entropy, MSE/MAE/Huber), регуляризация, метрики и feature maps.
Одна идея на всю лекциюEvery model computes w·x + b — only the loss changes.
Score, sign, hyperplane
Input: feature vector x. Output: метка y из фиксированного набора. Linear classifier принимает решение одной взвешенной суммой признаков.
Binaryf(x) = w·x + b = w₁x₁ + w₂x₂ + … + b, ŷ = sign(f(x)) ∈ {−1, +1}. Граница = множество, где f(x) = 0.
- w — weights
- Насколько важен каждый признак и в какую сторону он тянет решение. w перпендикулярен границе и указывает в сторону класса +1.
- b — bias
- Сдвигает границу от начала координат (порог). Без b граница всегда проходит через 0.
- f(x) — score
- Знак даёт класс, модуль намекает на уверенность.
- Distance
- От x до границы:
|w·x + b| / ‖w‖. Умножение w и b на одну константу границу не двигает.
В 2D граница = прямая, в 3D = плоскость, в d измерениях = hyperplane. Learning = выбор, где провести линию.
Пример: сдаст ли студент
x₁ = часы учёбы в день, x₂ = пропуски в неделю, w = (0.8, −0.5), b = −1, ‖w‖ = √0.89 ≈ 0.943.
| Студент | x | w·x + b | Класс | Distance |
| Aigerim | (3, 2) | 0.8·3 − 0.5·2 − 1 = 0.4 | +1 pass | 0.4 / 0.943 = 0.42 |
| Daniyar | (1, 2) | 0.8·1 − 0.5·2 − 1 = −1.2 | −1 fail | 1.27 |
Linearly separable: существует линия, которая правильно делит все точки. Если граница на самом деле круг или XOR, любая прямая ошибается.
Multiclass: s = Wx + b
Для K классов: W имеет размер K × D (по строке на класс), b = K чисел, s = K scores. Predicted class = argmax(s). Для CIFAR-10: x = 3072, W = 10 × 3072, b = 10.
s =·+→ sᵢ = wᵢ₀x₀ + wᵢ₁x₁ + bᵢ
- Algebraic view: каждая строка W = веса одного класса; score класса = скалярное произведение строки на x плюс bias.
- Visual view (templates): каждая строка W, развёрнутая в картинку 32×32×3, = template класса; score = насколько x похож на шаблон. Один шаблон на класс → «двухголовая лошадь».
- Geometric view: каждый класс отделён гиперплоскостью; граница между i и j:
(wᵢ − wⱼ)·x + (bᵢ − bⱼ) = 0.
One-vs-rest: K бинарных классификаторов «класс k против остальных», ŷ = argmaxₖ(wₖ·x + bₖ). Softmax regression: одна модель, K векторов весов, обучение через cross-entropy, вероятности суммируются в 1.
Perceptron (Rosenblatt, 1958)
- Начать с
w = 0, b = 0, метки y ∈ {−1, +1}.
- Для каждого примера посчитать
yᵢ(w·xᵢ + b).
- Если ≤ 0 (ошибка):
w ← w + η yᵢ xᵢ, b ← b + η yᵢ.
- Повторять проходы, пока проход без ошибок.
Пропущенный positive тянет w к xᵢ, пропущенный negative отталкивает. η = learning rate (часто 1).
| Точка | y | Score | Ошибка? | w после | b после |
| A (2, 3) | +1 | 0 | да (0 ≤ 0) | (2, 3) | 1 |
| B (1, 1) | −1 | 2+3+1 = 6 | да | (1, 2) | 0 |
| C (4, 5) | +1 | 4+10+0 = 14 | нет | (1, 2) | 0 |
| D (3, 1) | −1 | 3+2+0 = 5 | да | (−2, 1) | −1 |
После 10 обновлений 6-й проход без ошибок: w = (−3, 4), b = −4.
- Convergence theorem (Novikoff, 1962): если данные separable с margin γ и ‖x‖ ≤ R, ошибок не больше (R/γ)².
- Limits: не separable → никогда не сойдётся; останавливается на любом разделителе, не лучшем; нет вероятностей; XOR одной линией не разделить (Minsky & Papert, 1969).
Logistic regression
σ(z) = 1 / (1 + e⁻ᶻ), P(y = 1 | x) = σ(w·x + b). Score 0 → probability 0.5: та же гиперплоскость, но читается как вероятность. Метки y ∈ {0, 1}.
Binary cross-entropyL = −(1/n) Σ [yᵢ log pᵢ + (1 − yᵢ) log(1 − pᵢ)]. Для y = 1: p = 0.9 → 0.105, p = 0.5 → 0.693, p = 0.1 → 2.303. Уверенные ошибки стоят дороже всего; функция convex (один глобальный минимум).
Gradient: ∇w L = (1/n) Xᵀ(p − y), ∂L/∂b = mean(p − y). Update: w ← w − η∇w L. «Error × input»: каждый пример добавляет (pᵢ − yᵢ)·xᵢ. В отличие от perceptron, учитываются все примеры, взвешенные по ошибке.
Шаг для Aigerim (y = 1, η = 0.1): z = 0.4, p = σ(0.4) = 0.599, loss = 0.513 → p − y = −0.401 → ∇w = (−1.204, −0.803), ∇b = −0.401 → w = (0.920, −0.420), b = −0.960 → new p = 0.723, loss 0.324.
Breast cancer: 569 опухолей, 30 признаков, StandardScaler + LogisticRegression → 98.2% test accuracy. predict_proba даёт столбцы P(0), P(1). Коэффициенты: e^w = во сколько раз меняются odds при +1 std признака; отрицательный вес толкает к malignant (0); коррелирующие признаки делят вес.
Linear SVM
Из многих разделяющих прямых SVM выбирает ту, у которой самый широкий margin (ширина «улицы» = 2/‖w‖). Hard margin: min ½‖w‖² при yᵢ(w·xᵢ + b) ≥ 1. Границу определяют только support vectors.
Soft margin: min ½‖w‖² + C Σ max(0, 1 − yᵢ(w·xᵢ + b)) (hinge loss). Вне margin (y·f ≥ 1) → 0; внутри margin → маленький штраф, даже если верно; не та сторона → растёт линейно.
Large C
Мало нарушений, узкий margin → риск overfitting.
Small C
Широкий margin, больше нарушений → более гладкая модель.
decision_function даёт сырые scores w·x + b, не вероятности. C = 100 сильнее подгоняется под train и падает на test (0.947 vs 0.974).
LDA и сравнение
LDA: каждый класс Gaussian со своим средним μₖ и общей covariance Σ → по Bayes граница линейна, w = Σ⁻¹(μ₁ − μ₀). Generative (моделирует распределение x в каждом классе, closed form) vs discriminative (logistic regression и SVM моделируют границу напрямую). На breast cancer (5-fold CV): logistic 0.981, SVM 0.967, perceptron 0.963, LDA 0.960, ridge 0.958 — все рисуют гиперплоскость, разница ≈ 2 пункта.
Loss functions
DefinitionLoss говорит, насколько хорош классификатор: low loss = good. L(W) = (1/N) Σ Lᵢ(f(xᵢ, W), yᵢ) + λR(W) = data loss + regularization. Training = поиск W, минимизирующего L(W).
Пример (три комментария студентов; scores, жирный = верный класс):
| A «Great labs» | B «It was okay» | C «Too fast» |
| positive | 2.8 | 2.1 | 0.6 |
| neutral | 1.2 | 1.7 | 1.9 |
| negative | −0.9 | 0.4 | 1.1 |
Multiclass SVM loss (hinge)
Lᵢ = Σ_{j≠yᵢ} max(0, sⱼ − s_{yᵢ} + Δ), обычно Δ = 1. «Верный класс должен быть выше каждого другого хотя бы на margin».
- A: max(0, 1.2 − 2.8 + 1) + max(0, −0.9 − 2.8 + 1) = 0 + 0 = 0
- B: max(0, 2.1 − 1.7 + 1) + max(0, 0.4 − 1.7 + 1) = 1.4 + 0 = 1.4
- C: max(0, 0.6 − 1.1 + 1) + max(0, 1.9 − 1.1 + 1) = 0.5 + 1.8 = 2.3
- L = (0 + 1.4 + 2.3) / 3 = 1.23
Вопросы: min/max = 0 и ∞; все scores ≈ 0 → L ≈ C − 1 (проверка на баги); сумма по всем классам → +Δ, тот же минимум; mean вместо sum → масштаб, тот же минимум; квадраты → другая функция (squared hinge); W с L = 0 не уникален (2W тоже даёт 0, регуляризация выбирает).
Softmax и cross-entropy
P(Y = k | X = xᵢ) = e^{sₖ} / Σⱼ e^{sⱼ}. Scores (logits) → exp (положительные) → normalize (сумма 1). A: e^2.8 = 16.445, e^1.2 = 3.320, e^−0.9 = 0.407, сумма 20.171 → 0.815, 0.165, 0.020.
Lᵢ = −log P(Y = yᵢ | X = xᵢ): A 0.204, B 1.017, C 1.343, mean 0.855. Min 0, max ∞. При scores ≈ 0: P = 1/C, L = log C (3 класса → 1.099, 10 → 2.303) — sanity check перед обучением.
SVM loss
Доволен, как только margin выполнен; [5, 2, 1], [5, 3.9, 3.9] и [5, −5, −5] все дают 0.
Cross-entropy
Никогда не удовлетворён полностью: 0.066, 0.510, 0.000; всегда хочет увеличить отрыв верного класса.
Numerical stability: e¹⁰⁰⁰ = ∞ → nan. Вычесть max: softmax(s) = softmax(s − max s); для loss log-sum-exp. Градиент по scores: CE: ∂L/∂sⱼ = pⱼ − 1[j = yᵢ]; SVM: +1 каждому неверному классу с положительным членом, верному −(их число). Дальше ∂L/∂W = (∂L/∂s) xᵀ.
Почему не squared error для классификации: через sigmoid при p = 0.01 и y = 1 градиент MSE ≈ 0.020, у CE = 0.990 (в 50 раз сильнее); MSE через sigmoid не convex.
Regression и imbalanced
MSE r² (большие ошибки доминируют), MAE |r| (robust), Huber (квадратичный около 0, линейный дальше). Residuals (0.5, −1, 0.2, 8): MSE 16.32 (98% от outlier), MAE 2.43, Huber 2.04. Для дисбаланса: weighted CE (w_c = n / (K·n_c), class_weight="balanced") и focal loss −(1 − p)^γ log p.
| Ситуация | Loss |
| Binary, нужны вероятности | Log-loss (BCE), LogisticRegression |
| Binary, max margin | Hinge / squared hinge, LinearSVC |
| Multiclass | Softmax cross-entropy |
| Imbalanced | Weighted CE / focal |
| Regression / с outliers | MSE / Huber, MAE |
Default для классификации: cross-entropy.
In practice
- Scale features: без StandardScaler 0.947 и ConvergenceWarning, со scaler 0.982. Scaler fit только на train (pipeline делает это сам).
- Regularization: L2
Σw² уменьшает веса; L1 Σ|w| даёт точные нули (feature selection). В sklearn C = 1/λ: меньше C → сильнее штраф. L1 при C = 0.1 оставляет 7 из 30 признаков.
- Tuning: GridSearchCV с cross-validation; test set трогать один раз в конце.
Evaluation: accuracy is not enough
| Pred malignant | Pred benign |
| True malignant | 40 (TP) | 2 (FN, пропущен рак) |
| True benign | 0 (FP) | 72 (TN) |
Метрикиaccuracy = (TP + TN) / total · precision = TP / (TP + FP) · recall = TP / (TP + FN) · F1 = 2PR / (P + R). Recall (malignant) = 40/42 = 0.952. 98.2% accuracy прячет 2 самые важные ошибки.
ROC AUC использует вероятности и оценивает ранжирование при всех порогах (0.996). Threshold — бизнес-решение: при t = 0.95 ни один рак не пропущен, но accuracy 0.912.
Beyond linear
Feature transforms: φ(x) = (x₁, x₂, x₁², x₁x₂, x₂²). Круг x₁² + x₂² = r² становится гиперплоскостью в φ-пространстве. XOR и circles: plain features 0.50, degree-2 features 1.00 (решает произведение x₀·x₁). Text: TF-IDF → линейная модель: много признаков, быстро, интерпретируемо.
Strengths
- Быстро обучать и предсказывать
- Веса легко объяснить
- Сильный baseline в high dimensions
- Вероятности (logistic)
- Мало hyperparameters (C)
Limits
- Только прямые границы в данных признаках
- Кривые нужно feature engineering
- Чувствительны к масштабу
- Коррелирующие признаки → нестабильные веса
- Perceptron и SVM без вероятностей
Lecture 4.1
Introduction to Artificial Neural Networks
Где останавливается линейный классификатор, нейрон биологический и искусственный, слои, двухслойная сеть на CIFAR-10, зачем нужна нелинейность, activation functions, forward pass на spam-примере, training loop и типы сетей.
Где останавливаются линейные классификаторы
One template per class
Лошадь влево и лошадь вправо делят один шаблон → размытая «двухголовая» лошадь.
Only straight boundaries
Каждый класс отделён гиперплоскостью. XOR и концентрические кольца не разделить.
Biological vs artificial neuron
| Biological | Artificial |
| Dendrites receive signals | Inputs x₁ … xₙ |
| Synapse strength | Weights wᵢ (меняются при обучении) |
| Cell body integrates | Weighted sum Σwᵢxᵢ + b |
| Fires if threshold reached | Activation g(·) |
| Axon sends the spike | Output a → следующий слой |
ANN vs BNN: слои vs дендриты/тело/аксон; алгоритм меняет веса vs опыт меняет синапсы; нужно много размеченных примеров vs справляется с шумными неразмеченными; цифровая, быстрая, на GPU vs электрохимическая, массово параллельная; в основном фиксирована после обучения vs учится постоянно; огромные энергозатраты vs ≈ 20 W. Мозг ≈ 86 млрд нейронов. Neural networks are inspired by the brain. They are not a model of it.
Пять компонентов сети
- Neurons
- Суммируют входы и применяют activation function.
- Connections
- Передают выход нейрона следующему слою.
- Weights & biases
- Обучаемые числа: сила каждой связи.
- Propagation
- Как значения идут вперёд слой за слоем до выхода.
- Learning rule
- Как веса меняются, чтобы уменьшить ошибку: gradient descent.
Parameters vs hyperparametersУчатся только weights и biases. Архитектура, activation, learning rate — design choices (hyperparameters).
Один нейрон и слои
z = Σ wᵢxᵢ + b, a = g(z). Без g нейрон = линейный классификатор. Input layer (по юниту на признак, например 3072 пикселя) → hidden layers (превращают входы в полезные признаки) → output layer (scores классов или значение регрессии). Каждый узел связан с каждым узлом следующего слоя = fully connected (dense). Слои считают по весам, без input: это 2-layer network.
Двухслойная сеть на CIFAR-10
Формулаf(x) = W₂ · max(0, W₁x + b₁) + b₂: 3072 входа → 100 hidden (= 100 шаблонов) → 10 scores.
Параметры: 3072·100 + 100 + 100·10 + 10 = 308 310. Второй слой смешивает шаблоны: horse = 0.7 · left-facing + 0.6 · right-facing, поэтому у класса может быть несколько «мод».
Почему нелинейность обязательна
CollapseW₂(W₁x) = (W₂W₁)x = W′x. Любой стек линейных слоёв схлопывается в один линейный слой. Глубина даёт силу, только если между слоями есть activation.
Activation functions
| Function | Formula | Range | Pros / cons |
| Sigmoid | 1 / (1 + e⁻ᶻ) | (0, 1) | Saturates, not zero-centred |
| tanh | tanh(z) | (−1, 1) | Zero-centred, still saturates |
| ReLU | max(0, z) | [0, ∞) | Default. Дёшево; юниты могут «умереть» |
| Leaky ReLU | max(0.01z, z) | ℝ | Исправляет dead units |
| GELU | z · Φ(z) | ≈ (−0.17, ∞) | Стандарт в Transformers |
Saturation: на плоских концах градиент почти 0 → обучение останавливается. ReLU имеет наклон ровно 1 при z > 0. Правило курса: ReLU в hidden, sigmoid только на выходе для binary.
Worked example: spam
«Get free gift cards now!» → free = 1, win = 0, offer = 1 → x = [1, 0, 1]. Biases = 0.
| Unit | Weighted sum | Activation | Output |
| H1 | 1·0.5 + 0·(−0.2) + 1·0.3 = 0.8 | ReLU | 0.8 |
| H2 | 1·0.4 + 0·0.1 + 1·(−0.5) = −0.1 | ReLU | 0 |
| Out | 0.8·0.7 + 0·0.2 = 0.56 | Sigmoid | 0.636 |
0.636 > 0.5 → spam. H2 = 0, потому что ReLU обрезает отрицательные.
Training loop
- Forwardвходы → предсказание
- LossMSE или cross-entropy
- Backwardchain rule → ∂L/∂w
- Updatew ← w − η·∂L/∂w
- Repeatмного эпох
Learning paradigms: supervised (пары (x, y); большая часть CV: классификация, детекция), unsupervised (без меток: кластеры, autoencoders, self-supervised), reinforcement (агент, награды; роботы, игры).
Типы сетей
| Architecture | Для чего | Где в курсе |
| Feedforward / MLP | Векторы фиксированного размера, данные идут в одну сторону | Lecture 4 |
| CNN | Изображения, видео: фильтры скользят по картинке | Следующие лекции |
| RNN · LSTM · GRU | Последовательности, hidden state = память | Recurrent networks |
| Transformer | Токены, патчи; attention связывает все со всеми (ViT, DETR, SAM) | Transformers |
| Autoencoder · GAN | Сжатие в code и восстановление; generator vs discriminator | Generative models |
| Siamese | Сравнение двух входов | Face verification |
Редко сейчас: RBFN, SOM, DBN (эпоха pre-training 2006–2012), CapsNet, SNN (spiking, ближе всего к биологии).
Strengths
- Нелинейные паттерны
- Сами извлекают признаки
- Параллельно на GPU
- Обобщают на новые данные
Limitations
- Дорого обучать
- «Black box»
- Могут переобучиться
- Нужны большие размеченные датасеты
TipНе уменьшай сеть, чтобы бороться с overfitting. Бери большую сеть + сильную регуляризацию (weight decay, dropout).
model = nn.Sequential(
nn.Flatten(),
nn.Linear(3*32*32, 100), # W1, b1
nn.ReLU(),
nn.Linear(100, 10)) # W2, b2
loss_fn = nn.CrossEntropyLoss()
opt = torch.optim.SGD(model.parameters(), lr=1e-2)
for x, y in train_loader:
loss = loss_fn(model(x), y) # forward
opt.zero_grad()
loss.backward() # backprop
opt.step() # update
Lecture 4.2
Backpropagation
Зачем backprop, computational graph и chain rule, пример f = (x + y)·z, gate patterns, backward pass для spam-сети, матричные градиенты и правило shapes, модульные слои, gradient check и типичные ошибки.
Проблема: 308 310 весов, один loss
| Способ | Стоимость |
| By hand | Страницы алгебры, заново для каждой архитектуры. Infeasible. |
| Numerically | 2 forward pass на вес ≈ 616 000 на шаг. Far too slow. |
| Backpropagation | Один forward и один backward для всех весов ≈ 2–3× forward pass. |
Computational graph + chain rule
Всё правилоdownstream = local × upstream: ∂L/∂x = (∂z/∂x) · ∂L/∂z. Узлу не нужно знать остальную сеть, только свою локальную производную. Градиенты идут справа налево, от loss к входам.
Пример: f = (x + y) · z
x = −2, y = 5, z = −4 → q = x + y = 3 → f = q·z = −12.
| Var | Forward | Local | Upstream | ∂f/∂· |
| f | −12 | — | — | 1 |
| z | −4 | ∂f/∂z = q = 3 | 1 | 3 |
| q | 3 | ∂f/∂q = z = −4 | 1 | −4 |
| x | −2 | ∂q/∂x = 1 | −4 | −4 |
| y | 5 | ∂q/∂y = 1 | −4 | −4 |
Проверка: x + 0.01 → q = 3.01 → f = −12.04; изменение −0.04 = −4 × 0.01 ✔
Gate patterns
- add → distributor
- Передаёт upstream gradient без изменений каждому входу.
- multiply → swapper
- Градиент одному входу = upstream × другой вход.
- max → router
- Весь градиент большему входу, остальным 0. Так работает ReLU.
- copy → adder
- Если значение идёт в несколько веток, их градиенты суммируются.
Sigmoid можно считать одним узлом: σ′(z) = σ(z)(1 − σ(z)). При σ = 0.99 локальный градиент ≈ 0.01: это и есть saturation.
Backward pass для spam-сети (y = 1)
| Шаг | Вычисление | Результат |
| Loss (BCE) | L = −ln(0.636) | 0.452 |
| Output grad | ∂L/∂z = p − y | −0.364 |
| Output weights | −0.364 × [0.8, 0] | [−0.291, 0] |
| Hidden outputs | −0.364 × [0.7, 0.2] | [−0.255, −0.073] |
| Through ReLU | вход H2 был −0.1 → градиент блокирован | [−0.255, 0] |
| W₁, row H1 | −0.255 × [1, 0, 1] | [−0.255, 0, −0.255] |
| Update, η = 0.1 | 0.7 − 0.1 × (−0.291) | 0.729 |
Сразу три паттерна: multiply подставляет другой вход, ReLU направляет в 0, вес для «win = 0» не обновляется. Sigmoid + BCE дают простой градиент p − y.
Векторы и матрицы: y = Wx
Формулы∂L/∂W = (∂L/∂y) · xᵀ, ∂L/∂x = Wᵀ · (∂L/∂y). Shape rule: градиент имеет ту же форму, что и переменная.
W: 10×3072, x: 3072×1, ∂L/∂y: 10×1 → (10×1)·(1×3072) = 10×3072 ✔ совпадает с W. Полный Jacobian огромный и почти весь из нулей, его не строят. Забыл формулу — расставь транспонирования, пока shapes не сойдутся.
Модульные слои
class Multiply:
def forward(self, x, y):
self.x, self.y = x, y # cache
return x * y
def backward(self, dout):
dx = dout * self.y # swap
dy = dout * self.x
return dx, dy
forward() считает выход и кэширует нужное для backward. backward(dout) берёт upstream и возвращает local × upstream. Autograd в PyTorch хранит граф и вызывает backward в обратном порядке.
Gradient check
∂f/∂w ≈ [f(w + h) − f(w − h)] / 2h (centred difference, h ≈ 1e-5). Numerical: медленно, но надёжно (эталон). Analytic: быстро и точно, но легко сломать. Relative error |a − n| / max(|a|, |n|) < 1e-7 → backward верен; ≈ 1e-4 допустимо с ReLU; 1e-2 → баг.
Четыре частые ошибки
- Overwriting at branches: градиенты веток надо складывать (
+=, не =).
- Forgetting the cache: backward нужны входы из forward.
- Wrong ReLU mask: пропускать градиент там, где вход был положительным.
- No zero_grad(): PyTorch накапливает градиенты между шагами (это правило copy → adder).
SummaryNon-linearity makes depth useful; the chain rule makes training possible. Next: CNN.
Практика · по образцу мидтерма
Image Processing & OpenCV
Этого нет в слайдах лекций 1–4, но Q1 и Q4 образца (40 баллов) целиком про OpenCV: изображение как массив, BGR, resize, grayscale, фильтры, Canny, threshold, нормализация и preprocessing для классификации.
Изображение = NumPy array
- Color image
img.shape = (H, W, 3) — высота, ширина, каналы. dtype = uint8, значения 0–255.
- Grayscale
(H, W) — 2D, третьего измерения нет (1 канал).
- Пиксель
img[y, x] — сначала строка (y), потом столбец (x). Цветной пиксель = 3 числа [B, G, R].
- Crop
img[y1:y2, x1:x2]
- Размер в числах
- H·W·C: 224×224×3 = 150 528 значений; 32×32×3 = 3072.
Главные функции
| Функция | Что делает | Ловушка |
cv2.imread(path) | Читает изображение в BGR | Не RGB! Если файла нет, возвращает None без ошибки. Флаг cv2.IMREAD_GRAYSCALE читает сразу в серый. |
cv2.cvtColor(img, code) | Смена цветового пространства | Для imread нужен COLOR_BGR2GRAY, COLOR_BGR2RGB, COLOR_BGR2HSV. COLOR_RGB2GRAY на BGR-картинке перепутает веса R и B. |
cv2.resize(img, (w, h)) | Меняет размер | dsize = (width, height), а shape = (height, width, C). Не сохраняет aspect ratio → искажение. Интерполяция: INTER_AREA для уменьшения, INTER_LINEAR/CUBIC для увеличения. |
cv2.GaussianBlur(img, (k, k), σ) | Сглаживание взвешенным средним (Gaussian kernel) | k положительное и нечётное: (3,3), (5,5). (4,4) → ошибка. σ = 0 → вычисляется из k. |
cv2.blur(img, (k, k)) | Mean filter | Размывает края сильнее Gaussian. |
cv2.medianBlur(img, k) | Медиана окна | Лучший против salt-and-pepper шума; k нечётное, одно число. |
cv2.bilateralFilter(img, d, σc, σs) | Сглаживает, сохраняя края | Медленнее. |
cv2.Canny(gray, low, high) | Edge detector (John Canny, 1986) → бинарная карта краёв 0/255 | Выход 1 канал, тот же H×W. Чувствителен к шуму → сначала blur. |
cv2.threshold(gray, t, 255, cv2.THRESH_BINARY) | Бинаризация | Возвращает кортеж (ret, img). THRESH_OTSU подбирает t сам; adaptiveThreshold для неравномерного света. |
cv2.equalizeHist(gray) | Histogram equalization: растягивает контраст | Только для 1 канала. CLAHE (createCLAHE) — локальная версия, меньше усиливает шум. |
cv2.flip(img, 1) | Горизонтальное отражение (augmentation) | 0 = вертикально, −1 = оба. |
cv2.imshow / plt.imshow | Показ | matplotlib ждёт RGB → BGR-картинка выглядит синей. Сначала BGR2RGB. |
Canny: что внутри
- Gaussian smoothingубрать шум
- Gradientмагнитуда и направление (Sobel)
- Non-max suppressionтонкие края в 1 пиксель
- Double thresholdlow / high: strong и weak edges
- Hysteresisweak оставить, только если связан со strong
Почему blur перед CannyCanny основан на градиентах (производных яркости). Шум = резкие локальные перепады → большие градиенты → ложные края. Gaussian blur подавляет высокочастотный шум, и остаются настоящие границы объектов. Своё сглаживание у Canny есть, но дополнительный blur даёт больше контроля.
Grayscale: плюсы и минусы
Advantages
- 3 канала → 1: в 3 раза меньше данных, быстрее, меньше параметров модели
- Меньше чувствительность к оттенку освещения
- Нужен для Canny, threshold, equalizeHist
Disadvantages
- Теряется цвет: пятна болезни (жёлтые/коричневые на зелёном), цвет мусора, спелость фрукта
- Разные цвета с одинаковой яркостью становятся одинаковыми
Preprocessing для классификации
- Resize to fixed size
- Разные разрешения → модели нужен фиксированный input (например 224×224 или 32×32), батчи одного размера.
- Normalization
img / 255.0 → [0, 1], или standardization (x − mean) / std по train. Одинаковый масштаб признаков, стабильнее и быстрее обучение (как StandardScaler в L3).
- Denoising
- Gaussian / median blur против шума сенсора; median для salt-and-pepper.
- Lighting correction
- Histogram equalization / CLAHE или нормализация яркости при разном освещении.
- Color conversion
- BGR → RGB для модели и показа; HSV для сегментации по цвету (
cv2.inRange).
- Cropping / segmentation
- Вырезать объект, убрать фон (background clutter).
- Data augmentation
- Flip, rotation, crop, brightness/contrast — только для train; делает модель устойчивой к viewpoint и illumination.
«More preprocessing always improves accuracy?» — нет
- Удаляет полезную информацию: grayscale убирает цвет пятен болезни; сильный blur стирает мелкие пятна и текстуру; resize до 32×32 теряет детали.
- Усиливает шум: histogram equalization на тёмном шумном фото.
- Нереалистичная augmentation: вертикальный flip цифры 6 → 9 меняет класс.
- Mismatch: если preprocessing на test отличается от train, качество падает.
Каждый шаг надо обосновывать задачей и проверять на validation set.
Типичные баги в коде (ищут в Q1c)
# BAD
img = cv2.imread("leaf.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) # imread даёт BGR
blur = cv2.GaussianBlur(gray, (4, 4), 0) # ядро должно быть нечётным
# GOOD
img = cv2.imread("leaf.jpg")
if img is None:
raise FileNotFoundError("leaf.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
cv2.resize(img, (h, w)) вместо (w, h) для неквадратного размера.
cv2.Canny на цветном вместо grayscale (работает, но обычно подают серый).
thresh = cv2.threshold(...) без распаковки _, thresh.
cv2.equalizeHist на 3-канальном изображении → ошибка.
img + 100 в uint8 переполняется по модулю 256; cv2.add насыщает до 255.
cv2.medianBlur(img, (5, 5)) — нужен int 5.
Pipeline из Q4: shapes по шагам
| Строка | Shape |
img = cv2.imread("cat.jpg") | (H, W, 3), BGR, uint8 |
img = cv2.resize(img, (224, 224)) | (224, 224, 3) |
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | (224, 224) — 3 канала → 1 |
blur = cv2.GaussianBlur(gray, (5, 5), 0) | (224, 224) — размер не меняется |
edges = cv2.Canny(blur, 100, 200) | (224, 224), значения 0 или 255 |
Если задача зависит от цвета, подавать только edges нельзя: edges хранят форму и границы, но цвет потерян ещё на шаге grayscale. Лучше подать цветное изображение (RGB, нормализованное) или цвет + edges.
Практика · по образцу мидтерма
Designing a CV System & Evaluation
Q5 образца и части Q2: как организовать датасет, разделить train/val/test, выбрать preprocessing и метрику, распознать overfitting и domain shift. Собрано из L2–L4 и практики.
Порядок проектирования
- Defineклассы и что считается «верно»
- Collect & labelразнообразные данные
- Splittrain / val / test, stratified
- Preprocessresize, normalize, augment
- Trainbaseline → лучше модель
- Evaluateметрика, confusion matrix
Организация датасета
waste_dataset/
train/ plastic/ paper/ glass/ other/
val/ plastic/ paper/ glass/ other/
test/ plastic/ paper/ glass/ other/
- Одна папка на класс (или CSV: filename, label) — метки однозначны и проверены.
- Проверить баланс классов (сколько изображений в каждом).
- Убрать дубликаты и битые файлы; одинаковые/почти одинаковые фото не должны попасть в train и test одновременно (data leakage).
- Разнообразие: разные фоны, освещение, ракурсы, камеры.
Train / validation / test split
| Split | Из 2000 | Зачем |
| 80 / 20 | 1600 train · 400 test | Самый простой ответ на «train/test split» |
| 70 / 15 / 15 | 1400 train · 300 val · 300 test | Val для hyperparameters, test один раз в конце |
| 80 / 10 / 10 | 1600 · 200 · 200 | Больше данных для обучения |
Stratified split: в каждой части те же пропорции классов (при 4 сбалансированных классах: 1600 / 4 = 400 на класс в train, 100 на класс в test). Для маленьких датасетов можно k-fold cross-validation (L2).
Метрики
- Accuracy
correct / total. Хороша, когда классы сбалансированы и ошибки одинаково «дорогие».
- Precision
TP / (TP + FP): из предсказанных как класс, сколько правда этот класс.
- Recall
TP / (TP + FN): из настоящих объектов класса, сколько нашли.
- F1 / macro-F1
2PR / (P + R); macro = среднее F1 по классам. Для imbalanced классов.
- Confusion matrix
- Какие классы путаются (plastic ↔ glass).
- Top-5 accuracy
- Верный класс среди 5 лучших (ImageNet).
Пример: 95 «other» и 5 «glass» → модель «всегда other» имеет 95% accuracy, но recall(glass) = 0. Поэтому при дисбалансе смотрим per-class recall / macro-F1.
Score vs probability
Class score
Сырое число из Wx + b (logit), любое вещественное, может быть отрицательным; суммы нет смысла сравнивать между примерами. Решение = argmax.
Class probability
Softmax(scores): каждое в [0, 1], сумма = 1, читается как уверенность. Argmax тот же, что у scores.
Overfitting и underfitting
| Симптом | Диагноз | Что делать |
| Train высокий, test низкий (95% vs 62%) | Overfitting: модель запомнила train, не обобщает | Больше данных, data augmentation, регуляризация (L2 / weight decay, dropout), early stopping, выбор hyperparameters на val. Совет L4: большая сеть + сильная регуляризация. |
| Train и test оба низкие | Underfitting: модель слишком простая (линейная для нелинейных данных) | Более сложная модель (NN вместо линейной), лучше признаки, дольше учить. |
Domain shift
Модель отлично работает на своём датасете, но плохо на фото с телефона другого студента. Причины: другая камера (разрешение, цветопередача, шум, обработка), другое освещение, фон, ракурс, расстояние. Train и test были из одного распределения, а реальные данные из другого: distribution / domain shift, слабое обобщение. Решение: собирать разнообразные данные (разные телефоны, условия), augmentation (яркость, цвет, blur, crop), нормализация, fine-tuning на новых данных.
Выбор модели
- kNN на пикселях: простой baseline, но медленный и плохие distance metrics (L2).
- Linear classifier: быстрый, один шаблон на класс, только прямые границы (L3).
- Neural network / CNN: нелинейные признаки, лучшее качество на изображениях (L4 и дальше).