TensorFlow 是一个端到端开源机器学习平台。 是开源的、基于 Python 的机器学习框架,用于帮助开发和训练机器学习模型。
tensorflow最擅长的任务就是训练深度神经网络
TensorFlow采用数据流图(data flow graphs)来计算, 首先得创建一个数据流图, 然后再将数据(数据以张量(tensor)的形式存在)放在数据流图中计算. 节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组, 即张量(tensor). 训练模型时tensor会不断的从数据流图中的一个节点flow到另一节点, 这就是TensorFlow名字的由来.-》先创建结构,再放入数据进行计算。数据叫做tensor,在结构图中flow
张量(Tensor): * 张量有多种. 零阶张量为 纯量或标量 (scalar) 也就是一个数值. 比如 [1] * 一阶张量为 向量 (vector), 比如 一维的 [1, 2, 3] * 二阶张量为 矩阵 (matrix)
tf.Session()
先把东西准备好,然后用session激活计算结果。相当于一个开关闸。
# method 1
sess = tf.Session()
result = sess.run(product)
print(result)
sess.close()
# method 2
with tf.Session() as sess:
result2 = sess.run(product)
print(result2)
如果是高版本的tf,可用tf.compat.v1.Session()。
tf.name_scope()和tf.variable_scope()
作用:
TensorFlow 可以有数以千计的节点,如此多以至于难以一下全部看到,也难以使用标准图表工具展示。所以,通过tf.name_scope()和tf.variable_scope() 来为op/tensor
名划定范围,并且用该信息在可视化图表中的节点上定义层级。默认情况下只有顶层节点会显示。简单说,就是为了方便命名管理。
例如:
import tensorflow as tf
with tf.name_scope('hidden') as scope:
a = tf.constant(5, name='alpha')
W = tf.Variable(tf.random_uniform([1, 2], -1.0, 1.0), name='weights')
b = tf.Variable(tf.zeros([1]), name='biases')
print(a.name)
print(W.name)
print(b.name)
# 结果
# hidden/alpha
# hidden/weights
# hidden/biases
区别:
使用tf.Variable()的时候,tf.name_scope()和tf.variable_scope() 都会给 Variable 和 op 的 name属性加上前缀。
使用tf.get_variable()的时候,tf.name_scope()就不会给 tf.get_variable()创建出来的Variable加前缀。但是 tf.Variable() 创建出来的就会受到 name_scope 的影响.
tf.reduce_mean()
tf.reduce_mean 函数用于计算张量tensor沿着指定的数轴(tensor的某一维度)上的平均值,主要用作降维或者计算tensor的平均值。
reduce_mean(input_tensor, # 待降维的tensor
axis=None) # 指定的轴,如果不指定,则计算所有元素的均值;
例如
import tensorflow as tf
x = [[1,2,3],
[1,2,3]]
xx = tf.cast(x,tf.float32)
mean_all = tf.reduce_mean(xx)
mean_0 = tf.reduce_mean(xx, axis=0)
mean_1 = tf.reduce_mean(xx, axis=1)
with tf.Session() as sess:
m_a,m_0,m_1 = sess.run([mean_all, mean_0, mean_1])
print(m_a) # output: 2.0
print(m_0) # output: [ 1. 2. 3.]
print(m_1) #output: [ 2. 2.]
placeholder和feed_dict
简单说,构建graph时用placeholder占位(分配必要的内存),要run session的时候用feed_dict赋值。
import tensorflow as tf
import numpy as np
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = tf.multiply(input1, input2)
with tf.Session() as sess:
print(sess.run(output, feed_dict = {input1:[3.], input2: [4.]}))
tf.reduce_sum()
reduce表示降维,sum表示降维的方式。reduce_sum通过求和降维,reduce_mean通过求均值降维。
常用形式为reduce_sum(arg1, arg2)
,参数arg1
为要求和的数据,arg2为求和的维度,0表示纵向,1表示横向,省略表示对所有元素求和。
tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels)
1.简要说明
理解这个函数的输入输出,知道怎么用它就行。这个函数的功能可以理解为对batch实现softmax+交叉熵的操作。sparse_softmax_cross_entropy_with_logits+reduce_mean是有监督学习中非常常用的loss形式。(交叉熵简单理解就是对应真实值的那个预测值的概率的负对数值)
输入:参数logits表示神经网络的预测值(未经softmax),参数labels表示真实标签值(序号形式,如果已经转为了one-hot形式则可以用softmax_cross_entropy_with_logits()函数,本质上是一样的)。通常logits的shape是[None, num_classes]其中None表示batch_size,num_classes表示分类的种数,例如[64, 2]表示batch_size为64、结果分为二类。
处理流程:先对logits求softmax,然后求其与labels的cross_entropy,就得到了输出
输出:[batch_size, ]也即batch中每个样本的cross_entropy值。
后续处理:通常使用tf.nn.sparse_softmax_cross_entropy_with_logits的下一行会用tf.reduce_mean求该batch中所有样本cross_entropy的平均值作为整个batch的loss。
# 使用实例
self.logits = tf.matmul(out_put, output_w)+output_b
with tf.name_scope("loss"):
self.loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.logits+1e-10,labels=self.target)
self.cost = tf.reduce_mean(self.loss)
2.具体一些
以神经网络输出层输出64×2的向量为例,64就是batch_size,2是因为问题是二分类。相当于每个样本经过神经网络都要被分为两类中的一类,例如第一个样本,属于类别一的值是0.00827,属于类别二的值是-0.03050(不用纠结是负数,这只是一个值),而这里有64个样本。经过softmax,把每个样本属于每个每个类别的值都归一化),例如第一个样本,属于类别一的值(可以认为是概率)是0.50969,属于类别二的值(可以认为是概率)是0.49030。经过softmax的结果还是64×2的向量。
交叉熵里的样本的真实label向量一般是one-hot向量,但是也可以换一种思路把它定义为one-hot向量里的数字‘’1‘’对应的那一维度的序号。例如第一个样本的label,用one-hot表示其实是[0,1],这里,[0,1]里的"1"对应的序号恰好也是1(序号从0开始,如果label是[0,0,1]则对应的序号是2),所以label用序号表示时取为1。sparse_softmax_cross_entropy_with_logits()这个函数里其实就是用的序号表示。把每个样本经过softmax的结果与label做交叉熵,得到一个loss,有64个样本也就有64个loss。 简而言之,label向量不管是one-hot表示还是序号表示,本质上都是一回事,如果用one-hot表示,用softmax_cross_entropy_with_logits()函数,如果用序号表示,用sparse_softmax_cross_entropy_with_logits()函数。(也许是序号表示简单一点,所以函数名字前面加了个sparse)(摘自https://blog.csdn.net/ZJRN1027/article/details/80199248)
3.再次注意
这个函数的返回值是[batch_size, ]的向量,而不是一个数。如果求交叉熵,需要再做reduce_sum对向量中所有元素求和才能得到;如果求loss,需要再做reduce_mean对向量求均值。
以下代码说明了该函数的作用和自己先求softmax再求cross_entropy是一样的。
# 例子说明
import tensorflow as tf
#our NN's output
logits=tf.constant([[1.0,2.0,3.0],[1.0,2.0,3.0],[1.0,2.0,3.0]])
#step1:do softmax
y=tf.nn.softmax(logits)
#true label
y_=tf.constant([[0.0,0.0,1.0],[0.0,0.0,1.0],[0.0,0.0,1.0]])
#step2:do cross_entropy
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
#do cross_entropy just one step
cross_entropy2=tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(logits, y_))#dont forget tf.reduce_sum()!!
with tf.Session() as sess:
softmax=sess.run(y)
c_e = sess.run(cross_entropy)
c_e2 = sess.run(cross_entropy2)
print("step1:softmax result=")
print(softmax)
print("step2:cross_entropy result=")
print(c_e)
print("Function(softmax_cross_entropy_with_logits) result=")
print(c_e2)
# 输出结果
step1:softmax result=
[[ 0.09003057 0.24472848 0.66524094]
[ 0.09003057 0.24472848 0.66524094]
[ 0.09003057 0.24472848 0.66524094]]
step2:cross_entropy result=
1.22282
Function(softmax_cross_entropy_with_logits) result=
1.2228
4.问题: 强化学习中并没有所谓的真实值labels,那为什么强化学习的损失函数也用该函数实现?
解答:输入的labels是choose_action实际选择的动作,在sparse_softmax_cross_entropy_with_logits公式里其实就只是起到一个让交叉熵只计算实际动作对应概率的负对数值的作用,没采取的动作的labels对应0从而不计入交叉熵。例如某一step实际选择了3号动作,则sparse_softmax_cross_entropy_with_logits返回的就是3号动作对应预测概率的负对数值。之后再reduce_mean步骤中乘上该动作得到的未来折扣奖励R,就得到了-(log_p * R)的loss。
简单说,sparse_softmax_cross_entropy_with_logits返回的就是所选动作的负对数,参数labels起到指明所选动作的作用。
与理论上根本的奖励函数是一致的,就是使期望奖励最大,也就是奖励*该奖励对应的概率。使用对数概率是普遍做法,说法是对数形式有更高的收敛性。所以就说通了,强化学习损失函数的实现用该函数是正确的。
with tf.name_scope('loss'):
# 一个episode调用一次learn、传入整个episode的数据、计算一次loss。
# tf_acts是这个batch每一步的实际动作序号(由choose_action函数依照神经网络输出的概率随机选出),all_act应该是这个batch每一步对应网络的输出值,
# 目标是让total reward (log_p * R)最大,也就是让-(log_p * R)最小。
# *R在reduce_mean的时候同时进行,所以sparse_softmax_cross_entropy_with_logits就是在求-log_p。也即该奖励出现的概率的对数。
# 该奖励对应的是choose_action实际选择的动作,理论上应该求神经网络输出该动作的概率。sparse_softmax_cross_entropy_with_logits也正是在求这个,就是概率的负对数值。
# to maximize total reward (log_p * R) is to minimize -(log_p * R), and the tf only have minimize(loss)
neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=all_act, labels=self.tf_acts) # this is negative log of chosen action
# all_act是神经网络输出的还没转成概率分布的各个动作对应值,self.tf_acts是实际采用的动作(交互时存储并feed进来的),都是一个episode的数据
# 一个episode调用一次learn,learn feed给self.train_op的是一个episode的数据也即三个列表,列表的长度即为该episode里step的个数。step个数相当于是batch_size。计算neg_log_prob的时候是对每个step的数据计算,得到的是一个列表。
# self.tf_vt也是一个列表,每个值表示该步的动作价值,也就是该步的未来折扣奖励和。
loss = tf.reduce_mean(neg_log_prob * self.tf_vt) # 对这个episode所有step对应的loss求平均作为episode的loss。求loss时在sparse_softmax_cross_entropy_with_logits后面都会跟上reduce_mean。
with tf.name_scope('train'):
self.train_op = tf.train.AdamOptimizer(self.lr).minimize(loss) # 使用Adam梯度下降使loss最小
5.公式复习