Как правильно тренировать и прогнозировать ценность биомассы с помощью GRN RNN? - PullRequest
0 голосов
/ 15 мая 2019

Я впервые пытался обучить набор данных, содержащий 8 переменных, во временном ряду или около того, используя GRN RNN. Значение биомассы - это то, что я пытаюсь предсказать на основе других переменных. Я пытаюсь сначала с 1 слоя ГРУ. Я не использую softmax для выходного слоя. MSE используется для моей функции стоимости.

Это базовая GRU с прямым распространением и обновлением обратного градиента. Вот основная функция, которую я определил:

   'x_t is the input training dataset with a dimension of 7572x8. So T = 7572, input_dim = 8, hidden_dim =128. y_train is my train label.'

   def forward_prop_step(self, x_t,y_train, s_t1_prev,V, U, W, b, c,learning_rate):
       T = x_t.shape[0]
       z_t1 = np.zeros((T,self.hidden_dim))
       r_t1 = np.zeros((T,self.hidden_dim))
       h_t1 = np.zeros((T,self.hidden_dim))
       s_t1 = np.zeros((T+1,self.hidden_dim))
       o_s = np.zeros((T,self.input_dim))
       for i in xrange(T):
           x_e = x_t[i].T
           z_t1[i] = sigmoid(U[0].dot(x_e) + W[0].dot(s_t1[i]) + b[0])#128x1
           r_t1[i] = sigmoid(U[1].dot(x_e) + W[1].dot(s_t1[i]) + b[1])#128x1
           h_t1[i] = np.tanh(U[2].dot(x_e) + W[2].dot(s_t1[i] * r_t1[i]) + b[2])#128x1
           s_t1[i+1] = (np.ones_like(z_t1[i]) - z_t1[i]) * h_t1[i] + z_t1[i] * s_t1[i]#128x1

           o_s[i] = np.dot(V,s_t1[i+1]) + c#8x1
       return [o_s,z_t1,r_t1,h_t1,s_t1]

   def bptt(self, x,y_train,o,z_t1,r_t1,h_t1,s_t1,V, U, W, b, c):
       bptt_truncate = 360
       T = x.shape[0]#length of time scale of input data (train)
       dLdU = np.zeros(U.shape)
       dLdV = np.zeros(V.shape)
       dLdW = np.zeros(W.shape)
       dLdb = np.zeros(b.shape)
       dLdc = np.zeros(c.shape)
       y_train_sp = np.repeat(y_train,self.input_dim)
       for t in np.arange(T)[::-1]:
           dLdy = 2 * (o[t] - y_train_sp[t])
           dydV = s_t1[t]
           dydc = 1.0
           dLdV += np.outer(dLdy,dydV)
           dLdc += dLdy*dydc            
           for i in np.arange(max(0, t-bptt_truncate), t+1)[::-30]:#every month in the past year           
               s_t1_pre = s_t1[i]          
               dydst1 = V #8x128                
               dst1dzt1 = -h_t1[i] + s_t1_pre #128x1
               dst1dht1 = np.ones_like(z_t1[i]) - z_t1[i] #128x1

               dzt1dU = np.outer(z_t1[i]*(1.0-z_t1[i]),x[i]) #128x8
               #print dzt1dU.shape
               dzt1dW = np.outer(z_t1[i]*(1.0-z_t1[i]),s_t1_pre)  #128x128
               dzt1db = z_t1[i]*(1.0-z_t1[i]) #128x1

               dht1dU = np.outer((1.0-h_t1[i] ** 2),x[i]) #128x8
               dht1dW = np.outer((1.0-h_t1[i] ** 2),s_t1_pre * r_t1[i])  #128x128
               dht1db = 1.0-h_t1[i] ** 2 #128x1

               dht1drt1 = (1.0-h_t1[i] ** 2)*(W[2].dot(s_t1_pre))#128x1

               drt1dU = np.outer((r_t1[i]*(1.0-r_t1[i])),x[i]) #128x8
               drt1dW = np.outer((r_t1[i]*(1.0-r_t1[i])),s_t1_pre) #128x128
               drt1db = (r_t1[i]*(1.0-r_t1[i]))#128x1
               dLdW[0] += np.outer(dydst1.T.dot(dLdy),dzt1dW.dot(dst1dzt1)) #128x128
               dLdU[0] += np.outer(dydst1.T.dot(dLdy),dst1dzt1.dot(dzt1dU)) #128x8
               dLdb[0] += (dydst1.T.dot(dLdy))*dst1dzt1*dzt1db#128x1

               dLdW[1] += np.outer(dydst1.T.dot(dLdy),dst1dht1*dht1drt1).dot(drt1dW)#128x128
               dLdU[1] += np.outer(dydst1.T.dot(dLdy),dst1dht1*dht1drt1).dot(drt1dU) #128x8
               dLdb[1] += (dydst1.T.dot(dLdy))*dst1dht1*dht1drt1*drt1db#128x1

               dLdW[2] += np.outer(dydst1.T.dot(dLdy),dht1dW.dot(dst1dht1))  #128x128
               dLdU[2] += np.outer(dydst1.T.dot(dLdy),dst1dht1.dot(dht1dU))#128x8
               dLdb[2] += (dydst1.T.dot(dLdy))*dst1dht1*dht1db#128x1

       return [ dLdV,dLdU, dLdW, dLdb, dLdc ]
   def predict( self, x): 
       pred = np.amax(x, axis = 1)
       pred_f = relu(pred)
       return pred_f


