【问题标题】:RNN Training Loss Goes Down Then Acts ErraticallyRNN 训练损失下降,然后行为不正常
【发布时间】:2017-12-04 20:39:36
【问题描述】:

我一直在尝试在 Python 3.6 中创建一个普通的 3 层 RNN,但是每当我训练它时,前 X 次训练迭代的训练损失都会减少,然后偶尔会上下波动,我无法确定问题所在.我暂时不想使用 Tensorflow 或 Keras 或任何深度学习框架,因为我试图更好地了解这些 NN 的工作原理。

我很确定我的问题在于我在前向道具函数中添加矩阵的方式,或者在我的反向道具函数的获取错误和权重更新部分,因此我将在下面发布它们。

对不起,如果我的代码有点乱,但这是我通过我的神经网络转发道具的函数。

def RNN_forward(self, A):

    #input layer
    self.A = A

    #self.AB is a-b weight matrix
    self.B1 = np.dot(self.A, self.AB)

    #self.B_t is self.B (layer 2) from the previous timestep
    self.B_t1 = np.dot(self.B_t, self.B_RNN)

    #combining matrices
    self.B = self.sigmoid((self.B1) + (self.B_t1))
    self.C1 = np.dot(self.B, self.BC)

    #output layer
    self.C = self.sigmoid(self.C1) 
    return self.C

我的反向传播和更新权重矩阵函数被合并为一个函数,抱歉一切都这么混乱

def RNN_backprop(self, C_real):

    #did this so I could transpose a 1D matrix
    BT = self.B[np.newaxis]

    #get error of BC weight matrix
    delta3 = np.multiply(-(C_real-self.C), self.sigmoidPrime(self.C1))
    BCp = np.dot(BT.T, delta3)
    BCpT = BCp[np.newaxis]

    #get error of AB weight matrix
    delta2 = np.dot(delta3, self.BC.T)*self.sigmoidPrime(self.B1) 
    AT, d2 = self.A[np.newaxis], delta2[np.newaxis]
    ABp = np.dot(AT.T, d2)

    #get error of weight matrix linked to previous time step
    delta2t = np.dot(delta3, self.BC.T)*self.sigmoidPrime(self.B_t1) 
    B_RNNT, d2t = self.B_t[np.newaxis], delta2t[np.newaxis]
    B_RNNp = np.dot(B_RNNT.T, d2t)

    #training speed
    weight_multiplier = 10

    #update weight matricies
    self.BC = self.BC - BCpT.T*weight_multiplier 
    self.AB = self.AB - ABp*weight_multiplier 
    self.B_RNN = self.B_RNN - B_RNNp*weight_multiplier             

    #store layer 2 to be used in next timestep
    self.B_t = self.B

我很高兴发布整个代码或任何其他人可能需要帮助诊断我的问题的任何内容。

提前感谢您提供的任何建议或可能的解决方案!

编辑:这是整个代码:它的注释真的很差,所以很难阅读它,但它都在这里。有些行被注释掉只是因为我不确定我是否会尝试使用它们。

将 numpy 导入为 np

类NN(对象):

def __init__(self):
    self.A_size = 4
    self.B_size = 6
    self.C_size = 1

def init_weights(self):
    self.AB = np.random.randn(self.A_size, self.B_size)
    self.BC = np.random.randn(self.B_size, self.C_size)
    self.B_t = [0]
    self.B_RNN = np.random.randn(self.B_size, self.B_size)

def sigmoid(self, X1):
    return 1/(1+np.exp(-X1))

def sigmoidPrime(self,X1):
    return np.exp(-X1)/((1+np.exp(-X1))**2)

def print_status(self, NN_type):
    print("---------Status---------")
    print("A: ", self.A)
    print("AB: ", self.AB)
    print("B: ", self.B)
    print("BC: ", self.BC)
    print("C: ", self.C)
    if NN_type == "RNN":
        print("Previous B: ", self.B_t)
    if NN_type == "LSTM":
        pass        
    #print("Error: ", self.cost)
    print("---------Done---------")

def RNN_forward(self, A):
    self.A = A
    self.B1 = np.dot(self.A, self.AB)
    if len(self.B_t) > 2:
        self.B_t1 = np.dot(self.B_t, self.B_RNN)
        self.B = self.sigmoid((self.B1) + (self.B_t1))
        #self.B = self.sigmoid(np.tanh(self.B1) + np.tanh(self.B_t1))
    else:
        self.B = self.sigmoid(self.B1)
        self.B_t = self.B
        self.B_t1 = np.dot(self.B_t, self.B_RNN)
        print('this should only print once')
    self.C1 = np.dot(self.B, self.BC)
    self.C = self.sigmoid(self.C1) 
    return self.C

