永兴的Tensorflow笔记-7 损失函数以及神经网络的基本属性

在这里插入图片描述

一、神经网络的基本属性:

神经网络 的四个基本属性:

  • (1)非线性:非线性是自然界的普遍特征。人脑智能就是一种非线性现象。人工神经元处于两种不同的激活或抑制状态,它们在数学上是非线性的。由阈值神经元组成的网络具有更好的性能,可以提高网络的容错性和存储容量。
  • (2)无限制性:神经网络通常由多个连接广泛的神经元组成。一个系统的整体行为不仅取决于单个神经元的特性,而且还取决于单元之间的相互作用和互连。通过单元之间的大量连接来模拟大脑的非限制性。联想记忆是一个典型的无限制的例子。
  • (3)非常定性:人工神经网络具有自适应、自组织和自学习的能力。神经网络处理的信息不仅会发生变化,而且非线性动态系统本身也在发生变化。迭代过程通常用来描述动态系统的演化。
  • (4)非凸性:在一定条件下,系统的演化方向取决于特定的状态函数。例如,能量函数的极值对应于系统的相对稳定状态。非凸性是指函数具有多个极值,系统具有多个稳定平衡态,从而导致系统演化的多样性。

此外:
1、神经网络的复杂度:
一般用神经网络的层数和神经网络中待优化参数个数表示。
2、神经网络的层数:
一般不计入输入层,层数 = n 个隐藏层 + 1 个输出层
3、神经网路待优化的参数:
神经网络中所有参数 w 的个数 + 所有参数 b 的个数

二、什么是损失函数?

  • 损失函数(loss function)或代价函数(cost function)是将随机事件或其有关随机变量的取值映射为非负实数以表示该随机事件的“风险”或“损失”的函数。在应用中,损失函数通常作为学习准则与优化问题相联系,即通过最小化损失函数求解和评估模型。

三、为什么要使用损失函数?

  • 机器学习中被用于模型的参数估计(parameteric estimation),机器学习中,损失函数是模型输出和正确结果间概率分布差异的量化,计算损失(loss)
  • 损失(loss):用来表示预测值(y)与已知答案(y_)的差距。在训练神经网络时,通过不断 改变神经网络中所有参数,使损失函数不断减小,从而训练出更高准确率的神经网络模型 。

四、基本函数:

1、tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)

函数用于从服从指定正态分布的数值中取出指定个数的值。

  • shape: 输出张量的形状,必选
  • mean: 正态分布的均值,默认为0
  • stddev: 正态分布的标准差,默认为1.0
  • dtype: 输出的类型,默认为tf.float32
  • seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样
  • name: 操作的名称
2、tf.greater(a,b)

功能:比较a、b两个值的大小
返回值:一个列表,元素值都是true和false

3、tf.where:函数有三个参数,根据第一个条件是否成立,当为True的时候选择第二个参数中的值,否则使用第三个参数中的值。
4、tf.clip_by_value(1-y,1e-10,1.0) 运用的是交叉熵而不是二次代价函数。

功能:可以将一个张量中的数值限制在一个范围之内。(可以避免一些运算错误:可以保证在进行log运算时,不会出现log0这样的错误或者大于1的概率)

  • 参数:(1)1-y:input数据(2)1e-10、1.0是对数据的限制。
    • 当1-y小于1e-10时,输出1e-10;
    • 当1-y大于1e-10小于1.0时,输出原值;
    • 当1-y大于1.0时,输出1.0;
5、tf.argmax(input,axis)根据axis取值的不同返回每行或者每列最大值的索引。
  • 参数:
    • _sentinel:用于防止positional参数。内部的,不要使用。
    • labels:一个Tensor,与logits具有相同的类型和shape。
    • logits:一个Tensor,类型为float32或float64。
    • name:操作的名称(可选)。
6、tf.reduce_mean 函数用于计算张量tensor沿着指定的数轴(tensor的某一维度)上的的平均值,主要用作降维或者计算tensor的平均值。
reduce_mean(input_tensor,
                axis=None,
                keep_dims=False,
                name=None,
                reduction_indices=None)
  • 第一个参数input_tensor: 输入的待降维的tensor;
  • 第二个参数axis: 指定的轴,如果不指定,则计算所有元素的均值;
  • 第三个参数keep_dims:是否降维度,设置为True,输出的结果保持输入* * tensor的形状,设置为False,输出结果会降低维度;
  • 第四个参数name: 操作的名称;
  • 第五个参数 reduction_indices:在以前版本中用来指定轴,已弃用;

