如何使用迷你批次代替SGD

时间:2016-11-20 22:27:59

标签: python machine-learning neural-network

这是python中单层神经网络的快速实现:

import numpy as np

# simulate data
np.random.seed(94106)
X = np.random.random((200, 3)) # 100 3d vectors
# first col is set to 1
X[:, 0] = 1
def simu_out(x):
    return np.sum(np.power(x, 2))
y = np.apply_along_axis(simu_out, 1, X)
# code 1 if above average
y = (y > np.mean(y)).astype("float64")*2 - 1
# split into training and testing sets
Xtr = X[:100]
Xte = X[100:]
ytr = y[:100]
yte = y[100:]
w = np.random.random(3)

# 1 layer network. Final layer has one node
# initial weights,
def epoch():
    err_sum = 0
    global w
    for i in range(len(ytr)):
        learn_rate = .1
        s_l1 = Xtr[i].T.dot(w) # signal at layer 1, pre-activation
        x_l1 = np.tanh(s_l1) # output at layer 1, activation
        err = x_l1 - ytr[i]
        err_sum += err
        # see here: https://youtu.be/Ih5Mr93E-2c?t=51m8s
        delta_l1 = 2 * err * (1 - x_l1**2)
        dw = Xtr[i] * delta_l1
        w -= learn_rate * dw
    print("Mean error: %f" % (err_sum / len(ytr)))
epoch()
for i in range(1000):
    epoch()

def predict(X):
    global w
    return np.sign(np.tanh(X.dot(w)))

# > 80% accuracy!!
np.mean(predict(Xte) == yte)

使用随机梯度下降进行优化。我在想如何在这里应用小批量梯度下降?

1 个答案:

答案 0 :(得分:2)

与“经典”SGD到小批量梯度下降的区别在于您使用多个样本(所谓的小批量)来计算w的更新。这样做的好处是,当你遵循平滑的渐变时,你在解决方向上采取的步骤会减少噪音。

要做到这一点,您需要一个内部循环来计算更新dw,您可以在其中迭代迷你批次。例如(快速脏代码):

def epoch(): 
    err_sum = 0
    learn_rate = 0.1
    global w
    for i in range(int(ceil(len(ytr) / batch_size))):
        batch = Xtr[i:i+batch_size]
        target = ytr[i:i+batch_size]
        dw = np.zeros_like(w)
        for j in range(batch_size):
            s_l1 = batch[j].T.dot(w)
            x_l1 = np.tanh(s_l1)
            err = x_l1 - target[j]
            err_sum += err
            delta_l1 = 2 * err * (1 - x_l1**2)
            dw += batch[j] * delta_l1
        w -= learn_rate * (dw / batch_size)
    print("Mean error: %f" % (err_sum / len(ytr)))

在测试中给出了87%的准确度。

现在,还有一件事:你总是从头到尾经历训练集。你应该在每次迭代中 shuffle 数据。始终以相同的顺序进行操作会影响您的表现,尤其是首先是A级的所有样本,然后是B级的所有样本。这也可以让你的训练循环进行。所以只需按随机顺序浏览该集,例如与

order = np.random.permutation(len(ytr))

并在i函数中将所有order[i]替换为epoch()

更一般的说法:全局变量通常被认为是糟糕的设计,因为您无法控制哪些代码段修改变量。而是将w作为参数传递。学习率和批量大小也是如此。