Весы / смещения обновляются только один раз для каждой мини-партии?

Я следую учебному пособию по нейронным сетям, и у меня есть вопрос о функции, которая обновляет веса.

def update_mini_batch(self, mini_batch, eta):
    """Update the network's weights and biases by applying
    gradient descent using backpropagation to a single mini batch.
    The "mini_batch" is a list of tuples "(x, y)", and "eta"
    is the learning rate."""
    nabla_b = [np.zeros(b.shape) for b in self.biases]                #Initialize bias matrix with 0's
    nabla_w = [np.zeros(w.shape) for w in self.weights]               #Initialize weights matrix with 0's
    for x, y in mini_batch:                                           #For tuples in one mini_batch
        delta_nabla_b, delta_nabla_w = self.backprop(x, y)            #Calculate partial derivatives of bias/weights with backpropagation, set them to delta_nabla_b
        nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] #Generate a list with partial derivatives of bias of every neuron
        nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] #Generate a list with partial derivatives of weights for every neuron
    self.weights = [w-(eta/len(mini_batch))*nw                        #Update weights according to update rule
                    for w, nw in zip(self.weights, nabla_w)]          #What author does is he zips 2 lists with values he needs (Current weights and partial derivatives), then do computations with them.
    self.biases = [b-(eta/len(mini_batch))*nb                         #Update biases according to update rule
                   for b, nb in zip(self.biases, nabla_b)]

Чего я здесь не понимаю, так это того, что для вычисления nabla_b и nabla_w используется цикл for (частные производные от весов / смещений). С обратным распространением для каждого учебного примера в мини-партии, но обновлять веса / смещения только один раз.

Мне кажется, что, скажем, у нас есть мини-пакет размером 10, мы вычисляем nabla_b и nabla_w 10 раз, и после того, как цикл for завершает обновление весов и смещений. Но разве цикл for не сбрасывает списки nabla_b и nabla_b каждый раз? Почему бы нам не обновить self.weights а также self.biases внутри цикла?

Нейронная сеть работает отлично, поэтому я думаю, что где-то допускаю небольшую ошибку мышления.

К вашему сведению: соответствующую часть учебника, которому я следую, можно найти здесь

2 ответа

Решение

Ключом к пониманию того, как этот цикл добавляет смещения и веса в каждом учебном примере, является примечание порядка оценки в Python. В частности, все справа от = знак оценивается до того, как он назначен переменной слева от = подписать.

Это более простой пример, который может быть проще для понимания:

nabla_b = [0, 0, 0, 0, 0]
for x in range(10):
    delta_nabla_b = [-1, 2, -3, 4, -5]
    nabla_b = [nb + dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]

В этом примере у нас есть только пять скалярных смещений и постоянный градиент для каждого. В конце этого цикла, что является nabla_b? Рассмотрим понимание, расширенное с использованием определения zip и помня, что все справа от = знак оценивается до того, как он будет записан в имя переменной слева:

nabla_b = [0, 0, 0, 0, 0]
for x in range(10):
    # nabla_b is defined outside of this loop
    delta_nabla_b = [-1, 2, -3, 4, -5]

    # expand the comprehension and the zip() function
    temp = []
    for i in range(len(nabla_b)):
        temp.append(nabla_b[i] + delta_nabla_b[i])

    # now that the RHS is calculated, set it to the LHS
    nabla_b = temp

На этом этапе должно быть ясно, что каждый элемент nabla_b суммируется с каждым соответствующим элементом delta_nabla_b в понимании, и этот результат перезаписывает nabla_b для следующей итерации цикла.

Итак, в учебном примере, nabla_b а также nabla_w являются суммами частных производных, к которым добавлен градиент, один раз за обучающий пример в мини-пакете. Технически они сбрасываются для каждого обучающего примера, но они сбрасываются до их предыдущего значения плюс градиент, который является именно тем, что вы хотите. Более понятный (но менее лаконичный) способ написать это мог бы быть:

def update_mini_batch(self, mini_batch, eta):
    nabla_b = [np.zeros(b.shape) for b in self.biases]
    nabla_w = [np.zeros(w.shape) for w in self.weights]
    for x, y in mini_batch:
        delta_nabla_b, delta_nabla_w = self.backprop(x, y)
        # expanding the comprehensions
        for i in range(len(nabla_b)):
            nabla_b[i] += delta_nabla_b[i]      # set the value of each element directly
        for i in range(len(nabla_w)):
            nabla_w[i] += delta_nabla_w[i]
    self.weights = [w-(eta/len(mini_batch))*nw  # note that this comprehension uses the same trick
                    for w, nw in zip(self.weights, nabla_w)]
    self.biases = [b-(eta/len(mini_batch))*nb
                   for b, nb in zip(self.biases, nabla_b)]

Нет, обновление происходит после окончания пакета, применяя каждое из обучающих обновлений по очереди. Каноническое описание говорит, что мы вычисляем среднее значение всех обновлений и корректируем это значение; корректировка каждого обновления, в свою очередь, арифметически эквивалентна.

Сначала инициализируйте массивы смещения и веса.

nabla_b = [np.zeros(b.shape) for b in self.biases]                #Initialize bias matrix with 0's
nabla_w = [np.zeros(w.shape) for w in self.weights]               #Initialize weights matrix with 0's

Для каждого наблюдения в мини-матче вставьте результат тренировки в массивы смещения и веса

for x, y in mini_batch:                                           #For tuples in one mini_batch
    delta_nabla_b, delta_nabla_w = self.backprop(x, y)            #Calculate partial derivatives of bias/weights with backpropagation, set them to delta_nabla_b
    nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] #Generate a list with partial derivatives of bias of every neuron
    nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] #Generate a list with partial derivatives of weights for every neuron

Наконец, отрегулируйте каждый вес и уклон, изменяя значение для каждого из результатов тренировки, по очереди.

self.weights = [w-(eta/len(mini_batch))*nw                        #Update weights according to update rule
                for w, nw in zip(self.weights, nabla_w)]          #What author does is he zips 2 lists with values he needs (Current weights and partial derivatives), then do computations with them.
self.biases = [b-(eta/len(mini_batch))*nb                         #Update biases according to update rule
               for b, nb in zip(self.biases, nabla_b)]
Другие вопросы по тегам