MARSHAL327

linear_svm

Dec 26th, 2023
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.60 KB | None | 0 0
  1. import numpy as np
  2. from random import shuffle
  3.  
  4. def svm_loss_naive(W, X, y, reg):
  5. """
  6. SVM функция потерь, наивная реализация (с циклами).
  7.  
  8. D - длина вектора данных, C - число классов,
  9. операции выполняются над миниблоками с N примерами.
  10.  
  11. Входы:
  12. - W: numpy масссив формы (D, C), содержащий веса.
  13. - X: numpy масссив формы (N, D), содержащий миниблок данных.
  14. - y: numpy масссив формы (N,), содержащий обучающие метки; y[i] = c означает,
  15. что X[i] имеет метку c, где 0 <= c < C.
  16. - reg: (float) коэффициент регуляризации
  17.  
  18. Возращает кортеж из:
  19. - потери в формате single float
  20. - градиент по отношению к весам W; массив такой же формы как W
  21. """
  22.  
  23. dW = np.zeros(W.shape) # инициализируем градиент
  24.  
  25. num_classes = W.shape[1]
  26. num_train = X.shape[0]
  27.  
  28.  
  29. loss = 0.0
  30. for i in range(num_train):
  31. scores = X[i].dot(W)
  32. correct_class_score = scores[y[i]]
  33. for j in range(num_classes):
  34. if j == y[i]:
  35. continue
  36. margin = scores[j] - correct_class_score + 1 # note delta = 1
  37. if margin > 0:
  38. loss += margin
  39. dW[:, j] += X[i]
  40. dW[:, y[i]] -= X[i]
  41.  
  42. # До этого момента потери - это сумма потерь по всем обучающим примерам,
  43. # но мы хотим получить средние потери поэтому делим на num_train.
  44. loss /= num_train
  45.  
  46. # Добавляем регуляризацию
  47. loss += reg * np.sum(W * W)
  48.  
  49. # Усредняем градиент по всем обучающим примерам
  50. dW /= num_train
  51.  
  52. # Добавляем к градиенту слагаемое от регуляризации
  53. dW += 2 * reg * W #2 * ...
  54.  
  55. #############################################################################
  56. # ЗАДАНИЕ: #
  57. # Вычислите градиент функции потерь по отношению к W и сохраните его в dW. #
  58. # Вместо того, чтобы сначала вычислять функцию потерь, а затем вычислять #
  59. # производную, вычисляйте производную в процессе вычисления функции потерь. #
  60. # Поэтому Вам просто модифицируйте код приведенный выше, включив него #
  61. # вычисление требуемого градиента #
  62. #############################################################################
  63.  
  64. return loss, dW
  65.  
  66.  
  67. def svm_loss_vectorized(W, X, y, reg):
  68. """
  69. SVM функцмя потерь, векторизованная реализация.
  70.  
  71. Входы и выходы такие же, как и у svm_loss_naive.
  72. """
  73. loss = 0.0
  74. dW = np.zeros(W.shape) # инициализируем градиент нулями
  75.  
  76. #############################################################################
  77. # ЗАДАНИЕ: #
  78. # Реализуйте векторизованную версию кода для вычисления SVM функции потерь. #
  79. # Сохраните результат в переменной loss. #
  80. #############################################################################
  81.  
  82.  
  83. num_train = X.shape[0]
  84.  
  85. # Вычисляем оценки для каждого класса
  86. scores = X.dot(W) # форма (N, C)
  87.  
  88. # Вычисляем правильные оценки для каждого примера
  89. correct_scores = scores[np.arange(num_train), y].reshape(-1, 1) # форма (N,)
  90.  
  91. # Вычисляем маржинальные ошибки для каждого класса
  92. margins = np.maximum(0, scores - correct_scores + 1) # форма (N, C)
  93.  
  94. # Устанавливаем маржинальные ошибки для правильных классов равными нулю
  95. margins[np.arange(num_train), y] = 0
  96.  
  97. # Суммируем маржинальные ошибки по всем классам и усредняем по числу примеров
  98. loss = np.sum(margins) / num_train
  99.  
  100. # Добавляем регуляризационный член к потерям
  101. loss += reg * np.sum(W * W)
  102.  
  103. #############################################################################
  104. # КОНЕЦ ВАШЕГО КОДА #
  105. #############################################################################
  106.  
  107.  
  108. #############################################################################
  109. # ЗАДАНИЕ: #
  110. # Реализуйте векторизованную версию кода для вычисления градиента SVM #
  111. # функции потерь. Сохраните результат в переменной dW. #
  112. # Совет: Используйте некоторые промежуточные значения, которые были #
  113. # получены при вычислении функции потерь. #
  114. #############################################################################
  115.  
  116. # Создаем матрицу binary, которая содержит 1 для элементов, где margin > 0, и 0 в остальных случаях
  117. binary = np.zeros((num_train, W.shape[1]))
  118. binary[margins > 0] = 1
  119.  
  120. # Для каждого примера обучения, обнуляем элемент, соответствующий правильному классу
  121. # Это нужно для того, чтобы не учитывать вклад правильного класса в функцию потерь и градиент
  122. binary[np.arange(num_train), y] = 0
  123.  
  124. # Для каждого примера обучения, вычитаем сумму всех единиц из элемента, соответствующего правильному классу
  125. # Это нужно для того, чтобы правильный класс получал отрицательный вклад в функцию потерь и градиент
  126. binary[np.arange(num_train), y] = -np.sum(binary, axis=1)
  127.  
  128. # Вычисляем градиент по матрице весов, умножая транспонированную матрицу данных на бинарную матрицу
  129. dW = X.T.dot(binary) # форма (D, C)
  130.  
  131. # Усредняем градиент по числу примеров
  132. dW /= num_train #X.shape[0]
  133.  
  134. # Добавляем регуляризационный член к градиенту
  135. dW += 2 * reg * W #2 потому что L2 регуляризация
  136.  
  137. #############################################################################
  138. # КОНЕЦ ВАШЕГО КОДА #
  139. #############################################################################
  140. return loss, dW
  141.  
Add Comment
Please, Sign In to add comment