五、如果选择正确的损失函数?

损失函数可以让我们看到模型的优劣,并且为我们提供了优化的方向,但是我们必须知道没有任何一种损失函数适用于所有的模型。损失函数的选取依赖于参数的数量、异常值、机器学习算法、梯度下降的效率、导数求取的难易和预测的置信度等若干方面。

对应回归问题我们一般选择均方误差。(回归预测建模是将输入变量(X)的映射函数(f)近似为连续输出变量(y)的任务。比如:预测房屋可以出售特定的价值)

1、均方误差(mse):

n 个样本的预测值 y 与已知答案 y_之差的平方和,再求平均值。
数学表达式:
在这里插入图片描述
tensorflow下:

loss_mse = tf.reduce_mean(tf.square(y_ - y)) #均方误差 (一般y_为答案 y为计算结果)
  • 例题1:
    预测酸奶日销量 y,x1 和 x2 是影响日销量的两个因素。
    应提前采集的数据有:一段时间内,每日的 x1 因素、x2 因素和销量 y_。采集的数据尽量多。
    在本例中用销量预测产量,最优的产量应该等于销量。由于目前没有数据集,所以拟造了一套数 据集。利用 Tensorflow 中函数随机生成 x1、 x2,制造标准答案 y_ = x1 + x2,为了更真实,求和后 还加了正负 0.05 的随机噪声。
    我们把这套自制的数据集喂入神经网络,构建一个一层的神经网络,拟合预测酸奶日销量的函数。
import tensorflow as tf
import numpy as np
seed = 23455 #随机种子
batahSize = 8 #定义每一轮喂入数据的数量
STEPS = 20000 #训练轮数

rdm = np.random.RandomState(seed) #设置的seed相同取出地随机数就一样
X = rdm.rand(32,2) #生成 [32,2] 的随机数矩阵

Y = [[x1+x2+(rdm.rand()/10.0-0.05)] for (x1,x2) in X]
# 等价于
# Y = []
# for x1,x2 in X :
#     Y.append([x1+x2+(rdm.rand()/10.0-0.05)])

#定义神经网络的输入
x = tf.placeholder(tf.float32,shape=(None,2))
y_ = tf.placeholder(tf.float32,shape=(None,1))

#定义学习参数:权重w
w1 = tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))

#定义 前向传播的过程 OP
y = tf.matmul(x,w1)

#定义损失函数
loss = tf.reduce_sum(tf.square(y_-y))

#设置优化器。设定学习率
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss)

init = tf.global_variables_initializer()
with tf.Session() as sess :
    sess.run(init)
    for i in range(STEPS):
        start = (i*batahSize) % 32 #数据只有32组,不断利用
        end = (i*batahSize) % 32 + batahSize
        sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]})
        if i % 200 == 0:
            print("第%d轮"%i)
            print("loss:",sess.run(loss,feed_dict={x:X[start:end],y_:Y[start:end]}))
    print("最后一次训练的loss为:",sess.run(loss,feed_dict={x:X[start:end],y_:Y[start:end]}))

在分类问题中,我们一般使用交叉熵作为损失函数:

2、交叉熵(Cross Entropy):

表示两个概率分布之间的距离。交叉熵越大,两个概率分布距离越远,两个概率分布越相异;交叉熵越小,两个概率分布距离越近,两个概率分布越相似。
交叉熵计算公式:
在这里插入图片描述
tensorflow 二分类问题下:

