如何定义损失?
我们将使用占位符(placeholder)来表示标签(label),作为我们只在运行使喂给的数据,使用label和prediction建立一个损失节点(loss node)
prediction=tf.nn.softmax(……) #神经网络输出的预测值
label=tf.placeholder(tf.float32,[100,10])
cross_entropy=-tf.reduce_sum(label*tf.log(prediction),axis=1)
第一行:这是对神经网络顶层进行softmax函数计算,输出一个概率向量,这是一个回归过程,一个迹象就是神经网络前馈阶段结束的地方就是神经网络预测出值的地方
第二行:定义一个占位符,模型训练就是根据这些标签来训练,这些label的每一行都是一个one-hot向量
第三行:创建交叉熵节点,就是标签乘以tensorflow中对prediction取对数的乘积(我觉得相当于prediction这个值乘以label这个矩阵),每一行就都变成只有一个值其他全为0,再按行求和(相当于挤压成了一列),然后返回一个列表。
reduce就是“对矩阵降维”的含义,下划线后面的部分就是降维的方式,在reduce_sum()中就是按照求和的方式对矩阵降维
axis=1以后就是将一个矩阵的每一行向量相加
计算梯度
tensorflow中有一个通用的抽象类叫做优化器,在这个类中每一个子类都是一个针对特定学习算法的优化器,我们目前使用的学习算法是梯度下降算法。
prediction=tf.nn.softmax(……) #神经网络输出的预测值
label=tf.placeholder(tf.float32,[100,10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(label* tf.log(prediction), reduction_indices=[1])) #按行求和
train_step=tf.train.GradientDescentOptumizer(0.5).minimize(cross_entropy)#设置学习率为0.5 #返回list格式
tf.train.GradientDescentOptumizer是创建优化节点的对象,然后对此调用.minimize()函数方法,参数是我们想要最小化的节点。minimize() 函数做了两件事情:
- 计算参数的梯度。这里的参数是交叉熵,它又与图中定义的所有变量有关,即W、b。
- 根据梯度计算更新这些参数变量。
这两件事情拆开的好处是,可以对计算的梯度进行限制,防止梯度消失和爆炸。
那如何计算梯度的呢?在Tensorflow中的工作方式是 每一个图节点都有一个附加的梯度操作,都有相对于输入预先构建的输出梯度。所以我们计算交叉熵,相对于所有参数的梯度时,是通过使用链式法则利用反向传播计算实现的。
机器学习框架表示为计算图表的主要优势是:程序容易回退,在图形中向后遍历,并在每一个节点上将误差信号乘以节点的预定义梯度。以上这些都是自动实现的
训练模型-----创建一个迭代的学习计划
sess.run(train_step,feeds)
1.创建session对象
2.构建训练模型
3.运行迭代
sess=tf.Session()
sess.run(tf.initialize_all_variables())
for i in range(1000):
batch_x,batch_label=data.next_batch()#输入一个批次的实际数据以及相应的标签值
sess.run(train_step,feed_dict={x:batch_x,label:batch_label}
#对图中的所有变量应用梯度
#将数据赋值给之前就定义好的占位符placeholder:x和label时图中的节点。字典的关键字是图中的节点,对应的项是numpy数据
这就是tensorflow提供numpy接口的地方,tensorflow自动把图中节点的数据转换为张量。
如果此时定义一个变量叫output,使得output=sess.run(train_step,feed_dict={x:batch_x,label:batch_label},那么这个变量是对应节点的numpy数组,也就是这些节点评估的值
将模型封装成类
如果想一次性在不同的设备上训练模型,并且实例化或者建模,就要用到变量分享。
或许首先想到的是建立这个变量的字典或者把这些变量设置为全局变量。
例如:variables_dict={
“weights”:tf.Variable(tf.random_normal([782,100]),names=“weights”)
“biases”:tf.Variables(tf.zeros([100]),names=“biases”)
}
但是存在的问题是打破了封装性,这些变量必须文档化被其他代码文件引用,一旦代码变化,调用方也可能需要变化。
保证封装性的方式可以是将模型封装成类。
TensorFlow提供了Variable Scope 这种独特的机制来共享变量:
- tf.variable_scope() 提供了一个简单的命名空间来避免冲突
- tf.get_variable() 创建一个之前没有的变量,如果之前存在,它将访问该变量
with tf.variable_scope("foo"): #指定了第一个卷积层作用域为foo
#创建并返回叫做"v"的变量
v=tf.get_variable("v",shape=[1]) #v.name=="foo/v:0"
with tf.variable_scope("foo",reuse=True): #设置为重用foo目录下的v变量
v1=tf.get_variable("v") #shared variable found! 访问成功
with tf.variable_scope("foo",reuse=False): #设置为不重用
v1=tf.get_variable("v") #CRASh foo/v:0 already exists!!!崩溃
总结
- 我们学会了在Tensorflow中建立一个图,该图形具有前馈和预测的特征,还可以通过梯度计算和建立训练操作优化神经网络中的变量,就是将梯度更新应用到参数上
- 初始化Session对象,session会将图部署到硬件上,例如闯进啊一个与运行环境来运行程序
- 建立一个简单的迭代学习计划(session.run(train_step,feed_dict))不断运行和训练我们的模型