Векторизация для цикла в Python - PullRequest
0 голосов
/ 05 мая 2018

У меня есть следующий цикл, в котором я вычисляю преобразование softmax для пакетов разных размеров, как показано ниже

import numpy as np 
def softmax(Z,arr):
    """
    :param Z:  numpy array of any shape (output from hidden layer)
    :param arr: numpy array of any shape (start, end)
    :return A: output of multinum_logit(Z,arr), same shape as Z
    :return cache: returns Z as well, useful during back propagation
    """
    A = np.zeros(Z.shape)
    for i in prange(len(arr)):
        shiftx = Z[:,arr[i,1]:arr[i,2]+1] - np.max(Z[:,int(arr[i,1]):int(arr[i,2])+1])
        A[:,arr[i,1]:arr[i,2]+1] = np.exp(shiftx)/np.exp(shiftx).sum()
    cache = Z
    return A,cache

Поскольку цикл for не векторизован, это узкое место в моем коде. Какое возможное решение, чтобы сделать это быстрее. Я попытался использовать @jit из numba, что делает его немного быстрее, но недостаточно. Мне было интересно, есть ли другой способ сделать это быстрее или векторизовать / распараллелить это.

Пример входных данных для функции

Z = np.random.random([1,10000])
arr = np.zeros([100,3])
arr[:,0] = 1
temp = int(Z.shape[1]/arr.shape[0])
for i in range(arr.shape[0]):
    arr[i,1] = i*temp
    arr[i,2] = (i+1)*temp-1
arr = arr.astype(int)

EDIT:

Я забыл подчеркнуть, что количество моих классов варьируется. Например, партия 1 имеет, например, 10 классов, партия 2 может иметь 15 классов. Поэтому я передаю массив arr, который отслеживает, какие строки принадлежат batch1 и так далее. Эти партии отличаются от партий в традиционной структуре нейронной сети

В приведенном выше примере arr отслеживает начальный индекс и конечный индекс строк. Таким образом, знаменатель в функции softmax будет суммой только тех наблюдений, чей индекс находится между начальным и конечным индексом.

1 Ответ

0 голосов
/ 05 мая 2018

Вот векторизованная функция softmax. Это выполнение задания из Стэнфордского курса cs231n по сетям.

Функция принимает оптимизируемые параметры, входные данные, цели и регуляризатор. (Вы можете игнорировать регуляризатор, поскольку он ссылается на другой класс, исключающий некоторые назначения cs231n).

Возвращает потери и градиенты параметров.

def softmax_loss_vectorized(W, X, y, reg):
  """
  Softmax loss function, vectorized version.
  Inputs and outputs are the same as softmax_loss_naive.
  """
  # Initialize the loss and gradient to zero.

  loss = 0.0
  dW = np.zeros_like(W)

  num_train = X.shape[0]

  scores = X.dot(W)

  shift_scores = scores - np.amax(scores,axis=1).reshape(-1,1)

  softmax = np.exp(shift_scores)/np.sum(np.exp(shift_scores), axis=1).reshape(-1,1)

  loss = -np.sum(np.log(softmax[range(num_train), list(y)]))

  loss /= num_train

  loss += 0.5* reg * np.sum(W * W)

  dSoftmax = softmax.copy()

  dSoftmax[range(num_train), list(y)] += -1

  dW = (X.T).dot(dSoftmax)
  dW = dW/num_train + reg * W

  return loss, dW

Для сравнения приведу наивную (не векторизованную) реализацию того же метода.

def softmax_loss_naive(W, X, y, reg):
  """
  Softmax loss function, naive implementation (with loops)
  Inputs have dimension D, there are C classes, and we operate on minibatches
  of N examples.
  Inputs:
  - W: A numpy array of shape (D, C) containing weights.
  - X: A numpy array of shape (N, D) containing a minibatch of data.
  - y: A numpy array of shape (N,) containing training labels; y[i] = c means
    that X[i] has label c, where 0 <= c < C.
  - reg: (float) regularization strength
  Returns a tuple of:
  - loss as single float
  - gradient with respect to weights W; an array of same shape as W
  """

  loss = 0.0
  dW = np.zeros_like(W)

  num_train = X.shape[0]
  num_classes = W.shape[1]

  for i in xrange(num_train):
      scores = X[i].dot(W)

      shift_scores = scores - max(scores)

      loss_i = -shift_scores[y[i]] + np.log(sum(np.exp(shift_scores)))
      loss += loss_i
      for j in xrange(num_classes):
          softmax = np.exp(shift_scores[j])/sum(np.exp(shift_scores))
          if j==y[i]:

              dW[:,j] += (-1 + softmax) * X[i]
          else:
              dW[:,j] += softmax *X[i]

  loss /= num_train

  loss += 0.5 * reg * np.sum(W * W)

  dW /= num_train + reg * W

  return loss, dW

Источник

...