代码(操纵全局变量)
- xiaojie=1
- i=tf.constant(0,dtype=tf.int32)
- batch_len=tf.constant(10,dtype=tf.int32)
- loop_cond = lambda a,b: tf.Less(a,batch_len)
- #yy=tf.Print(batch_len,[batch_len],"batch_len:")
- yy=tf.constant(0)
- loop_vars=[i,yy]
- def _recurrence(i,yy):
- c=tf.constant(2,dtype=tf.int32)
- x=tf.multiply(i,c)
- global xiaojie
- xiaojie=xiaojie+1
- print_info=tf.Print(x,[x],"x:")
- yy=yy+print_info
- i=tf.add(i,1)
- # print (xiaojie)
- return i,yy
- i,yy=tf.while_loop(loop_cond,_recurrence,loop_vars,parallel_iterations=1)# 可以批处理
- sess = tf.Session()
- print (sess.run(i))
- print (xiaojie)
输出的是 10 和 2.
也就是 xiaojie 只被修改了一次.
这个时候, 在_recurrence 循环体中添加语句
print (xiaojie)
会输出 2. 而且只输出一次. 具体为什么, 最后总结的时候再解释.
代码(操纵类成员变量)class RNN_Model():
- def __init__(self):
- self.xiaojie=1
- def test_RNN(self):
- i=tf.constant(0,dtype=tf.int32)
- batch_len=tf.constant(10,dtype=tf.int32)
- loop_cond = lambda a,b: tf.Less(a,batch_len)
- #yy=tf.Print(batch_len,[batch_len],"batch_len:")
- yy=tf.constant(0)
- loop_vars=[i,yy]
- def _recurrence(i,yy):
- c=tf.constant(2,dtype=tf.int32)
- x=tf.multiply(i,c)
- self.xiaojie=self.xiaojie+1
- print_info=tf.Print(x,[x],"x:")
- yy=yy+print_info
- i=tf.add(i,1)
- print ("_recurrence:",self.xiaojie)
- return i,yy
- i,yy=tf.while_loop(loop_cond,_recurrence,loop_vars,parallel_iterations=1)# 可以批处理
- sess = tf.Session()
- sess.run(yy)
- print (self.xiaojie)
- if __name__ == "__main__":
- model = RNN_Model()# 构建树, 并且构建词典
- model.test_RNN()
输出是:
_recurrence: 2 10 2
tf.while_loop 操纵全局变量和类成员变量总结
为什么_recurrence 中定义的 print 操作只执行一次呢, 这是因为_recurrence 中的 print 相当于一种对代码的定义, 直接在定义的过程中就执行了. 所以, 可以看到输出是在 sess.run 之前的. 但是, 定义的其它操作就是数据流图中的操作, 需要在 sess.run 中执行.
就必须在 sess.run 中执行. 但是, 全局变量 xiaojie 也好, 还是类成员变量 xiaojie 也好. 其都不是图中的内容. 因此, tf.while_loop 执行的是 tensorflow 计算图中的循环, 对于不是在计算图中的, 就不会参与循环. 注意: 而且必须是与 loop_vars 中指定的变量存在数据依赖关系的 tensor 才可以! 此外, 即使是依赖关系, 也必须是_recurrence 循环体中 return 出的变量, 才会真正的变化. 比如, 见下面的 self.L. 总之, 想操纵变量, 就要传入 loop_vars!
如果对一个变量没有修改, 就可以直接在循环中以操纵类成员变量或者全局变量的方式只读.
self.L 与 loop_vars 中变量有依赖关系, 但是并没有真正被修改.
- #IIII 通过计算将非叶子节点的词向量也放入 nodes_tensor 中.
- iiii=tf.constant(0,dtype=tf.int32)
- loop____cond = lambda a,b,c,d,e: tf.Less(a,self.sentence_length-1)#iiii 的范围是 0 到 sl-2. 注意, 不包括 sl-1. 这是因为只需要计算 sentence_length-1 次, 就能构建出一颗树
- loop____vars=[iiii,columnLinesOfL,node_tensors_cost_tensor,nodes_tensor,tfPrint]
- def ____recurrence(iiii,columnLinesOfL,node_tensors_cost_tensor,nodes_tensor,tfPrint):# 循环的目的是实现 Greedy 算法
- ###
- #Greedy 的主要目标就是确立树结构.
- ###
- c1 = self.L[:,0:columnLinesOfL-1]# 这段代码是从 RvNN 的 matlab 的源码中复制过来的, 但是 Matlab 的下标是从 1 开始, 并且 Matlab 中 1:2 就是 1 和 2, 而 python 中 1:2 表示的是 1, 不包括 2, 所以, 有很大的不同.
- c2 = self.L[:,1:columnLinesOfL]
- c=tf.concat([c1,c2],axis=0)
- p=tf.tanh(tf.matmul(self.W1,c)+tf.tile(self.b1,[1,columnLinesOfL-1]))
- p_normalization=self.normalization(p)
- y=tf.tanh(tf.matmul(self.U,p_normalization)+tf.tile(self.bs,[1,columnLinesOfL-1]))# 根据 Matlab 中的源码来的, 即重构后, 也有一个激活的过程.
- #将 Y 矩阵拆分成上下部分之后, 再分别进行标准化.
- columnlines_y=columnLinesOfL-1
- (y1,y2)=self.split_by_row(y,columnlines_y)
- y1_normalization=self.normalization(y1)
- y2_normalization=self.normalization(y2)
- #论文中提出一种计算重构误差时要考虑的权重信息. 具体见论文, 这里暂时不实现.
- #这个权重是可以修改的.
- alpha_cat=1
- bcat=1
- #计算重构误差矩阵
- ## constant1=tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0],[7.0,8.0,9.0]])
- ## constant2=tf.constant([[1.0,2.0,3.0],[1.0,4.0,2.0],[1.0,6.0,1.0]])
- ## constructionErrorMatrix=self.constructionError(constant1,constant2,alpha_cat,bcat)
- y1c1=tf.subtract(y1_normalization,c1)
- y2c2=tf.subtract(y2_normalization,c2)
- constructionErrorMatrix=self.constructionError(y1c1,y2c2,alpha_cat,bcat)
- ################################################################################
- print_info=tf.Print(iiii,[iiii],"\niiii:")# 专门为了调试用, 输出相关信息.
- tfPrint=print_info+tfPrint
- print_info=tf.Print(columnLinesOfL,[columnLinesOfL],"\nbefore modify. columnLinesOfL:")# 专门为了调试用, 输出相关信息.
- tfPrint=print_info+tfPrint
- print_info=tf.Print(constructionErrorMatrix,[constructionErrorMatrix],"\nbefore modify. constructionErrorMatrix:",summarize=100)# 专门为了调试用, 输出相关信息.
- tfPrint=tf.to_int32(print_info[0])+tfPrint# 一种不断输出 tf.Print 的方式, 注意 tf.Print 的返回值.
- ################################################################################
- J_minpos=tf.to_int32(tf.argmin(constructionErrorMatrix))# 如果不转换的话, 下面调用 delete_one_column 中, 会调用 tf.slice, 之后 tf.slice 的参数中的类型必须是一样的.
- J_min=constructionErrorMatrix[J_minpos]
- #一共要进行 sl-1 次循环. 因为是从 sl 个叶子节点, 两两结合 sl-1 次, 才能形成一颗完整的树, 而且是采用 Greedy 的方式.
- #所以, 需要为下次循环做准备.
- #第一步, 从该 sentence 的词向量矩阵中删除第 J_minpos+1 列, 因为第 J_minpos 和第 J_minpos+1 列对应的单词要合并为一个新的节点, 这里就是修改 L
- ################################################################################
- print_info=tf.Print(self.L,[self.L[0]],"\nbefore modify. L row 0:",summarize=100)# 专门为了调试用, 输出相关信息.
- tfPrint=tf.to_int32(print_info[0][0])+tfPrint
- print_info=tf.Print(self.L,[tf.shape(self.L)],"\nbefore modify. L shape:")# 专门为了调试用, 输出相关信息.
- tfPrint=tf.to_int32(print_info[0][0])+tfPrint
- ################################################################################
- deleteColumnIndex=J_minpos+1
- self.L=self.delete_one_column(self.L,deleteColumnIndex,self.numlinesOfL,columnLinesOfL)
- columnLinesOfL=tf.subtract(columnLinesOfL,1) #列数减去 1.
- ################################################################################
- print_info=tf.Print(deleteColumnIndex,[deleteColumnIndex],"\nbefore modify. deleteColumnIndex:")# 专门为了调试用, 输出相关信息.
- tfPrint=print_info+tfPrint
- print_info=tf.Print(self.L,[self.L[0]],"\nafter modify. L row 0:",summarize=100)# 专门为了调试用, 输出相关信息.
- tfPrint=tf.to_int32(print_info[0][0])+tfPrint
- print_info=tf.Print(self.L,[tf.shape(self.L)],"\nafter modify. L shape:")# 专门为了调试用, 输出相关信息.
- tfPrint=tf.to_int32(print_info[0][0])+tfPrint
- print_info=tf.Print(columnLinesOfL,[columnLinesOfL],"\nafter modify. columnLinesOfL:")# 专门为了调试用, 输出相关信息.
- tfPrint=print_info+tfPrint
- ################################################################################
- #第二步, 将新的词向量赋值给第 J_minpos 列
- columnTensor=p_normalization[:,J_minpos]
- new_column_tensor=tf.expand_dims(columnTensor,1)
- self.L=self.modify_one_column(self.L,new_column_tensor,J_minpos,self.numlinesOfL,columnLinesOfL)
- #第三步, 同时将新的非叶子节点的词向量存入 nodes_tensor
- modified_index_tensor=tf.to_int32(tf.add(iiii,self.sentence_length))
- nodes_tensor=self.modify_one_column(nodes_tensor,new_column_tensor,modified_index_tensor,self.numlines_tensor,self.numcolunms_tensor)
- #第四步: 记录合并节点的最小损失, 存入 node_tensors_cost_tensor
- J_min_tensor=tf.expand_dims(tf.expand_dims(J_min,0),1)
- node_tensors_cost_tensor=self.modify_one_column(node_tensors_cost_tensor,J_min_tensor,iiii,self.numlines_tensor2,self.numcolunms_tensor2)
- #### 进入下一次循环
- iiii=tf.add(iiii,1)
- print_info=tf.Print(J_minpos,[J_minpos,J_minpos+1],"node:")# 专门为了调试用, 输出相关信息.
- tfPrint=tfPrint+print_info
- # columnLinesOfL=tf.subtract(columnLinesOfL,1) #在上面的循环体中已经执行了, 没有必要再执行.
- return iiii,columnLinesOfL,node_tensors_cost_tensor,nodes_tensor,tfPrint
- iiii,columnLinesOfL,node_tensors_cost_tensor,nodes_tensor,tfPrint=tf.while_loop(loop____cond,____recurrence,loop____vars,parallel_iterations=1)
- pass
上述代码是 Greedy 算法, 递归构建神经网络树结构.
但是程序出错了, 后来不断的调试, 才发现 self.L 虽然跟循环 loop____vars 中的变量有依赖关系, 也就是在 tf.while_loop 进行循环的时候, 也可以输出它的值.
但是, 它每一次都无法真正意义上对 self.L 进行修改. 会发现, 每一次循环结束之后, 进入下一次循环时, self.L 仍然没有变化.
执行结果如下:
- before modify. columnLinesOfL:[31]
- iiii:[0]
- after modify. columnLinesOfL:[30]
- before modify. L shape:[300 31]
- before modify. L row 0:[0.126693 -0.013654 -0.166731 -0.13703 -0.261395 0.11459 0.016001 0.016001 0.144603 0.05588 0.171787 0.016001 1.064545 0.144603 0.130615 -0.13703 -0.261395 1.064545 -0.261395 0.144603 0.036626 1.064545 0.188871 0.201198 0.05588 0.203795 0.201198 0.03536 0.089345 0.083778 0.103635]
- node:[0][1]
- before modify. constructionErrorMatrix:[3.0431733686706206 11.391056715427794 19.652819956115856 13.713453313903868 11.625973829805879 12.827533320819564 9.7513513723204746 13.009151292890811 13.896089243289065 10.649829109971648 9.45239374745086 15.704486086921641 18.274065790781862 12.447866299915024 15.302996103637689 13.713453313903868 14.295549844738751 13.779406175789358 11.625212314259059 16.340507223201449 19.095964364689717 15.10149194936319 11.989443162329437 13.436654650354058 11.120373311110505 12.39345317975002 13.568052800712424 10.998430341124633 8.3223909323599869 6.8896857405641851]
- after modify. L shape:[300 30]
- after modify. L row 0:[0.126693 -0.166731 -0.13703 -0.261395 0.11459 0.016001 0.016001 0.144603 0.05588 0.171787 0.016001 1.064545 0.144603 0.130615 -0.13703 -0.261395 1.064545 -0.261395 0.144603 0.036626 1.064545 0.188871 0.201198 0.05588 0.203795 0.201198 0.03536 0.089345 0.083778 0.103635]
- before modify. deleteColumnIndex:[1]
- before modify. columnLinesOfL:[30]
- iiii:[1]
- before modify. L shape:[300 31]
- after modify. columnLinesOfL:[29]
- before modify. L row 0:[0.126693 -0.013654 -0.166731 -0.13703 -0.261395 0.11459 0.016001 0.016001 0.144603 0.05588 0.171787 0.016001 1.064545 0.144603 0.130615 -0.13703 -0.261395 1.064545 -0.261395 0.144603 0.036626 1.064545 0.188871 0.201198 0.05588 0.203795 0.201198 0.03536 0.089345 0.083778 0.103635]
- before modify. deleteColumnIndex:[1]
- node:[0][1]
- before modify. constructionErrorMatrix:[3.0431733686706206 11.391056715427794 19.652819956115856 13.713453313903868 11.625973829805879 12.827533320819564 9.7513513723204746 13.009151292890811 13.896089243289065 10.649829109971648 9.45239374745086 15.704486086921641 18.274065790781862 12.447866299915024 15.302996103637689 13.713453313903868 14.295549844738751 13.779406175789358 11.625212314259059 16.340507223201449 19.095964364689717 15.10149194936319 11.989443162329437 13.436654650354058 11.120373311110505 12.39345317975002 13.568052800712424 10.998430341124633 8.3223909323599869]
- after modify. L shape:[300 29]
- after modify. L row 0:[0.126693 -0.166731 -0.13703 -0.261395 0.11459 0.016001 0.016001 0.144603 0.05588 0.171787 0.016001 1.064545 0.144603 0.130615 -0.13703 -0.261395 1.064545 -0.261395 0.144603 0.036626 1.064545 0.188871 0.201198 0.05588 0.203795 0.201198 0.03536 0.089345 0.083778]
- before modify. columnLinesOfL:[29]
- iiii:[2]
后面那个 after modify 时 L shape 为 [300 29] 的原因是: 执行
self.L=self.modify_one_column(self.L,new_column_tensor,J_minpos,self.numlinesOfL,columnLinesOfL)
时, columnLinesOfL 是循环 loop____vars 中的变量, 因此会随着每次循环发生变化, 我写的 modify_one_column 见我的博文 "修改 tensor 张量矩阵的某一列". 它决定了
修改后 tensor 的维度.
但是, 无论如何, 每一次循环, 都是
before modify. L shape:[300 31]
说明 self.L 在循环体中没有被修改.
来源: http://www.bubuko.com/infodetail-2875425.html