Tensorflow:不規(guī)則張量tf.RaggedTensor學習和測試

關鍵詞:Tensorflow

業(yè)務背景

最近有個需求使用KPRN算法預測一組輸入序列的得分,問題在于不同端點之間的這一組序列數(shù)量不一致,而每一個最小顆粒度序列都需要過一個LSTM層,在LSTM之后歸屬于同一對端點的序列需要合并為一組,例如輸入100個序列在經(jīng)過LSTM+2層全連接之后得到100個值[V1,V2,V3....,V100],然后歸屬于同一組的至需要聚合,比如[[V1, V2], [V3, V4, V5] ,[V100]],此時已經(jīng)不能使用tensorflow的reshape算子,引出不規(guī)則矩陣tf.RaggedTensor

根據(jù)組的id聚合


測試使用tf.RaggedTensor能否完成靜態(tài)圖loss優(yōu)化

工程采用tensorflow 1.X,引入不規(guī)則張量的原因是必須使用全流程使用張量構建靜態(tài)圖,如果因此聚合操作導致中間引入Python集合操作,勢必斷開了靜態(tài)圖導致無法訓練,而要完成聚合操作目前看只能引入不規(guī)則張量。下面一個簡單例子調試下,

  • 每次輸入一個固定數(shù)量比如64端點對的batch,但是一對之間可能有多組序列(特征embedding),因此炸開之后每個batch的序列數(shù)不一樣,比如這批100,下次150,在下次143
  • 每個batch雖然數(shù)量不一樣,但是會同時輸入一個rowids,這個長度也是None,所有rowids里面的最大值應該相同
  • KPRN是每個序列LSTM+兩層全鏈接輸出一個值,本次實驗直接使用一個一層全鏈接輸出一個值代替
  • LSTM+兩層全鏈接之后是logsumexp,本次使用保持一致,并且論文中參數(shù)設置為1
  • 最后套一層sigmod和y值計算交叉熵計算loss,y等于batch聚合分組后的大小
import tensorflow as tf

input_x = tf.placeholder(tf.float32, [None, 5])
input_rowids = tf.placeholder(tf.int64, [None])
input_y = tf.placeholder(tf.float32, [None, 1])

full_connect = tf.layers.dense(input_x, units=1, activation=tf.nn.sigmoid)
agg_layers = tf.RaggedTensor.from_value_rowids(full_connect, value_rowids=input_rowids)
logsumexp_layers = tf.log(tf.reduce_sum(tf.exp(agg_layers), axis=1))
sigmoid_out = tf.sigmoid(logsumexp_layers)
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=input_y, logits=logsumexp_layers))
optimizer = tf.train.AdamOptimizer(learning_rate=0.01)
train_step = optimizer.minimize(loss)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(10):
        full_connect_val, agg_layers_val, logsumexp_layers_val, sigmoid_out_val, loss_val, _ = sess.run(
            [full_connect, agg_layers, logsumexp_layers, sigmoid_out, loss, train_step],
            feed_dict={input_x: [[1.0, 2.0, 3.0, 4.0, -1.0],
                                 [2.0, -2.0, -1.0, 1.0, -2.0],
                                 [3.0, -3.0, 3.0, 2.0, -3.0],
                                 [4.0, 1.0, 3.0, 2.0, 2.0],
                                 [5.0, 1.0, 2.0, 4.0, 3.0]],
                       input_rowids: [0, 0, 0, 1, 1],
                       input_y: [[1.0], [0.0]]})
        print(full_connect_val)
        print(agg_layers_val)
        print(logsumexp_layers_val)
        print(sigmoid_out_val)
        print("loss:", loss_val)
        print("---------------")

運行輸出最后一輪迭代如下

[[0.67166984]
 [0.7236427 ]
 [0.82996327]
 [0.12828942]
 [0.04120561]]
<tf.RaggedTensorValue [[[0.6716698408126831], [0.7236427068710327], [0.8299632668495178]], [[0.12828941643238068], [0.04120561480522156]]]>
[[1.8425585]
 [0.7788424]]
[[0.86325103]
 [0.6854306 ]]
loss: 0.6518001
---------------

整體沒有問題可以跑通進行l(wèi)oss迭代

以上代碼主要是這一行,其他都是小場面

agg_layers = tf.RaggedTensor.from_value_rowids(full_connect, value_rowids=input_rowids)

tf.RaggedTensor.from_value_rowids輸入了兩個tensor,一個tensor是上一個操作產(chǎn)生的tensor,在例子中那就是全鏈接之后的向量,另一個tensor是每一個輸入所屬的組號,組號從0開始,如果某個組元素為空則直接跳過這個組號往后寫。因此在這個地方解決了炸開之后的每個最小顆粒度輸入,在經(jīng)過神經(jīng)網(wǎng)絡變化之后,如果再根據(jù)分組號聚合改變形狀的問題。
tf.RaggedTensor支持大部分tensorflow的運算,但是本例子不支持tf.reduce_logsumexp

logsumexp_layers = tf.reduce_logsumexp(agg_layers)

TypeError: Failed to convert object of type <class 'tensorflow.python.ops.ragged.ragged_tensor.RaggedTensor'> to Tensor. Contents: tf.RaggedTensor(values=Tensor("dense/Sigmoid:0", shape=(?, 1), dtype=float32), row_splits=Tensor("RaggedFromValueRowIds_2/concat_1:0", shape=(?,), dtype=int64)). Consider casting elements to a supported type.

因此本例子手動使用tf的其他簡單操作實現(xiàn)


tf.RaggedTensor官方文檔學習

參考這個https://tensorflow.google.cn/guide/ragged_tensor

tensorflow文檔

(1)構造不規(guī)則張量

最簡單方式是使用 tf.ragged.constant,它會構建與給定的嵌套 Python list 或 NumPy array 相對應的 RaggedTensor

>>> tf.ragged.constant([[1, 2, 3], [2, 3]])
tf.RaggedTensor(values=Tensor("RaggedConstant/values:0", shape=(5,), dtype=int32), row_splits=Tensor("RaggedConstant/Const:0", shape=(3,), dtype=int64))

除此之外還可以通過將扁平的值張量行分區(qū)張量進行配對來構造不規(guī)則張量,行分區(qū)張量使用 tf.RaggedTensor.from_value_rowids、tf.RaggedTensor.from_row_lengthstf.RaggedTensor.from_row_splits,本例就是采用的from_value_rowids
文檔里面說扁平的值張量測試就算不是值張量,只要是規(guī)則的多維矩陣都可以使用這種轉化為不規(guī)則的張量

>>> b = tf.RaggedTensor.from_value_rowids(values=[[1, 2], [3, 4], [5, 6]], value_rowids=[0,0,1])
>>> with tf.Session() as sess:
...     print(sess.run(b))
... 
<tf.RaggedTensorValue [[[1, 2], [3, 4]], [[5, 6]]]>

另外輸入values可以是python集合,也可以是自定義的另外一個規(guī)則的tensor。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容