Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import numpy as np
- from random import shuffle
- def svm_loss_naive(W, X, y, reg):
- """
- SVM функция потерь, наивная реализация (с циклами).
- D - длина вектора данных, C - число классов,
- операции выполняются над миниблоками с N примерами.
- Входы:
- - W: numpy масссив формы (D, C), содержащий веса.
- - X: numpy масссив формы (N, D), содержащий миниблок данных.
- - y: numpy масссив формы (N,), содержащий обучающие метки; y[i] = c означает,
- что X[i] имеет метку c, где 0 <= c < C.
- - reg: (float) коэффициент регуляризации
- Возращает кортеж из:
- - потери в формате single float
- - градиент по отношению к весам W; массив такой же формы как W
- """
- dW = np.zeros(W.shape) # инициализируем градиент
- num_classes = W.shape[1]
- num_train = X.shape[0]
- loss = 0.0
- for i in range(num_train):
- scores = X[i].dot(W)
- correct_class_score = scores[y[i]]
- for j in range(num_classes):
- if j == y[i]:
- continue
- margin = scores[j] - correct_class_score + 1 # note delta = 1
- if margin > 0:
- loss += margin
- dW[:, j] += X[i]
- dW[:, y[i]] -= X[i]
- # До этого момента потери - это сумма потерь по всем обучающим примерам,
- # но мы хотим получить средние потери поэтому делим на num_train.
- loss /= num_train
- # Добавляем регуляризацию
- loss += reg * np.sum(W * W)
- # Усредняем градиент по всем обучающим примерам
- dW /= num_train
- # Добавляем к градиенту слагаемое от регуляризации
- dW += 2 * reg * W #2 * ...
- #############################################################################
- # ЗАДАНИЕ: #
- # Вычислите градиент функции потерь по отношению к W и сохраните его в dW. #
- # Вместо того, чтобы сначала вычислять функцию потерь, а затем вычислять #
- # производную, вычисляйте производную в процессе вычисления функции потерь. #
- # Поэтому Вам просто модифицируйте код приведенный выше, включив него #
- # вычисление требуемого градиента #
- #############################################################################
- return loss, dW
- def svm_loss_vectorized(W, X, y, reg):
- """
- SVM функцмя потерь, векторизованная реализация.
- Входы и выходы такие же, как и у svm_loss_naive.
- """
- loss = 0.0
- dW = np.zeros(W.shape) # инициализируем градиент нулями
- #############################################################################
- # ЗАДАНИЕ: #
- # Реализуйте векторизованную версию кода для вычисления SVM функции потерь. #
- # Сохраните результат в переменной loss. #
- #############################################################################
- num_train = X.shape[0]
- # Вычисляем оценки для каждого класса
- scores = X.dot(W) # форма (N, C)
- # Вычисляем правильные оценки для каждого примера
- correct_scores = scores[np.arange(num_train), y].reshape(-1, 1) # форма (N,)
- # Вычисляем маржинальные ошибки для каждого класса
- margins = np.maximum(0, scores - correct_scores + 1) # форма (N, C)
- # Устанавливаем маржинальные ошибки для правильных классов равными нулю
- margins[np.arange(num_train), y] = 0
- # Суммируем маржинальные ошибки по всем классам и усредняем по числу примеров
- loss = np.sum(margins) / num_train
- # Добавляем регуляризационный член к потерям
- loss += reg * np.sum(W * W)
- #############################################################################
- # КОНЕЦ ВАШЕГО КОДА #
- #############################################################################
- #############################################################################
- # ЗАДАНИЕ: #
- # Реализуйте векторизованную версию кода для вычисления градиента SVM #
- # функции потерь. Сохраните результат в переменной dW. #
- # Совет: Используйте некоторые промежуточные значения, которые были #
- # получены при вычислении функции потерь. #
- #############################################################################
- # Создаем матрицу binary, которая содержит 1 для элементов, где margin > 0, и 0 в остальных случаях
- binary = np.zeros((num_train, W.shape[1]))
- binary[margins > 0] = 1
- # Для каждого примера обучения, обнуляем элемент, соответствующий правильному классу
- # Это нужно для того, чтобы не учитывать вклад правильного класса в функцию потерь и градиент
- binary[np.arange(num_train), y] = 0
- # Для каждого примера обучения, вычитаем сумму всех единиц из элемента, соответствующего правильному классу
- # Это нужно для того, чтобы правильный класс получал отрицательный вклад в функцию потерь и градиент
- binary[np.arange(num_train), y] = -np.sum(binary, axis=1)
- # Вычисляем градиент по матрице весов, умножая транспонированную матрицу данных на бинарную матрицу
- dW = X.T.dot(binary) # форма (D, C)
- # Усредняем градиент по числу примеров
- dW /= num_train #X.shape[0]
- # Добавляем регуляризационный член к градиенту
- dW += 2 * reg * W #2 потому что L2 регуляризация
- #############################################################################
- # КОНЕЦ ВАШЕГО КОДА #
- #############################################################################
- return loss, dW
Add Comment
Please, Sign In to add comment