2017-06-20 20 views
3

我正在用python在TensorFlow中編寫優化程序。計算優化器中連接到相同神經元的張量值子集的值

如何計算作爲神經元輸入連接連接的張量值子集的值?


例如,讓我們用動量項隨機梯度下降優化。動量項是針對每個連接單獨計算的。現在我想通過計算連接到同一神經元的連接的所有動量值的平均值來計算一個連接的動量。

Example connections

在這張照片中,可以看到兩個連接,它們都連接到神經元3作爲傳入的連接。兩個連接都應考慮用於一個連接的權重更新。正常情況下,連接更新(1,3)只包含梯度(1,3)和動量(1,3)。爲了更新連接(1,3),我想使用動量(1,3)和動量(2,3)的平均值。

讓我們來看看一個輸入神經元,兩個隱含層,每個隱含層和一個輸出神經元兩個神經元一個簡單的完全連接的神經網絡:

Example Neural Network

如果我們看一下正常計算對於神經元2和神經元5之間的連接權重更新的動量(在代碼中稱爲「積累」),我們只考慮最後一次的動量。

我們可以看到正常的「積累」更新從下面的Python實現計算:

accumulation = self.get_slot(var, "a") 
accumulation_update = grad + (mu_t * accumulation) 

對於神經元2和神經元5積累之間的連接是這樣的:

accumulationUpdate_{2,5} = grad_{2,5} + (\mu * accumulation_{2,5})

這是應該改變的部分。新的動量計算應該將所有連接的平均值作爲傳入連接連接到與計算權重更新的連接相同的神經元。查看示例神經網絡,連接(2,5)的「累積」值是連接(2,5)和(3,5)的「累積」值的平均值。這些都是神經元5的傳入連接。

的「累積」更新以如下方式變化:

accumulation = self.get_slot(var, "a") 
accumulation_means = # Code to calculate all mean values for all neurons 
accumulation_update = grad + (mu_t * accumulation_means) # Use the means for the accumulation_update 

用於連接的累積更新計算(2,5)現在被計算方式如下:

accumulation_mean = (accumulation(2, 5) + accumulation(3, 5))/2 
accumulation_update(2, 5) = grad(2, 5) + (mu_t * accumulation_mean) 

該計算對於每個連接都以相同的方式完成:

calculation for all connections

這裏的Python實現隨機梯度下降的動量:

from __future__ import absolute_import 
from __future__ import division 
from __future__ import print_function 

from tensorflow.python.framework import ops 
from tensorflow.python.ops import control_flow_ops 
from tensorflow.python.ops import math_ops 
from tensorflow.python.ops import state_ops 
from tensorflow.python.training import optimizer 


class SGDmomentum(optimizer.Optimizer): 
    def __init__(self, learning_rate=0.001, momentum_term=0.9, use_locking=False, name="SGDmomentum"): 
     super(SGDmomentum, self).__init__(use_locking, name) 
     self._lr = learning_rate 
     self._mu = momentum_term 

     self._lr_t = None 
     self._mu_t = None 

    def _create_slots(self, var_list): 
     for v in var_list: 
      self._zeros_slot(v, "a", self._name) 

    def _apply_dense(self, grad, var): 
     lr_t = math_ops.cast(self._lr_t, var.dtype.base_dtype) 
     mu_t = math_ops.cast(self._mu_t, var.dtype.base_dtype) 
     accumulation = self.get_slot(var, "a") 

     accumulation_update = grad + (mu_t * accumulation) 
     accumulation_t = state_ops.assign(accumulation, accumulation_update, use_locking=self._use_locking) 

     var_update = lr_t * accumulation_t 
     var_t = state_ops.assign_sub(var, var_update, use_locking=self._use_locking) 

     return control_flow_ops.group(*[var_t, accumulation_t]) 

    def _prepare(self): 
     self._lr_t = ops.convert_to_tensor(self._lr, name="learning_rate") 
     self._mu_t = ops.convert_to_tensor(self._mu, name="momentum_term") 

的神經網絡我與(MNIST)測試:https://github.com/tensorflow/tensorflow/blob/r1.2/tensorflow/examples/tutorials/mnist/mnist_with_summaries.py

如何實現的「積累」的價值觀所描述的平均值到現有的MWE代碼中?


正如一個側面說明:

的MWE是不是我的真實生活場景。這只是一個最小的工作示例,用於解釋和解決我試圖解決的問題。