ce= -tf.reduce_mean(y_* tf.log(tf.clip_by_value(y, 1e -12, 1.0)))
  • 另外我们还可以用来测试神经网络准确性的比较:
    两个神经网络模型解决二分类问题中,已知标准答案为 y_ = (1, 0),第一个神经网络模型预测结果为
    6 y1=(0.6, 0.4),第二个神经网络模型预测结果为 y2=(0.8, 0.2),判断哪个神经网络模型预测的结果更接 近标准答案。
    根据交叉熵的计算公式得:
    H1((1,0),(0.6,0.4)) = -(1log0.6 + 0log0.4) ≈ -(-0.222 + 0) = 0.222
    H2((1,0),(0.8,0.2)) = -(1log0.8 + 0log0.2) ≈ -(-0.097 + 0) = 0.097
    由于 0.222>0.097,所以预测结果 y2 与标准答案 y_更接近,y2 预测更准确。

另外在tensorflow中
针对分类问题,有四个交叉熵函数,分别是:

1、tf.nn.sigmoid_cross_entropy_with_logits
output = tf.nn.sigmoid_cross_entropy_with_logits(logits=y, labels=y_))
  • 计算方式:对输入的logits先通过sigmoid函数计算,再计算它们的交叉熵,但是它对交叉熵的计算方式进行了优化,使得的结果不至于溢出。
    • 适用:每个类别相互独立但互不排斥的情况:例如一幅图可以同时包含一条狗和一只大象。
    • output不是一个数,而是一个batch中每个样本的loss,所以一般配合tf.reduce_mean(loss)使用。
  • 返回:
    • 与具有分量logistic损失的logits有着相同shape的Tensor。
    • 可能引发的异常:
      ValueError:如果logits和labels没有相同的shape。
softmax 函数:将 n 分类的 n 个输出(y1,y2…yn)变为满足以下概率分布要求的函数。

在这里插入图片描述
在这里插入图片描述
softmax 函数应用:在 n 分类中,模型会有 n 个输出,即 y1,y2…yn,其中 yi 表示第 i 种情况出现的可 能性大小。将 n 个输出经过 softmax 函数,可得到符合概率分布的分类结果。

2、tf.nn.softmax_cross_entropy_with_logits
tf.nn.softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, dim=-1, name=None)
  • 参数:
    • _sentinel:用于防止positional参数。内部的,不要使用。
    • labels:沿着类维度的每个向量应该保持有效的概率分布,例如:对于标签shape为[batch_size, num_classes]的情况,labels[i]的每一行必须是有效的概率分布。
    • logits:未缩放的日志概率。
    • dim:类维度。默认为-1,这是最后一个维度。
    • name:操作的名称(可选)。
  • 返回:
    • 一个Tensor,包含softmax交叉熵损失的。它的类型与logits相同,它的shape与labels是相同的,除了它没有labels的最后一个维度。
  • 计算方式:对输入的logits先通过softmax函数计算,再计算它们的交叉熵,但是它对交叉熵的计算方式进行了优化,使得结果不至于溢出。
  • 适用:每个类别相互独立且排斥的情况,一幅图只能属于一类,而不能同时包含一条狗和一只大象。
  • output:不是一个数,而是一个batch中每个样本的loss,所以一般配合tf.reduce_mean(loss)使用。
3、tf.nn.sparse_softmax_cross_entropy_with_logits
tf.nn.sparse_softmax_cross_entropy_with_logits(_sentinel=None,labels=None,logits=None, name=None)
  • 参数:
    • _sentinel:用于防止位置参数。内部,不要使用。
    • labels:Tensor,shape为[d_0, d_1, …, d_{r-1}](其中r是labels的秩和结果)并且类型为int32或int64。每个labels中的条目必须是[0, num_classes)中的索引。当此操作在CPU上运行时,其他值将引发异常,并返回NaN,以获取GPU上相应的损失和梯度行。
    • logits:shape为[d_0, d_1, …, d_{r-1}, num_classes]和类型为float16,float32或 float64的未缩放日志概率。
    • name:操作的名称(可选)。
  • 返回:
    • 一个Tensor,与labels形状相同、与具有SoftMax交叉熵损失的logits具有相同的类型。
  • 计算方式:对输入的logits先通过softmax函数计算,再计算它们的交叉熵,但是它对交叉熵的计算方式进行了优化,使得结果不至于溢出。
  • 适用:每个类别相互独立且排斥的情况,一幅图只能属于一类,而不能同时包含一条狗和一只大象 。
  • output不是一个数,而是一个batch中每个样本的loss,所以一般配合tf.reduce_mean(loss)使用。

