我创建了一个神经网络并尝试对其进行训练,一切顺利,直到我添加了偏差。
据我了解,在训练过程中,偏差会调整以使预期输出向上或向下移动,而权重则倾向于一个有助于YHat模拟某种函数的值,因此对于一个两层网络来说:
output = tanh(tanh(X0W0 + b0)W1 + b1)
在实际操作中,我发现W将所有权重设置为接近0,而b几乎是训练输出Y的回声。这基本上使得输出对训练数据完美工作,但当你输入不同类型的数据时,它总是会给出相同的输出。
这引起了相当大的困惑。我知道偏差的作用是将激活图向上或向下移动,但在训练时,它似乎使整个神经网络的目的变得无关紧要。以下是我训练方法的代码:
def train(self, X, Y, loss, epoch=10000): for i in range(epoch): YHat = self.forward(X) loss.append(sum(Y - YHat)) err = -(Y - YHat) for l in self.__layers[::-1]: werr = np.sum(np.dot(l.localWGrad, err.T), axis=1) werr.shape = (l.height, 1) l.adjustWeights(werr) err = np.sum(err, axis=1) err.shape = (X.shape[0], 1) l.adjustBiases(err) err = np.multiply(err, l.localXGrad)
以及调整权重和偏差的代码。(注意:epsilon是我的训练速率,lambda是正则化速率)
def adjustWeights(self, err): self.__weights = self.__weights - (err * self.__epsilon + self.__lambda * self.__weights)def adjustBiases(self, err): a = np.sum(np.multiply(err, self.localPartialGrad), axis=1) * self.__epsilon a.shape = (err.shape[0], 1) self.__biases = self.__biases - a
以下是我对这个网络进行的数学运算。
Z0 = X0W0 + b0X1 = relu(Z0)Z1 = X1W1 + b1X2 = relu(Z1)a = YHat-X2#注意第二部分用于正则化loss = ((1/2)*(a^2)) + (lambda*(1/2)*(sum(W1^2) + sum(W2^2)))
现在是导数
dloss/dW1 = -(YHat-X2)*relu'(X1W1 + b1)X1dloss/dW0 = -(YHat-X2)*relu'(X1W1 + b1)W1*relu'(X0W0 + b0)X0dloss/db1 = -(YHat-X2)*relu'(X1W1 + b1)dloss/db0 = -(YHat-X2)*relu'(X1W1 + b1)W1*relu'(X0W0 + b0)
我猜我做错了什么,但我不知道是什么。我尝试用以下输入训练这个网络
X = np.array([[0.0], [1.0], [2.0], [3.0]])Xnorm = X / np.amax(X)Y = np.array([[0.0], [2.0], [4.0], [6.0]])Ynorm = Y / np.amax(Y)
我得到的输出是:
训练后:shape: (4, 1) [[0. ] [1.99799666] [3.99070622] [5.72358125]] 预期: [[0.] [2.] [4.] [6.]]
看起来很棒…直到你输入其他数据:
shape: (4, 1) [[2.] [3.] [4.] [5.]]
然后我得到:
shape: (4, 1) [[0.58289512] [2.59967085] [4.31654068] [5.74322541]]预期: [[4.] [6.] [8.] [10.]]
我想“这可能是传说中的过拟合”,于是决定加入一些正则化,但即便如此也无法真正解决问题,从逻辑角度看,将偏差设置为等于输出并使权重为零是更快、更优化的做法…有人能解释一下我的思维哪里出了问题吗?
以下是训练后的网络结构,(注意,如果你将输出乘以训练Y的最大值,你将得到预期的输出:)
===========================NeuralNetwork===========================Layers:===============Layer 0 :=============== Weights: (1, 3)[[0.05539559 0.05539442 0.05539159]]Biases: (4, 1)[[0. ] [0.22897166] [0.56300199] [1.30167665]]==============\Layer 0 :==============================Layer 1 :=============== Weights: (3, 1)[[0.29443245] [0.29442639] [0.29440642]]Biases: (4, 1)[[0. ] [0.13199981] [0.32762199] [1.10023446]]==============\Layer 1 :=========================================\NeuralNetwork===========================
图y = 2x在x=0处有一个y截距,因此所有偏差都应该是0,因为我们没有将图向上或向下移动…对吗?
谢谢你读到这里!
编辑:
这是损失图:
编辑2:
我刚刚尝试用单个权重和输出做这个实验,这里是我得到的输出结构:
===========================NeuralNetwork===========================Layers:===============Layer 0 :=============== Weights: (1, 1)[[0.47149317]]Biases: (4, 1)[[0. ] [0.18813419] [0.48377987] [1.33644038]]==============\Layer 0 :=========================================\NeuralNetwork===========================
对于这个输入:
shape: (4, 1) [[2.] [3.] [4.] [5.]]
我得到的输出是:
shape: (4, 1) [[4.41954787] [5.53236625] [5.89599366] [5.99257962]]
而它应该为:
预期: [[4.] [6.] [8.] [10.]]
注意偏差的问题仍然存在,你会认为在这种情况下权重应该是2,偏差应该是0。
回答:
从原始问题中移动的回答
原来我从未正确处理我的训练数据。输入向量:
[[0.0], [1.0], [2.0], [3.0]]
被标准化了,我将这个向量除以输入中的最大值3,因此我得到
[[0.0], [0.3333], [0.6666], [1.0]]
对于输入Y的训练向量,我有
[[0.0], [2.0], [4.0], [6.0]]
我愚蠢地决定对这个向量做同样的事情,但用Y的最大值6:
[[0.0], [0.333], [0.666], [1.0]]
所以基本上我是在说“嘿,网络,模仿我的输入”。这是我的第一个错误。第二个错误是由于对缩放的更多误解造成的。
虽然1是0.333,0.333*2 = 0.666,我然后乘以y的最大值(6)6*0.666 = 2,如果我再次尝试用一组不同的数据,例如:
[[2.0], [3.0], [4.0], [5.0]]
2将是2/5 = 0.4,0.4*2 = 0.8,乘以5将是2,但在现实世界中,我们无法知道5是数据集的最大输出,因此我认为可能是Y训练的最大值,即6,所以不是2/5 = 0.4,0.4*2 = 0.8 * 5,我做了2/5 = 0.4,0.4*2 = 0.8 * 6 = 4.8。
所以我得到了偏差和权重的奇怪行为。因此,在本质上摆脱了标准化后,我可以自由地调整超参数,现在对于基础训练数据的输出:
输入:
X: [[0.] [1.] [2.] [3.]]
我得到的输出是:
shape: (4, 1) [[0.30926124] [2.1030826 ] [3.89690395] [5.6907253 ]]
对于额外的测试数据(未训练):
shape: (4, 1) [[2.] [3.] [4.] [5.]]
我得到的输出是:
shape: (4, 1) [[3.89690395] [5.6907253 ] [7.48454666] [9.27836801]]
所以现在我很满意。我还将我的激活函数改成了leaky relu,因为它应该更适合线性方程(我认为)。我相信通过更多的测试数据和更多的超参数调整,它会完美适应。谢谢大家的帮助。尝试解释我的问题真的让我有了新的视角。