从最基础的开始,每天敲一点代码,慢慢积累。
Tensorflow是一种计算图模型,即用图的形式来表示运算过程的一种模型。Tensorflow程序一般分为图的构建和图的执行两个阶段。图的构建阶段也称为图的定义阶段,该过程会在图模型中定义所需的运算,每次运算的的结果以及原始的输入数据都可称为一个节点(operation ,缩写为op)。
import tensorflow as tf
a = 3
# Create a variable.
w = tf.Variable([[0.5,1.0]])
x = tf.Variable([[2.0],[1.0]])
y = tf.matmul(w, x)
#variables have to be explicitly initialized before you can run Ops
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
print (y.eval())
==>[[2.]]
tf.matmul()将矩阵a乘以矩阵b,生成a * b
格式: tf.matmul(a, b, transpose_a=False, transpose_b=False, adjoint_a=False, adjoint_b=False, a_is_sparse=False, b_is_sparse=False, name=None)
参数:
a: 一个类型为 float16, float32, float64, int32, complex64, complex128 且张量秩 > 1 的张量。
b: 一个类型跟张量a相同的张量。
transpose_a: 如果为真, a则在进行乘法计算前进行转置。
transpose_b: 如果为真, b则在进行乘法计算前进行转置。
adjoint_a: 如果为真, a则在进行乘法计算前进行共轭和转置。
adjoint_b: 如果为真, b则在进行乘法计算前进行共轭和转置。
a_is_sparse: 如果为真, a会被处理为稀疏矩阵。
b_is_sparse: 如果为真, b会被处理为稀疏矩阵。
name: 操作的名字(可选参数)
返回值: 一个跟张量a和张量b类型一样的张量且最内部矩阵是a和b中的相应矩阵的乘积。
注意:
(1)输入必须是矩阵(或者是张量秩 >2的张量,表示成批的矩阵),并且其在转置之后有相匹配的矩阵尺寸。
(2)两个矩阵必须都是同样的类型,支持的类型如下:float16, float32, float64, int32, complex64, complex128。
引发错误:
ValueError: 如果transpose_a 和 adjoint_a, 或 transpose_b 和 adjoint_b 都被设置为真
生成tensor:
tf.zeros(shape, dtype=tf.float32, name=None)
tf.zeros_like(tensor, dtype=None, name=None)
tf.constant(value, dtype=None, shape=None, name=‘Const’)
tf.fill(dims, value, name=None)
tf.ones_like(tensor, dtype=None, name=None)
tf.ones(shape, dtype=tf.float32, name=None)
m1 = tf.constant([3, 5])
m2 = tf.constant([2, 4])
result = tf.add(m1, m2)
print(result)
==>Tensor(“Add_2:0”, shape=(2,), dtype=int32)
m1 = tf.constant([3, 5])
m2 = tf.constant([2, 4])
result = tf.add(m1, m2)
sess = tf.Session()
print(sess.run(result))
sess.close()
==>[5 9]
首先通过“tf.session()”启动默认图模型,再调用run()方法启动、运行图模型,传入上述参数result,执行矩阵的加法,并打印出相加的结果,最后在任务完成时,要记得调用close()方法,关闭会话。
除了上述的session写法外,我们更建议大家,把session写成如下所示“with”代码块的形式,这样就无需显示的调用close释放资源,而是自动地关闭会话。
m1 = tf.constant([3, 5])
m2 = tf.constant([2, 4])
result = tf.add(m1, m2)
with tf.Session() as sess:
res = sess.run([result])
print(res)
==>[array([5, 9])]
此外,我们还可以利用CPU或GPU等计算资源分布式执行图的运算过程。一般我们无需显示的指定计算资源,Tensorflow可以自动地进行识别,如果检测到我们的GPU环境,会优先的利用GPU环境执行我们的程序。但如果我们的计算机中有多于一个可用的GPU,这就需要我们手动的指派GPU去执行特定的op。如下程序2-4所示,Tensorflow中使用with…device语句来指定GPU或CPU资源执行操作。
# 通过指定gpu来运行op
with tf.Session() as sess:
with tf.device("/gpu:2"):
m1 = tf.constant([3, 5])
m2 = tf.constant([2, 4])
result = tf.add(m1, m2)
上述程序中的“tf.device(“/gpu:2”)”是指定了第二个GPU资源来运行下面的op。依次类推,我们还可以通过“/gpu:3”、“/gpu:4”、“/gpu:5”…来指定第N个GPU执行操作。
关于GPU的具体使用方法,我们会在下面的章节结合案例的形式具体描述。
Tensorflow中还提供了默认会话的机制,如下所示,我们通过调用函数as_default()生成默认会话。
m1 = tf.constant([3, 5])
m2 = tf.constant([2, 4])
result = tf.add(m1, m2)
sess = tf.Session()
with sess.as_default():
print(result.eval())
==>[5 9]
我们在启动默认会话后,可以通过调用eval()函数,直接输出变量的内容。
有时,我们需要在Jupyter或IPython等python交互式环境开发。Tensorflow为了满足用户的这一需求,提供了一种专门针对交互式环境开发的方法InteractiveSession(),具体用法如下所示:
m1 = tf.constant([6, 9])
m2 = tf.constant([3, 8])
result = tf.add(m1, m2)
# 交互式环境中经常会使用的InteractiveSession()方法,其创建sess对象后,可以直接输出运算结果。
sess = tf.InteractiveSession()
print(result.eval())
==>[ 9 17]
综上所述,我们介绍了Tensorflow的核心概念——计算图模型,以及定义图模型和运行图模型的几种方式。接下来,我们思考一个问题,为什么Tensorflow要使用图模型?图模型有什么优势呢?
首先,图模型的最大好处是节约系统开销,提高资源的利用率,可以更加高效的进行运算。因为我们在图的执行阶段,只需要运行我们需要的op,这样就大大的提高了资源的利用率;其次,这种结构有利于我们提取中间某些节点的结果,方便以后利用中间的节点去进行其它运算;还有就是这种结构对分布式运算更加友好,运算的过程可以分配给多个CPU或是GPU同时进行,提高运算效率;最后,因为图模型把运算分解成了很多个子环节,所以这种结构也让我们的求导变得更加方便。
Tensor(张量)是Tensorflow中最重要的数据结构,用来表示Tensorflow程序中的所有数据。Tensor本是广泛应用在物理、数学领域中的一个物理量。那么在Tensorflow中该如何理解Tensor的概念呢?
实际上,我们可以把Tensor理解成N维矩阵(N维数组)。其中零维张量表示的是一个标量,也就是一个数;一维张量表示的是一个向量,也可以看作是一个一维数组;二维张量表示的是一个矩阵;同理,N维张量也就是N维矩阵。
在计算图模型中,操作间所传递的数据都可以看做是Tensor。
# 导入tensorflow模块
import tensorflow as tf
a = tf.constant([[2.0, 3.0]], name = "a")
b = tf.constant([[1.0], [4.0]], name = "b")
result = tf.matmul(a, b, name = "mul")
print(result)
==>Tensor(“mul_2:0”, shape=(1, 1), dtype=float32)
输出结果表明:构建图的运算过程输出的结果是一个Tensor,且其主要由三个属性构成:Name、Shape和Type。Name代表的是张量的名字,
也是张量的唯一标识符,我们可以在每个op上添加name属性来对节点进行命名,Name的值表示的是该张量来自于第几个输出结果(编号从0开始),
上例中的“mul_3:0”说明是第一个结果的输出。Shape代表的是张量的维度,上例中shape的输出结果(1,1)说明该张量result是一个二维数组,
且每个维度数组的长度是1。最后一个属性表示的是张量的类型,每个张量都会有唯一的类型.
常用的张量类型: tf.float32 tf.float64 tf.int8 tf.int16 tf.int32 tf.int64 tf.uint8 tf.uint16 tf.string tf.bool tf.complex64 tf.complex128 tf.qint8 tf.qint32 tf.quint8 我们需要注意的是要保证参与运算的张量类型相一致,否则会出现类型不匹配的错误。如程序2-8所示,当参与运算的张量类型不同时,Tensorflow会报类型不匹配的错误:(如下所示) TypeError: Input ‘y’ of ‘Add’ Op has type float32 that does not match type int32 of argument ‘x’.
k1 = tf.constant([2, 5])
k2 = tf.constant([1.0, 4.0])
result = tf.add(k1, k2)
==>TypeError: Input ‘y’ of ‘Add’ Op has type float32 that does not match type int32 of argument ‘x’.
常量、变量及占位符
Tensorflow中对常量的初始化,不管是对数值、向量还是对矩阵的初始化,都是通过调用constant()函数实现的。因为constant()函数在Tensorflow中的使用非常频繁,经常被用于构建图模型中常量的定义,所以接下来,我们通过以下程序了解一下constant()的相关属性:
import tensorflow as tf
c = tf.zeros([2, 2], tf.float32)
d = tf.zeros_like(c, optimize=True)
# with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, allow_soft_placement=True)) as sess:
with tf.Session() as sess:
with tf.device(None):
print(sess.run(c))
print(sess.run(d))
==>[[0. 0.]
[0. 0.]]
[[0. 0.]
[0. 0.]]
Tensorflow还可以生成一些随机的张量,方便快速初始化一些随机值。如:tf.random_normal()、tf.truncated_normal()、tf.random_uniform()、tf.random_shuffle()等。
import tensorflow as tf
random_num = tf.random_normal([2, 3], mean = -1, stddev = 4,
dtype = tf.float32, seed = None, name = 'rnum')
with tf.Session(config=config) as sess:
print(sess.run(random_num))
==>[[-1.0047752 0.1011107 -3.4977949]
[ 0.2747978 -7.6171293 -1.4803605]]
随机张量random_normal()有shape、mean、stddev、dtype、seed、name六个属性。 shape是指张量的形状,如上述程序是生成一个2行3列的tensor;mean是指正态分布的均值;stddev是指正太分布的标准差;dtype是指生成tensor的数据类型;seed是分发创建的一个随机种子;而name是给生成的随机张量命名。 Tensorflow官方手册:https://www.tensorflow.org/api_guides/python/constant_op。
除了常量constant(),变量variable()也是在Tensorflow中经常会被用到的函数。变量的作用是保存和更新参数。执行图模型时,一定要对变量进行初始化,经过初始化后的变量才能拿来使用。变量的使用包括创建、初始化、保存、加载等操作。
import tensorflow as tf
A = tf.Variable(3, name = "number")
B = tf.Variable([1, 3], name = "vector")
C = tf.Variable([[0, 1], [2, 3]], name = "matrix")
D = tf.Variable(tf.zeros([100]), name = "zero")
E = tf.Variable(tf.random_normal([2, 3], mean = 1, stddev = 2, dtype = tf.float32))
以上程序展示了创建变量的多种方式。我们可以把函数variable()理解为构造函数,构造函数的使用需要初始值,而这个初始值是一个任何形状、类型的Tensor。也就是说,我们
既可以通过创建数字变量、一维向量、二维矩阵初始化Tensor,也可以使用常量或是随机常量初始化Tensor,来完成变量的创建。
当我们完成了变量的创建,接下来,我们要对变量进行初始化。变量在使用前一定要进行初始化,且变量的初始化必须在模型的其它操作运行之前完成。通常,变量的初始化有三种方式,如以下程序所示:
import tensorflow as tf
# 初始化全部变量
init = tf.global_variables_initializer()
with tf.Session(config=config) as sess:
sess.run(init)
# 初始化变量的子集:
# init_subset = tf.variables_initializer([b,c], name="init_subset")
# with tf.Session(config=config) as sess:
# sess.run(init_subset)
# 初始化单个变量:
init_var = tf.Variable(tf.zeros([2, 5]))
with tf.Session(config=config) as sess:
sess.run(init_var.initializer)
初始化变量的三种方式:初始化全部变量、初始化变量的子集以及初始化单个变量。首先,global_variables_initializer()方法是不管全局有多少个变量,全部进行初始化,是最简单也是最常用的一种方式;variables_initializer()是初始化变量的子集,相比于全部初始化化的方式更加节约内存;Variable()是初始化单个变量,函数的参数便是要初始化的变量内容。通过上述的三种方式,我们便可以实现变量的初始化,放心的使用变量了。
我们经常在训练模型后,希望保存训练的结果,以便下次再使用或是方便日后查看,这时就用到了Tensorflow变量的保存。变量的保存是通过tf.train.Saver()方法创建一个Saver管理器,来保存计算图模型中的所有变量。
import tensorflow as tf
var1 = tf.Variable([1, 3], name = "v1")
var2 = tf.Variable([2, 4], name = "v2")
# 对全部变量进行初始化
init = tf.global_variables_initializer()
# 调用 Saver()存储方法
saver = tf.train.Saver()
# 执行图模型
with tf.Session(config=config) as sess:
sess.run(init)
# 设置存储路径
save_path = saver.save(sess, "test/save.ckpt")
我们要注意,我们的存储文件save.ckpt是一个二进制文件,Saver存储器提供了向该二进制文件保存变量和恢复变量的方法。保存变量的方法就是程序中的save()方法,保存的内容是从变量名到tensor值的映射关系。完成该存储操作后,会在对应目录下生成对应文件。
Saver提供了一个内置的计数器自动为checkpoint文件编号。这就支持训练模型在任意步骤多次保存。此外,还可以通过global_step参数自行对保存文件进行编号,例如:global_step=2,则保存变量的文件夹为model.ckpt-2。 那如何才能恢复变量呢?首先,我们要知道一定要用和保存变量相同的Saver对象来恢复变量。其次,不需要事先对变量进行初始化。
import tensorflow as tf
var1 = tf.Variable([0, 0], name = "v1")
var2 = tf.Variable([0, 0], name = "v2")
saver = tf.train.Saver()
module_file = tf.train.latest_checkpoint('test/')
config = tf.ConfigProto(allow_soft_placement=True)
config.gpu_options.allow_growth = True
with tf.Session(config=config) as sess:
saver.restore(sess, module_file)
print("Model restored.")
==>INFO:tensorflow:Restoring parameters from test/save.ckpt
Model restored.
我们要注意:变量的获取是通过restore()方法,该方法有两个参数,分别是session和获取变量文件的位置。我们还可以通过latest_checkpoint()方法,获取到该目录下最近一次保存的模型。
以上就是对变量创建、初始化、保存、加载等操作的介绍。此外,还有一些与变量相关的重要函数,如:eval()等。
认识了常量和变量,Tensorflow中还有一个非常重要的常用函数——placeholder。placeholder是一个数据初始化的容器,它与变量最大的不同在于placeholder定义的是一个模板,这样我们就可以session运行阶段,利用feed_dict的字典结构给placeholder填充具体的内容,而无需每次都提前定义好变量的值,大大提高了代码的利用率。
# placeholder占位符的使用过程
import tensorflow as tf
a = tf.placeholder(tf.float32, shape = [2], name = None)
b = tf.constant([6, 4], tf.float32)
c = tf.add(a, b)
with tf.Session(config=config) as sess:
print(sess.run(c, feed_dict = {a:[10, 10]}))
==>[16. 14.]
Placeholder()方法有dtype,shape和name三个参数构成。dtype是必填参数,代表传入value的数据类型;shape是选填参数,代表传入value的维度;name也是选填参数,代表传入value的名字。我们可以把这三个参数看作为形参,在使用时传入具体的常量值。这也是placeholder不同于常量的地方,它不可以直接拿来使用,而是需要用户传递常数值。
最后,Tensorflow中还有一个重要的概念——fetch。Fetch的含义是指可以在一个会话中同时运行多个op。这就方便我们在实际的建模过程中,输出一些中间的op,取回多个tensor。
# Fetch的具体用法 即我们利用session的run()方法同时取回多个tensor值,方便我们查看运行过程中每一步op的输出结果。
import tensorflow as tf
a = tf.constant(5)
b = tf.constant(6)
c = tf.constant(4)
add = tf.add(b, c)
mul = tf.multiply(a, add)
config = tf.ConfigProto(allow_soft_placement=True)
config.gpu_options.allow_growth = True
with tf.Session(config=config) as sess:
result = sess.run([mul, add])
print(result)
==>[50, 10]
s1 = tf.zeros([3, 4], tf.int32)
with tf.Session() as sess:
print(sess.run(s1))
==>[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]]
tensor = [[1, 2, 3], [4, 5, 6]]
s2 = tf.zeros_like(tensor)
with tf.Session() as sess:
print(sess.run(s2))
==>[[0 0 0]
[0 0 0]]
tf.constant(
value,
dtype=None,
shape=None,
name=‘Const’,
verify_shape=False
)
第一个值value是必须的,可以是一个数值,也可以是一个列表
第二个参数表示数据类型,一般可以是tf.float32, tf.float64等
第三个参数表示张量的“形状”,即维数以及每一维的大小。如果指定了第三个参数,当第一个参数value是数字时,张量的所有元素都会用该数字填充
而当第一个参数value是一个列表时,注意列表的长度必须小于等于第三个参数shape的大小(即各维大小的乘积),否则会报错,这是因为函数会生成一个shape大小的张量,然后用value这个列表中的值一一填充shape中的元素。这里列表大小为7,而shape大小为2*3=6,无法正确填充,所以发生了错误。
第四个参数name可以是任何内容,主要是字符串就行。
第五个参数verify_shape默认为False,如果修改为True的话表示检查value的形状与shape是否相符,如果不符会报错。
而如果列表大小小于shape大小,则会用列表的最后一项元素填充剩余的张量元素
查看结果必须创建一个会话,并用取值函数eval()来查看创建的tensor的值
s3 = tf.constant(4, shape = [4, 5], name = 's3')
with tf.Session() as sess:
print(sess.run(s3))
==>[[4 4 4 4 4]
[4 4 4 4 4]
[4 4 4 4 4]
[4 4 4 4 4]]
s3 = tf.constant(5)
sess = tf.Session()
with sess.as_default():
print("结果是:",s3.eval())
==>结果是: 5
s4 = tf.constant([[4, 8], [5, 7], [2, 6]])
sess = tf.Session()
with sess.as_default():
print("结果是:",s4.eval())
==>结果是: [[4 8]
[5 7]
[2 6]]
s5 = tf.constant(-1, shape = [4, 4])
sess = tf.Session()
with sess.as_default():
print("结果是:", s5.eval())
==>结果是: [[-1 -1 -1 -1]
[-1 -1 -1 -1]
[-1 -1 -1 -1]
[-1 -1 -1 -1]]
tf.fill(dims, value, name=None)
创建一个维度为dims,值为value的tensor对象.该操作会创建一个维度为dims的tensor对象,并将其值设置为value,该tensor对象中的值类型和value一致
当value为0时,该方法等同于tf.zeros()
当value为1时,该方法等同于tf.ones()
参数:
dims: 类型为int32的tensor对象,用于表示输出的维度(1-D, n-D),通常为一个int32数组,如:[1], [2,3]等
value: 常量值(字符串,数字等),该参数用于设置到最终返回的tensor对象值中
name: 当前操作别名(可选)
返回:
tensor对象,类型和value一致
sess = tf.InteractiveSession()
dim = [2, 4]
data1 = tf.fill(dim, 5)
data2 = tf.fill(dim, 4.0)
data3 = tf.fill(dim, "3")
with sess.as_default():
print(data1.eval())
print(data2.eval())
print(data3.eval())
==>[[5 5 5 5]
[5 5 5 5]]
[[4. 4. 4. 4.]
[4. 4. 4. 4.]]
[[b’3’ b’3’ b’3’ b’3’]
[b’3’ b’3’ b’3’ b’3’]]
o1 = tf.ones([3, 4], dtype = tf.float32, name = "o1")
o3 = [[3, 2, 4], [2, 2, 2], [1, 0, 7]]
o2 = tf.ones_like(o3, dtype = tf.float32, name = "o2")
with tf.Session() as sess:
print(sess.run(o1))
print(sess.run(o2))
==>[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
生成序列
tf.range(start, limit, delta=1, name=‘range’)
tf.linspace(start, stop, num, name=None)
range()函数用于创建数字序列变量,有以下两种形式:
range(limit, delta=1, dtype=None, name=‘range’)
range(start, limit, delta=1, dtype=None, name=‘range’)
该数字序列开始于 start 并且将以 delta 为增量扩展到不包括 limit 时的最大值结束,类似python的range函数。
x = tf.range(3, 9, 4)
y = tf.range(3, 7)
z = tf.range(4, 2, -0.6)
w = tf. range(4)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
print(sess.run(x))
print(sess.run(y))
print(sess.run(z))
print(sess.run(w))
sess.close()
==>[3 7]
[3 4 5 6]
[4. 3.4 2.8000002 2.2000003]
[0 1 2 3]
tf.linspace(start, end, num):这个函数主要的参数就这三个,start代表起始的值,end表示结束的值,num表示在这个区间里生成数字的个数,生成的数组是等间隔生成的。start和end这两个数字必须是浮点数,不能是整数,如果是整数会出错的,请注意! np.linspace(start, end, num):主要的参数也是这三个,我们平时用的时候绝大多数时候就是用这三个参数。start代表起始的值,end表示结束的值,num表示在这个区间里生成数字的个数,生成的数组是等间隔生成的。start和end这两个数字可以是整数或者浮点数!
l1 = tf.linspace(1.0, 18.0, 9)
# with tf.Session() as sess:
# print(sess.run(l1))
print(l1.eval(session= tf.Session()))
==>[ 1. 3.125 5.25 7.375 9.5 11.625 13.75 15.875 18. ]
norm = tf.random_normal([2, 3], mean=-1, stddev=4)
# Shuffle the first dimension of a tensor
c = tf.constant([[1, 2], [3, 4], [5, 6]])
shuff = tf.random_shuffle(c)
# Each time we run these ops, different results are generated
sess = tf.Session()
print (sess.run(norm))
print (sess.run(shuff))
==>[[ 0.31919324 -1.863795 -5.080905 ]
[-3.025766 1.3174827 -3.8188334 ]]
[[1 2]
[3 4]
[5 6]]
生成随机数
tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
tf.random_uniform(shape, minval=0.0, maxval=1.0, dtype=tf.float32, seed=None, name=None)
tf.random_shuffle(value, seed=None, name=None)
import tensorflow as tf
r1 = tf.random_normal([4, 3], mean = 1.2, stddev = 2, dtype = tf.float32, seed = 1234, name = "r1")
r2 = tf.truncated_normal([3, 4], mean = 1.5, stddev = 2.0, dtype = tf.float32)
r3 = tf.random_uniform([5, 5], minval = 4.0, maxval = 15.0, dtype = tf.float32)
r4 = tf.random_shuffle([[1, 3], [2, 5], [4, 7]])
with tf.Session() as sess:
print(sess.run(r1))
print(sess.run(r2))
print(sess.run(r3))
print(sess.run(r4))
==>[[ 2.2268097 0.6883721 2.5039825]
[ 3.9847276 1.9451361 1.6067262]
[ 3.6940367 -0.7666625 2.2087972]
[ 3.1720028 -2.2009864 4.2347994]]
[[ 0.2471739 2.865998 2.9082966 -0.57637405]
[ 3.1416745 3.6736414 1.7401202 4.8788157 ]
[ 1.7008524 4.2158194 2.7322671 4.185856 ]]
[[ 4.411948 5.5486135 5.7370925 5.8070545 4.9890246]
[ 5.1904593 8.236054 7.901836 14.207651 7.2826614]
[ 5.286718 12.172671 11.499342 5.990221 10.526257 ]
[ 6.4200253 14.828909 13.834933 10.898711 9.157386 ]
[ 4.7751646 10.312859 12.049599 12.611778 5.234629 ]]
[[2 5]
[1 3]
[4 7]]
tf.random_shuffle 函数
random_shuffle(
value,
seed=None,
name=None
)
随机地将张量沿其第一维度打乱.
参数:
value:将被打乱的张量.
seed:一个 Python 整数.用于为分布创建一个随机种子.查看 tf.set_random_seed 行为.
name:操作的名称(可选).
返回:
与 value 具有相同的形状和类型的张量,沿着它的第一个维度打乱.
# state += 1 用tensorflow实现:
import tensorflow as tf
state = tf.Variable(0)
new_value = tf.add(state, tf.constant(1))
update = tf.assign(state, new_value)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(state))
for _ in range(3):
sess.run(update)
print(sess.run(state))
==>0
1
2
3
今天先到这里,对自己说声晚安,继续努力!!