在 Tensorflow 中,一般让模型的输出经过 sofemax 函数,以获得输出分类的概率分布,再与标准 答案对比,求出交叉熵,得到损失函数,用如下函数实现:

ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
cem = tf.reduce_mean(ce)
4、tf.nn.weighted_cross_entropy_with_logits
tf.nn.weighted_cross_entropy_with_logits(labels,logits, pos_weight, name=None) 
  • 计算具有权重的sigmoid交叉熵sigmoid_cross_entropy_with_logits()
    logits和target必须具有相同的类型和形状。
  • 参数:
    • labels:一个张量,与logits具有相同的类型和形状。
    • logits:一个张量,类型为float32或float64。
    • pos_weight:正样本中使用的系数。
    • name:操作的名称(任选)。
  • 返回:
    • 与具有常量预算逻辑损失的日志具有相同形状的张量。

3、自定义损失函数:

根据问题的实际情况,定制合理的损失函数。
例如:
对于预鲜牛奶日销量问题,如果预测销量大于实际销量则会损失成本;如果预测销量小于实际销量则 会损失利润。在实际生活中,往往制造一盒鲜牛奶的成本和销售一盒鲜牛奶的利润是不等价的。因此,需要使用符合该问题的自定义损失函数。
自定义损失函数为:
在这里插入图片描述
其中,损失定义成分段函数:
在这里插入图片描述
损失函数表示,若预测结果 y 小于标准答案 y_,损失函数为利润乘以预测结果 y 与标准答案 y_之差; 若预测结果 y 大于标准答案 y_,损失函数为成本乘以预测结果 y 与标准答案 y_之差。
用 Tensorflow 函数表示为:
loss = tf.reduce_sum(tf.where(tf.greater(y,y_),COST(y-y_),PROFIT(y_-y)))
在这里插入图片描述

import tensorflow as tf
import numpy as np
seed = 23455 #随机种子
batahSize = 8 #定义每一轮喂入数据的数量
cost = 1 #酸奶成本1元,利润9元
profit = 9
STEPS = 20000 #训练轮数

rdm = np.random.RandomState(seed) #设置的seed相同取出地随机数就一样
X = rdm.rand(32,2) #生成 [32,2] 的随机数矩阵

Y = [[x1+x2+(rdm.rand()/10.0-0.05)] for (x1,x2) in X]
# 等价于
# Y = []
# for x1,x2 in X :
#     Y.append([x1+x2+(rdm.rand()/10.0-0.05)])

#定义神经网络的输入
x = tf.placeholder(tf.float32,shape=(None,2))
y_ = tf.placeholder(tf.float32,shape=(None,1))

#定义学习参数:权重w
w1 = tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))

#定义 前向传播的过程 OP
y = tf.matmul(x,w1)

#定义损失函数
#酸奶成本1元,利润9元
loss = tf.reduce_sum(tf.where(tf.greater(y,y_),(y-y_)*cost,(y_-y)*profit))

#设置优化器。设定学习率
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss)

init = tf.global_variables_initializer()
with tf.Session() as sess :
    sess.run(init)
    for i in range(STEPS):
        start = (i*batahSize) % 32 #数据只有32组,不断利用
        end = (i*batahSize) % 32 + batahSize
        sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]})
        if i % 200 == 0:
            print("第%d轮"%i)
            print("loss:",sess.run(loss,feed_dict={x:X[start:end],y_:Y[start:end]}))
    print("最后一次训练的loss为:",sess.run(loss,feed_dict={x:X[start:end],y_:Y[start:end]}))

由代码执行结果可知, 神经网络最终参数为 w1=1.03, w2=1.05,销量预测结果为 y =1.03x1 + 1.05x2。由此可见,采用自定义损失函数预测的结果大于采用均方误差预测的结果,更符合实际需求。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由执行结果可知,神经网络最终参数为 w1=0.96,w2=0.97,销量预测结果为 y =0.96x1 + 0.97x2。 因此,采用自定义损失函数预测的结果小于采用均方误差预测的结果,更符合实际需求。

本文有借鉴:北京大学助教的Tensorflow笔记

发布了45 篇原创文章 · 获赞 28 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/m0_43505377/article/details/103908993