1. 深层网络介绍
激活函数实现去线性化
在没有加入激活函数的时候,一个模型的运算其实就是输出是输入的线性加权和,不管中间有多少的隐层,因为每个隐藏层都是在做一个线性变换,后面不管再加上多少隐藏层,都是在做线性变换,因为线性模型的特点就是任意线性模型的组合任然是线性模型。
比如前向传播的计算公式:
a(1)=XW(1),y=a(1)W(2)
a
(
1
)
=
X
W
(
1
)
,
y
=
a
(
1
)
W
(
2
)
其中x为输入,w为参数,整理得:
y=X(W(1)W(2))=XW′
y
=
X
(
W
(
1
)
W
(
2
)
)
=
X
W
′
所以可以看出不管中间的隐藏层有多少层,其效果和一层隐藏层是一样的,都是线性的变换,而现实中的例子都是非线性的,此时的深度网络只通过加深网络层是没有改变线性的本质,这时,通过在神经元中加入激活函数(非线性函数),可以实现非线性变换。
tensorflow提供了7种不同的非线性激活函数,其中常用的是:
- tf.nn.relu
- tf.sigmoid
- tf.tanh
2. 经典损失函数
首先神经网络模型的效果以及优化的目标是通过损失函数来定义的。
在一般的二分类中,常通过sigmoid函数来把输出映射到0-1之间,这时一般取0.5作为阈值分割点,大于0.5的被分类到正类,小于0.5的被分类到负类。而在多分类中,理论上可以通过设置多个阈值区间来进行多分类,但在解决实际问题时并不常用,常用的是在输出层设置n个节点,每个节点代表一类。有了这个思想,我们就可以由此对样本打标签,比如:[0,1,0,0,0,1]
,其中一个节点为1,其他的都为0。那么此时的网络输出也应该是类似的形式,但实际的输出并不具有概率意义,这个时候就有了softmax层的出现,把实际输出转换成一个概率分布。有了期望输出和实际输出,当然要进行损失函数的确定,一般都是用交叉熵损失函数。
简单总结就是:原始的神经网络输出通过softmax层作用后被用作置信度来生成新的输出,而新的输出满足概率分布的所有要求。这个新的输出可以理解为经过神经网络的推到,一个样例为不同类别的概率分别为多大,这样就把神经网络的输出也变成了一个概率分布,这个时候就可以通过交叉熵来计算预测输出和真实分类的概率分布之间的差距了。
交叉熵为:
H(p,q)=−∑xp(x)logq(x)
H
(
p
,
q
)
=
−
∑
x
p
(
x
)
l
o
g
q
(
x
)
从交叉熵的公式中可以看到交叉熵函数是不对称的(
H(p,q)≠H(q,p)
H
(
p
,
q
)
≠
H
(
q
,
p
)
,它刻画的是通过概率分布q来表达概率分布p的困难程度。因为正确分类是希望得到的结果,所以当交叉熵作为损失函数时,p代的是正确分类,而q代表的是预测值。交叉熵刻画的是两个概率分布的距离,也就是说交叉熵越小,两个概率分布越接近。
具体可以参考:https://blog.csdn.net/lilong117194/article/details/81542667
在只有一个正确答案的分类问题中,tensorflow提供了tf.nn.sparse_softamx_cross_entropy_with_logits
函数来进一步加速计算。
在预测问题中常用的损失函数是均方误差损失函数:
MSE(y,y′)=∑ni=1(yi−y′i)2n
M
S
E
(
y
,
y
′
)
=
∑
i
=
1
n
(
y
i
−
y
i
′
)
2
n
在tensorflow中实现是:mse=tf.reduce_mean(tf.square(y_ - y))
,其中的-
也是两个矩阵中对应元素的减法。
3. 自定义损失函数
tensorflow不仅支持经典的损失函数,还可以优化任意的自定义损失函数。
下面的例子是预测商品的销售量问题。如果预测值比实际值大,则商家损失的是生产商品的成本,而如果预测的值小于实际值,则损失的是商品的利润。这里由于在大部分情况下商品的成本和商品的利润是不会严格相等的,也就是说如果使用上述的均方误差损失函数就不能最大化销售利润,因为当预测和实际值相等时,这时并不是最大化的利润,所以这个时候就要换个思路,不能再用均方误差函数了,需要自定义一个损失函数。
例如:一个商品的成本是1元,但是利润是10元,那么少预测一个就少挣10元,而多预测一个才少挣1元。
这里要注意的是损失函数是定义的损失,而要最大化利润就要把损失函数刻画成成本和代价,下面给出一个损失函数:
得到: loss(y,y′)=∑ni=1f(yi,y′i) l o s s ( y , y ′ ) = ∑ i = 1 n f ( y i , y i ′ )
这里 y′ y ′ 是预测值, y y 是正确值,就是上述的10, b b 就是1。
从公式可以推导出:
- 是预测小于真实值时的损失,这里a是10,权重大于b,就说明在最小化损失函数时,惩罚比较大,即是对于少预测大损失的情况要尽可能少的发生。
- 相反
b(y−x)
b
(
y
−
x
)
是预测值大于真实值的损失,这里的权重比较小,惩罚也比较小。
此时模型提供的预测值有可能最大化收益。 tensorflow中通过以下实现:
loss = tf.reduce_sum(tf.select(tf.greater(y, y_), (y - y_) * loss_more, (y_ - y) * loss_less))
tf.greater
:比较输入两个输入张量中的每个元素的大小,当输入的张量维度不一致时,tensorflow会通过numpy广播操作的处理。
tf.select
:有三个输入参数,当第一个选择条件根据,当为true时选择输出第二个参数中的值,否则选择输出第三个参数的值。
例如:import tensorflow as tf v1=tf.constant([1.0,2.0,3.0,4.0]) v2=tf.constant([4.0,3.0,2.0,1.0]) sess=tf.InteractiveSession() print(tf.greater(v1,v2).eval()) print(tf.where(tf.greater(v1,v2),v1,v2).eval()) sess.close()
运行结果:
[False False True True] [4. 3. 3. 4.]
示例:
import tensorflow as tf from numpy.random import RandomState # 定义神经网络的相关参数和变量 batch_size = 8 x = tf.placeholder(tf.float32, shape=(None, 2), name="x-input") y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input') # 定义一个单层的神经网络前向传播过过程,这里只是简单的加权和 w1= tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1)) y = tf.matmul(x, w1) # 定义损失函数使得预测少了的损失大,于是模型应该偏向多的方向预测。 loss_less = 10 loss_more = 1 loss = tf.reduce_sum(tf.where(tf.greater(y, y_), (y - y_) * loss_more, (y_ - y) * loss_less)) train_step = tf.train.AdamOptimizer(0.001).minimize(loss) rdm = RandomState(1) X = rdm.rand(128,2) # 设置回归的正确值为两个输入和加上一个随机量,也就是一个不可预测的噪音 Y = [[x1+x2+(rdm.rand()/10.0-0.05)] for (x1, x2) in X] with tf.Session() as sess: init_op = tf.global_variables_initializer() sess.run(init_op) STEPS = 5000 for i in range(STEPS): start = (i*batch_size) % 128 end = (i*batch_size) % 128 + batch_size sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]}) if i % 1000 == 0: print("After %d training step(s), w1 is: " % (i)) print(sess.run(w1), "\n") print ("Final w1 is: \n", sess.run(w1))
运行结果:
After 0 training step(s), w1 is: [[-0.81031823] [ 1.4855988 ]] After 1000 training step(s), w1 is: [[0.01247112] [2.1385448 ]] After 2000 training step(s), w1 is: [[0.45567414] [2.1706066 ]] After 3000 training step(s), w1 is: [[0.69968724] [1.8465308 ]] After 4000 training step(s), w1 is: [[0.89886665] [1.2973602 ]] Final w1 is: [[1.019347 ] [1.0428089]]
这里得到的结果会更偏向于预测多一点。
注意:
- 为了使得预测多了的时候损失大,这时模型应该往预测少的方向预测,这里只需要改变
loss_less = 1,loss_more = 10
- 当定义损失函数为MSE时,预测会和真实值比较接近,但是不是最大化利润的损失函数。
参考:《Tensorflow实战Google深度学习框架》
- 为了使得预测多了的时候损失大,这时模型应该往预测少的方向预测,这里只需要改变
- 相反
b(y−x)
b
(
y
−
x
)
是预测值大于真实值的损失,这里的权重比较小,惩罚也比较小。