def skip_backprop(self):
    self.B_t = self.B

def get_cost(self, C_real):
    #self.cost = 0.5*sum((C_real-self.C)**2)
    self.cost = 0.5*((C_real-self.C)**2)
    return self.cost

def RNN_backprop(self, C_real):
    BT = self.B[np.newaxis]
    delta3 = np.multiply(-(C_real-self.C), self.sigmoidPrime(self.C1))
    BCp = np.dot(BT.T, delta3)
    BCpT = BCp[np.newaxis]

    delta2 = np.dot(delta3, self.BC.T)*self.sigmoidPrime(self.B1) 
    AT, d2 = self.A[np.newaxis], delta2[np.newaxis]
    ABp = np.dot(AT.T, d2)

    delta2t = np.dot(delta3, self.BC.T)*self.sigmoidPrime(self.B_t1) 
    B_RNNT, d2t = self.B_t[np.newaxis], delta2t[np.newaxis]
    B_RNNp = np.dot(B_RNNT.T, d2t)

    #Important
    #weight_multiplier = 5 * (np.sum(np.absolute(ABp))+np.sum(np.absolute(BCpT))+np.sum(np.absolute(B_RNNp)))
    weight_multiplier = 0.01

    self.BC = self.BC - BCpT.T*weight_multiplier 
    self.AB = self.AB - ABp*weight_multiplier 
    self.B_RNN = self.B_RNN - B_RNNp*weight_multiplier             

    self.B_t = self.B

NN = NN()
NN.init_weights()

#important
iterations = 100000    
for a in range(iterations):
    total_error = 0
    for i in range(50):
        NN.RNN_forward(np.array(As[i]))
        NN.RNN_backprop(C_reals[i])
        total_error += NN.get_cost(C_reals[i])
    if a%500 == 0:    
        print("Error: ",total_error)
NN.RNN_forward(np.array([1,1,1,0.2]))
NN.skip_backprop()
print("0.4: ", NN.RNN_forward(np.array([1,1,1,0.3])))
NN.RNN_forward(np.array([1,1,1,0.4]))
NN.skip_backprop()
print("0.2: ", NN.RNN_forward(np.array([1,1,1,0.3])))

【问题讨论】:

  • self.B_RNN 在第一个代码块中使用之前未定义。在第二个代码块中, weight_multiplier 应该是您的学习率吗?通常学习率要小得多,比如 1e2 或更小
  • self.B_RNN 是在我创建类的实例时定义的,我一直在尝试不同的学习率,但它们似乎都有相同的问题。不过,我会测试一些小得多的学习率,看看是否有帮助!
  • 因为这不是一段功能齐全的代码,所以很难通过检查来尝试了解发生了什么问题。
  • 我发布了整个代码供您查看,如果您愿意的话。此外,我将学习率更改为 0.001、0.01、0.1 和 1,并且所有 4 都有相同的问题。
  • 你为什么要调用 NN.RNN_forward(np.array(As[i])) 然后立即调用 NN.RNN_backprop(C_reals[i]) ?通常我认为 RNN 每个序列有 1 个目标。你向前传播整个输入序列(想想一个句子),然后当你完成后,你反向传播。但是整个序列只有一个目标(如句子的标签)。这是其他用例吗?如果是,请具体说明您要解决的问题类型

标签: python neural-network recurrent-neural-network backpropagation data-loss


【解决方案1】:

消除这种行为的一种常见方法是在您继续训练时降低学习率。 虽然我无法解释,但添加批量标准化有助于我在一个案例中解决这个问题。但我可以在增加网络容量后摆脱它。

【讨论】:

  • 谢谢!到目前为止,这对我有用。我的新学习率定义为: learning_rate = ( ( 2000 / float(iteration_number) ** (1. / 3) ) + (iterations / 1000 ) ) / iterations 其中迭代是总训练迭代,迭代数是它的迭代已开启。
猜你喜欢
  • 1970-01-01
  • 2020-11-27
  • 1970-01-01
  • 1970-01-01
  • 2019-12-29
  • 1970-01-01
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
相关资源
最近更新 更多