對(duì)于 tf.get_variable() vs tf.Variable(),tf.name_scope() vs tf.variable_scope()
最近剛接手tf,有些函數(shù),理解不清楚,做一下筆記。
對(duì)于函數(shù),知道平時(shí)的用法就行了,不用糾結(jié)里面的每一個(gè)參數(shù)的意思,基本用不到,還浪費(fèi)時(shí)間
一、name-scope 和 variable-scope
name-scope 和 variable-scope 都是命名空間,意思就是,定義一個(gè)空間,在這個(gè)空間里面的,定義的變量,基本都會(huì)以這個(gè)命名空間作為其變量名的前綴。(但是也有例外)
比如下圖中,盡管是兩段代碼,但都是在variable-scope定義的名稱(chēng)為“V1”的空間中。而reuse命令,允許共享當(dāng)前scope(同一個(gè)命名空間)下的所有變量,所以a1和a3的變量名都是 V1/a1:0
import tensorflow as tf
import numpy as np
with tf.variable_scope('V1'):
a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1))
with tf.variable_scope('V1', reuse=True):
a3 = tf.get_variable('a1')
- name_scope對(duì) get_variable()創(chuàng)建的變量 的名字不會(huì)有任何影響,而創(chuàng)建的op會(huì)被加上前綴.
- tf.get_variable_scope() 返回的只是 variable_scope,不管 name_scope.所以以后我們?cè)谑褂胻f.get_variable_scope().reuse_variables() 時(shí)可以無(wú)視name_scope
- name_scope 是給op_name加前綴, variable_scope是給get_variable()創(chuàng)建的變量的名字加前綴。
二 、tf 的 reduce(降維)操作
1. 基礎(chǔ)理解
1.1 向量的“維”
這里加入基礎(chǔ)理解的意思,是為了防止概念不清晰。
比如若說(shuō)X是一個(gè)n維向量,表示X中,含有n個(gè)元素,可以在n維坐標(biāo)系中表示出來(lái)(原點(diǎn)到X坐標(biāo)的向量)。另外,在機(jī)器學(xué)習(xí)的降維中,是把X從n維降到k維。 ---但這不是tf中的‘‘降維”
n維向量!= n維數(shù)組!!!
1.2 tf中的“維”
在tf中,用constant定義的tensor
- 0維數(shù)組,表示一個(gè)數(shù),如:6。(可以理解為“點(diǎn)”)
- 1維數(shù)組,表示一個(gè)a = [1,2,3]。(可以理解為“線(xiàn)”,這也和上面的向量聯(lián)系起來(lái)了。一方面,這是一個(gè)三維向量,另一方面,在n維坐標(biāo)系中,向量是一條直線(xiàn),是“線(xiàn)”)
- 2維數(shù)組,表示一個(gè)
b = [[1,2,3],
[4,5,6]]。(可以理解為“面”,或者矩陣) - 3維數(shù)組,表示一個(gè)
c = [[[1,2,3],[4,5,6]],
[[7,8,9],[1,1,1]],
[[2,2,2],[3,3,3]]]
可以理解為“體”。
1.3 對(duì)數(shù)組進(jìn)行索引
索引,類(lèi)似于Python中的列表索引,0表示第一個(gè)元素,但又不一樣。
比如,對(duì)上面的2維數(shù)組b進(jìn)行索引 ,得到
b[0] = [1,2,3],
c[0] = [[1.2.3].[4.5.6]] (都是數(shù)組里的第一個(gè)元素)
1.4 tf.reduce_xxx操作中的axis
因?yàn)榘姹镜牟煌袝r(shí)參數(shù)axis(軸)等同于參數(shù)reduction_indices(減去索引)
這里所說(shuō)的,應(yīng)該是側(cè)重于axis軸的意思
這里作者就按照坐標(biāo)軸來(lái)理解。比如,上面的三維數(shù)組c,我把它理解為由x,y,z軸組成的坐標(biāo)系中的三個(gè)自變量組成的“體”,c的0維就相當(dāng)于x變量,剩下的由y和z兩個(gè)組成的幾個(gè)平面,也就是剩下的3個(gè)二維數(shù)組。這里的“c的0維”不等于“c[0]”。
那么。去掉c的0維,就相當(dāng)于只剩下y,z兩個(gè)變量組成的三個(gè)平面。
reduc_sum(c,0)那就理解為,先把三個(gè)平面相加,再去掉x自變量。
所以,就相當(dāng)于,先把每個(gè)第0維里面的元素(即三個(gè)二維數(shù)組)按照規(guī)則相加,再去掉最外面的“0維”。于是,最后剩一個(gè)二維數(shù)組。
最外面的中括號(hào)代表了第0維,再往里代表了第1維(比如[[1,2,3],[4,5,6]],第一維里面的元素相加,就是[1,2,3]+[4,5,6]),再往里代表了第2維(比如[1,2,3].)
1.5 代碼
具體別的情況,就看下面代碼。其中,keep_dims表示的意思就是,照常計(jì)算,但不消除該維。
import tensorflow as tf
import numpy as np
x = [[[1,2,3],[4,5,6]],
[[7,8,9],[1,1,1]],
[[2,2,2],[3,3,3]]]
x = tf.constant(x)
# x 后面沒(méi)有參數(shù),就默認(rèn)為把所有的元素相加
a = tf.reduce_sum(x)
#把所有0維里的元素都按照規(guī)則相加,再消去0維度(即消去代表0維度的中括號(hào))
b = tf.reduce_sum(x,0)
#以下沒(méi)有消去的維度都是保留的
#只舉一個(gè)例子,把目前所有1維里的元素都相加如 ==>得到相加的結(jié)果 ==>再消去1維度
# [1,2,3]+[4,5,6] ==> [5,7,9] ==>5,7,9
c = tf.reduce_sum(x,1)
#只舉一個(gè)例子, 把所有第2維的元素都相加 ==> 得到結(jié)果 ==> 消去2維度
# [1+2+3],[4+5+6] ==> [6],[15] ==> 6,15
d = tf.reduce_sum(x,2)
# 把第1維所有元素相加,得到結(jié)果 ==> 再把第2維所有元素相加,得到結(jié)果 ==>消去1,2維度
# [[[5,7,9]],[[8,9,10]],[[5,5,5]]]==>[[[21]],[[27]],[[15]]]==>[21,27,15]
f = tf.reduce_sum(x,[1,2])
#把0維所有元素相加以后,1維所有元素相加以后,2維所有元素相加以后消去012維
g = tf.reduce_sum(x,[0,1,2])
#把目前所有1維里的元素都相加如 ==>得到相加的結(jié)果 ==>但不消去1維度(即括號(hào)不去掉)== 保留該維度
# [1,2,3]+[4,5,6] ==> [5,7,9] ==>[5,7,9]
h = tf.reduce_sum(x,1,keep_dims=True)
#只舉一個(gè)例子, 把所有第2維的元素都相加 ==> 得到結(jié)果 ==> 但不消去2維度 == 保留該維度
# [1+2+3],[4+5+6] ==> [6],[15] ==> [6],[15]
i = tf.reduce_sum(x,2,keep_dims=True)
with tf.Session() as sess:
print('a',sess.run(a))
print('b',sess.run(b))
print('c',sess.run(c))
print('d',sess.run(d))
print('f',sess.run(f))
print('g',sess.run(g))
print('h',sess.run(h))
print('i',sess.run(i))
三、tf.nn.embedding_lookup()函數(shù)
基礎(chǔ)知識(shí)
shape,列表和數(shù)組,
1 shape方法
shape方法得到的結(jié)果的是一個(gè)tuple,從第一個(gè)元素到最后一個(gè)元素,依次表示的是從數(shù)組第0維里含有元素的個(gè)數(shù),第1維含有元素的個(gè)數(shù),第2維。。。如上面的x數(shù)組,x.shape ==>(3,2,3);再如a=[1,2,3]是一個(gè)列表,那么a.shape ==>(3,)一定有一個(gè)逗號(hào),表示這是一個(gè)元組的數(shù)據(jù)結(jié)構(gòu)2 列表和數(shù)組
在運(yùn)用一個(gè)函數(shù)或者方法之前,一定要弄明白,需要傳入的參數(shù)是什么數(shù)據(jù)結(jié)構(gòu)的!!!就比如這個(gè)方法,作者一開(kāi)始定義好x之后,沒(méi)有用np.array設(shè)置成數(shù)組,或者用constant設(shè)置成一個(gè)整體的tensor,結(jié)果x一直是列表形式,最終出現(xiàn)毛病。
def embedding_lookup(params, ids, partition_strategy="mod"),主要講這三個(gè)參數(shù)。
params可以是一個(gè)tensor,也可以是多個(gè)tensor,不過(guò)輸入多個(gè)tensor的時(shí)候,需要用作為params=[a,b,c]的形式進(jìn)行輸入。
當(dāng)系統(tǒng)認(rèn)為,params的長(zhǎng)度等于1時(shí)候,就和平時(shí)的索引一樣,按照ids中的id索引就行。
但是當(dāng)系統(tǒng)認(rèn)為params的長(zhǎng)度大于1的時(shí)候,就會(huì)用第三個(gè)參數(shù)(默認(rèn)是“mod”)的模式,將params去掉里面每個(gè)tensor的中括號(hào)以后所有的元素個(gè)數(shù),按照求余數(shù)相同的方式分成len(params)個(gè)切片,每個(gè)切片里的第i個(gè)id對(duì)應(yīng)該切片里的第i個(gè)元素。
舉個(gè)栗子:
a = [[1,2,3],[4,5,6]]
b = [[7,8,9],[1,1,1]]
c = [[2,2,2],[3,3,3]]
a = tf.constant(a)
b = tf.constant(b)
c = tf.constant(c)
那么傳入params=[a,b,c],此時(shí),系統(tǒng)認(rèn)為params里是多個(gè)量了(3個(gè)tensor),那么去掉每個(gè)tensor的最外面中括號(hào)共有3*2=6個(gè)元素,所以一共可以有6個(gè)id,分別是012345,有3個(gè)tensor,就有3個(gè)切片。按照余數(shù)相同分組,不均勻就前面的分的多。分為[0,3],[1,4],[2,5],對(duì)應(yīng)的分別是 a,b,c。索引id時(shí),id等于3,就相當(dāng)于索引的是a中第二個(gè)元素,所以索引的是[4,5,6].
另外,返回的tensor的shape應(yīng)該是shape(ids) + shape.params[1:]
這里的params指的是被索引的那個(gè)param
比如ids = [3],那么返回的結(jié)果的shape應(yīng)該是shape.[3] + shape.a[1:]=(1,)+(2,3)[1:] = (1,)+(3,) = (1,3),所以結(jié)果應(yīng)該是[[4,5,6]],二維數(shù)組
但這里,這個(gè)函數(shù)是把a(bǔ)作為一個(gè)params了,作為一個(gè)tensor了。
另外需要注意的是,tf中傳入多個(gè)參數(shù),就是用中括號(hào)把參數(shù)作為一個(gè)整體,以列表的方式傳給函數(shù)。所以,有的函數(shù)一旦遇到[a,b,c]這種形式的,就會(huì)認(rèn)為a,b,c是參數(shù)。
所以,若是x一開(kāi)始定義為列表格式的話(huà),那么這個(gè)函數(shù)就會(huì)把這個(gè)‘表示為列表的中括號(hào)’認(rèn)為是類(lèi)似于上面的[a,b,c]這個(gè)傳參的中括號(hào),從而把x認(rèn)為是由三個(gè)tensor組成的。然后就會(huì)啟動(dòng)上面所說(shuō)的切片模式。比如用上面說(shuō)的x,那么就會(huì)認(rèn)為x是三個(gè)[2,3]的數(shù)組。
但是如果用np.array(x)或者用x=tf.constant(x)以后,x就被認(rèn)為是一個(gè)整個(gè)的tensor了,那么這時(shí)候就認(rèn)為x是1個(gè),就不會(huì)啟動(dòng)上面的切片模式,就是正常的索引現(xiàn)象。
以后在遇到的時(shí)候,需要先明確x是列表,還是由constant定義好了的一個(gè)tensor(或者nparray定義的數(shù)組)。自己用的時(shí)候,最好用后者,把x當(dāng)成是一個(gè)整體,若是需要輸入多個(gè),那么就用[a,b,c]的方式輸入。
四、 tf.gather(params,indices,..)
合并 - 索引indices所指示的params中的切片
比如a = tf.gather(x,[0,2]),就是索引x這個(gè)tensor的0維下的元素的位置索引為0,2的兩個(gè)元素 并合并起來(lái),即結(jié)果再放進(jìn)一個(gè)列表中, 即使只有一個(gè)元素也要放進(jìn)列表中
import tensorflow as tf
x = [[[1,2,3],[4,5,6]],
[[7,8,9],[1,1,1]],
[[2,2,2],[3,3,3]]]
a = tf.gather(x,[0,2])
with tf.Session() as sess:
print('a',sess.run(a))#輸出123,456和222,333
五、tf 的onehot函數(shù)
參考[tf.one_hot()函數(shù)簡(jiǎn)介](http://www.lxweimin.com/writer#/notebooks/17771847/notes/18446692/preview
比如,輸入indices是一維列表,[1,3,5,7,9],depth等于10
那么就會(huì)輸出一個(gè)shape為[5,10]的二維數(shù)組,其中第一行中的索引為1的位置為1,其余為0.第二行中索引為3的位置為1,其余值為0.
如果輸入的indices是一個(gè)shape是[1,5]的二維數(shù)組,[[1,3,5,7,9]],那么輸出就會(huì)使一個(gè)[1,5,10]的三維數(shù)組。其中的onehot形式是一樣的。