Регуляризация отсева
Чтобы предотвратить проблему переобучения, наиболее часто используемым методом является регуляризация L2, то есть добавление члена регуляризации L2 после функции стоимости. Про регуляризацию L2 я много раз рассказывал в предыдущем блоге, поэтому повторяться здесь не буду. В этом блоге в основном представлена регуляризация отсева (регуляризация отсева), предложенная Шриваставой в 2014 году:Dropout: A Simple Way to Prevent Neural Networks from Overtting. Идея Dropout на самом деле очень проста и груба: для каждого слоя сети случайным образом отбрасываются какие-то единицы. Как показано ниже (изображение из отсева Шриваставы):
Относительно того, почему отсев может облегчить переоснащение, ng дает еще два интуитивно понятных объяснения:
- Именно потому, что некоторые единицы случайным образом отбрасываются в каждом слое, обученная сеть намного меньше, чем обычная сеть, что в определенной степени объясняет проблему предотвращения переобучения.
- Простая однослойная сеть, как показано на рисунке ниже, поскольку каждый признак может быть отброшен, вся сеть не будет смещена в сторону определенного признака (весу определенного признака присваивается большое значение), и каждый признак будет Веса назначаются очень маленькими, что несколько похоже на регуляризацию L2, которая может уменьшить переоснащение.
Этот метод может показаться сумасшедшим, но он работает. Давайте начнем рассматривать отсев регулярного члена с точки зрения технической реализации, наиболее важным параметром здесь является, называется зарезервированная вероятность (опять же,– вероятность падения), например, это означает, что слой случайным образом сохраняет 80 % нейронных единиц (то есть 20 % единиц отбрасываются). Обычно отсев реализован Техника регуляризации называется Инвертированное отсев, предполагая, что для третьего слоя конкретная реализация инвертированного отсева:
1. d3 = np.random.rand(a3.shape[0],a3.shape[1]) < keep_prob
2. a3 = np.multiply(a3,d3)
3. a3 = a3 / keep_prob
4. z4 = np.dot(w4,a3) + b4
Несколько замечаний по инструкциям для описанных выше шагов:
Шаг 1, создайте новый размер иТа же матрица вероятностей, по сути, тот же код, потому что каждый раз это случайное число, его можно сохранить только приблизительнотак много, как,Возможно, d3 составляет всего 79% от 1, что означает, что сохраняется только 79% единиц, но чем больше количество единиц скрытого слоя, тем ближе оно к 80%.
Шаг 2,иТочечное умножение, т.е. сохранениеединицы, остальноеблок деактивирован.
Шаг 3, потому что естьустройство отключено, поэтомуожидания снижаются, поэтому мы используем,такожидания остаются неизменными. Это перевернутый дропаут.
Вот для чего предназначен перевернутый дропаут. Следующие две динамические диаграммы используются для демонстрации процесса отсева (материал взят из класса глубокого обучения ng):
Далее мы в основном сосредоточимся на реализации кода. Предположим, что наша функция активации сети использует relu, а выходной слой использует сигмоид. Нам нужно использовать только переднийПошаговый почерк нейронной сетиНа основе прямого распространения (forward propagation) и обратного распространения (backward propagation) немного изменены:
Прямое распространение
def forward_propagation_with_dropout(X, parameters, keep_prob = 0.8):
"""
X -- input dataset, of shape (input size, number of examples)
parameters -- python dictionary containing your parameters "W1", "b1", "W2", "b2",...,"WL", "bL"
W -- weight matrix of shape (size of current layer, size of previous layer)
b -- bias vector of shape (size of current layer,1)
keep_prob: probability of keeping a neuron active during drop-out, scalar
:return:
AL: the output of the last Layer(y_predict)
caches: list, every element is a tuple:(W,b,z,A_pre)
"""
np.random.seed(1) #random seed
L = len(parameters) // 2 #number of layer
A = X
caches = [(None,None,None,X,None)] #用于存储每一层的,w,b,z,A,D第0层w,b,z用none代替
# calculate from 1 to L-1 layer
for l in range(1, L):
A_pre = A
W = parameters["W" + str(l)]
b = parameters["b" + str(l)]
z = np.dot(W, A_pre) + b # 计算z = wx + b
A = relu(z) # relu activation function
D = np.random.rand(A.shape[0], A.shape[1]) #initialize matrix D
D = (D < keep_prob) #convert entries of D to 0 or 1 (using keep_prob as the threshold)
A = np.multiply(A, D) #shut down some neurons of A
A = A / keep_prob #scale the value of neurons that haven't been shut down
caches.append((W, b, z, A,D))
# calculate Lth layer
WL = parameters["W" + str(L)]
bL = parameters["b" + str(L)]
zL = np.dot(WL, A) + bL
AL = sigmoid(zL)
caches.append((WL, bL, zL, A))
return AL, caches
обратное распространение
def backward_propagation_with_dropout(AL, Y, caches, keep_prob = 0.8):
"""
Implement the backward propagation presented in figure 2.
Arguments:
X -- input dataset, of shape (input size, number of examples)
Y -- true "label" vector (containing 0 if cat, 1 if non-cat)
caches -- caches output from forward_propagation(),(W,b,z,pre_A)
keep_prob: probability of keeping a neuron active during drop-out, scalar
Returns:
gradients -- A dictionary with the gradients with respect to dW,db
"""
m = Y.shape[1]
L = len(caches) - 1
# print("L: " + str(L))
# calculate the Lth layer gradients
prev_AL = caches[L - 1][3]
dzL = 1. / m * (AL - Y)
dWL = np.dot(dzL, prev_AL.T)
dbL = np.sum(dzL, axis=1, keepdims=True)
gradients = {"dW" + str(L): dWL, "db" + str(L): dbL}
# calculate from L-1 to 1 layer gradients
for l in reversed(range(1, L)): # L-1,L-2,...,1
post_W = caches[l + 1][0] # 要用后一层的W
dz = dzL # 用后一层的dz
dal = np.dot(post_W.T, dz)
Dl = caches[l][4] #当前层的D
dal = np.multiply(dal, Dl) #Apply mask Dl to shut down the same neurons as during the forward propagation
dal = dal / keep_prob #Scale the value of neurons that haven't been shut down
Al = caches[l][3] #当前层的A
dzl = np.multiply(dal, relu_backward(Al))#也可以用dzl=np.multiply(dal, np.int64(Al > 0))来实现
prev_A = caches[l-1][3] # 前一层的A
dWl = np.dot(dzl, prev_A.T)
dbl = np.sum(dzl, axis=1, keepdims=True)
gradients["dW" + str(l)] = dWl
gradients["db" + str(l)] = dbl
dzL = dzl # 更新dz
return gradients
Есть несколько вещей, которые следует отметить в отношении отсева:
- Используйте отсев только при обучении сети, не используйте отсев на тестовом наборе (при прогнозировании), что означает, что когда мы используем обученные параметры для прямого распространения при прогнозировании (классификации), нам нужно использовать отсев!
- отсев - это метод регуляризации
Давайте проведем простое сравнение в наборе данных load_breast_cancer в sklean, сети без регулярного термина, сети с обычным термином L2 и сетевом эффекте с отсевом:
Сеть без регулярного члена, точность: 0,912
Сеть регулярного члена L2, показатель точности: 0,921
Сеть выпадающих регулярных терминов, показатель точности: 0,929
Полный код выложен на github:
Сеть с обычным термином L2:deep_neural_network_with_L2
Сеть с отсевом обычного срока:deep_neural_network_with_dropout