我在Python中編寫優化程序,因爲我無法在Windows上構建TensorFlow,因此無法編譯C++文件。我確實花了很多時間試圖在Windows上構建,我不能浪費更多時間。 Python中的優化器對我來說已經足夠了,因爲我現在只是進行原型設計。

我是tensorflow和python的新手。在文檔中我找不到有關此主題的任何內容。將我與源聯繫起來會很好。張量的內部結構對我來說也是難以理解的,我在嘗試某些事情時得到的錯誤信息對我來說是無法理解的。解釋一些事情時請記住這一點。

+0

目前尚不清楚你在1-2個句子中想要實現的內容? – denfromufa

+0

目前尚不清楚您計劃如何使用這些累計值。 –

+0

所以你的想法是用另一種形式的動量實現一個新的SGD算法?在新算法中,一個變量「x」的積累(動量的新形式)是所有變量的積累的平均值,它們具有與「x」相同的輸出神經元。如果我理解你的算法是正確的,那麼假設我們已經得到了傳統的動量(與權重矩陣形狀相同的矩陣),那麼你希望的'x'積累就是同一行中所有元素的平均值'x'。不是嗎? – Seven

回答

1

我們以神經元2,3,4,5爲例來計算新的動量。我們忽略的偏見,只考慮權重:

enter image description here

我們使用W¯¯爲權重矩陣,W¯¯相應的梯度,中號爲相應的矩陣動量,\ {m} {M}}是平均矩陣。

enter image description here

這樣的新勢頭更新

enter image description here

我在你提出的SGDmomentum類改變了一些代碼,並在MNIST例如運行沒有錯誤,我想你已經完成了。

def _apply_dense(self, grad, var): 
    lr_t = math_ops.cast(self._lr_t, var.dtype.base_dtype) 
    mu_t = math_ops.cast(self._mu_t, var.dtype.base_dtype) 
    accumulation = self.get_slot(var, "a") 

    param_dims = len(accumulation.get_shape().as_list()) 
    if param_dims == 2: # fc layer weights 
     accumulation_mean = tf.reduce_mean(accumulation, axis=1, keep_dims=True) 
    elif param_dims == 1: # biases 
     accumulation_mean = accumulation 
    else: # cnn? or others 
     # TODO: improvement 
     accumulation_mean = accumulation 

    accumulation_update = grad + (mu_t * accumulation_mean) # broadcasting is supported by tf.add() 
    accumulation_t = state_ops.assign(accumulation, accumulation_update, use_locking=self._use_locking) 

    var_update = lr_t * accumulation_t 
    var_t = state_ops.assign_sub(var, var_update, use_locking=self._use_locking) 

    return control_flow_ops.group(*[var_t, accumulation_t]) 

培訓,

with tf.name_scope('train'): 
    train_step = SGDmomentum(FLAGS.learning_rate, 0.9).minimize(cross_entropy) 
    # train_step = tf.train.AdamOptimizer(FLAGS.learning_rate).minimize(
    #  cross_entropy) 

目前,該算法收斂比上MNIST勢頭傳統SGD不快。

至於額外的閱讀來源,我不知道斯坦福CS231n是否可以幫助你Gradient DescentSGD with momentum。可能你已經知道了。

如果您仍然對梯度張量的矩陣結構的使用感到困惑,那麼嘗試接受它,因爲它在這裏的矩陣和單個標量之間幾乎沒有區別。

我在這裏所做的只是將您的問題中每個accumulationUpdate_*的計算轉換爲矩陣形式。

+0

我真的很困惑你的答案。對我而言,梯度張量具有與您所顯示的矩陣相似的結構對我來說是新的。你有沒有這方面的信息來源,你如何在實際的張量優化器(我的問題中的MWE)中使用這個解決方案? – Spen

+0

在實現中,梯度張量具有相同的形狀,使得可以容易地執行張量相加,並且每個元素對應於權重矩陣中的變量的計算梯度。對於MWE,'accumulate = tf.reduce_mean(accumulate,axis = 1,keepdims = True)'和'accumulation_update = grad +(mu_t * accumulation)'可以幫助解決問題,這在'numpy'中沒有錯誤。但如果我誤解了你的問題,... – Seven

+0

我認爲你確實理解我的問題是正確的。有些額外的資料可以幫助我理解它。它不能與我正在測試的mnist網絡一起工作(偏向維度爲1,減少失敗並出現錯誤):測試網絡:https://github.com/tensorflow/tensorflow/blob/r1.2/tensorflow/examples /tutorials/mnist/mnist_with_summaries.py – Spen