激活函数去线性化
常用的有tf.nn.relu、tf.sigmoid(0~1)、tf.tanh(-1~1)。
经典损失函数-分类问题(交叉熵cross entropy)
cross_entropy = -tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,1)))
注意这里的y_,y可能为一个矩阵,需要注意的是要使用“*”而不是使用tf.matmul(),因为我们不是想要使用矩阵乘法。具体区别在书77页。
得到一个n x m大小的矩阵后,n是batch_size,m为分类的类数。reduce_mean来取平均值。
有个疑问就是按照交叉熵的公式应该是把n * m个数加起来除以n,但是如果使用reduce_mean是除以n*m。
Tensorflow的封装
因为交叉熵一般会与softmax回归一起使用,所以进行了封装
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=y)
在只有一个正确答案的分类问题中,下面这个函数可以进一步加速计算过程 //sparse:稀少的,稀疏的
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y_,logits=y)
经典损失函数-回归问题(均方误差MES,mean squared error)
mse = tf.reduce_mean(tf.square(y_ - y))
自定义损失函数
例如:在预测商品销量时,如果预测多了厂家会损失成本,预测少了厂家会损失利润,但是每个产品成本只有一块,而利润有十块,这时均方误差就不能很好的最大化销售利润。
这时的损失函数可以设定为当y(预测数据)>y_,loss = 1(y - y_);当y<_y,loss = 10(y - y_)。通过这样的自定义损失函数的优化,模型提供的预测值更有可能最大化收益。
可以通过以下代码来实现这个损失函数 //reduce有缩小的意思,可以理解为缩小维度
loss = tf.reduce_sum(tf.where(tf.greater(y, y_), (y - y_) * 1, (y_ - y) * 10))
使用下面的程序测试以下这个损失函数的效果
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_), loss_more * (y - y_), loss_less * (y_ - y)))
train_step = tf.train.AdamOptimizer(0.001).minimize(loss)
# 通过随机数生成一个模拟数据集
rdm = RandomState(1)
data_size = 128
X = rdm.rand(data_size, 2)
# 设置回归的正确值为两个输入的和加上一个随机量
# 加上随机量的是因为避免最后能完全正确预测,不同的损失函数的效果就看不出来了
Y = [[x1 + x2 + rdm.random() / 10.0 - 0.05] for (x1, x2) in X]
# 训练神经网络
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
STEP = 20000
for i in range(STEP):
start = (i * batch_size) % data_size
end = min(start + batch_size, data_size)
sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
if i % 1000 == 0:
print(sess.run(w1))
最后可以发现w1的值都比[1,1]要大。可以通过改变loss_less,loss_more的值来感受区别。