Параметры V , U , W , b , c обновляются градиентом dLdV , dLdU , dLdW , dLdb , dLdc , рассчитанный по bptt .

Я пробовал другую инициализацию веса (xavier или просто случайную), пробовал другое усечение времени. Но все приводят к одинаковому результату. Возможно, обновление веса не было правильным? Настройка сети кажется простой, хотя. Действительно бороться за понимание предикации и перевести на фактическую биомассу тоже. Функция предсказание - это то, что я определил, чтобы преобразовать выходной слой из сети GRU в значение биомассы, приняв максимальное значение. Но выходной слой дает одинаковое значение практически для всех временных итераций. Не уверен, что лучший способ сделать работу, хотя. Спасибо за любую помощь или предложения заранее.

1 Ответ

0 голосов
/ 15 мая 2019

Я сомневаюсь, что кто-нибудь в stackoverflow собирается отладить пользовательскую реализацию GRU для вас. Если бы вы использовали Tensorflow или другую высокоуровневую библиотеку, я мог бы попытаться сделать это, или если бы это была простая полностью подключенная сеть, но все, что я могу сделать, это дать несколько советов о том, как приступить к отладке.

Во-первых, похоже, что вы запускаете совершенно новую реализацию своего собственного набора данных с самого начала. Вместо этого попробуйте сначала протестировать свою сеть на тривиальных синтетических наборах данных. Может ли он выучить функцию идентичности? Ответ, который является просто средневзвешенным значением трех предыдущих отметок времени? И так далее. Легче отлаживать небольшие простые проблемы. Как только вы узнаете, что ваша реализация может изучать то, что должна изучать рекуррентная сеть на основе GRU, вы можете начать использовать свои собственные данные.

Во-вторых, ваш комментарий был очень проницательным:

Возможно, обновление веса было неправильным?

Хотя невозможно сказать наверняка, это очень распространенный - возможно, самый распространенный источник ошибок для реализаций backprop. Эндрю Нг рекомендует проверку градиента для отладки подобной реализации. По сути, это предполагает численное приближение градиента. Это вычислительно неэффективно, но опирается только на правильную реализацию прямого распространения, что делает его очень полезным для отладки. С одной стороны, если алгоритм сходится при использовании числового аппроксимированного градиента, вы можете быть более уверены, что ваша прямая опора правильна, и сосредоточиться на отладке backprop. (С другой стороны, если это все еще не удается, скорее всего, это проблема вашей прямой функции поддержки.) С другой стороны, если алгоритм работает с численно аппроксимированным градиентом, вы можете сравнить выходные данные своей аналитической функции градиента. с этим и отлаживать любые расхождения. Это делает это намного проще, потому что теперь вы знаете правильный ответ, что он должен вернуть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...