深度学习算法学习(三):损失函数-均方差、交叉熵(Cross Entropy)

28 阅读3分钟

损失函数

损失函数-均方差

MSE mean square error

对均方差在做开根号,可以得到根方差

image.png

损失函数-交叉熵

Cross Entropy常用于分类任务分类任务中,网络输出经常是所有类别上的概率分布

公式

image.png

例子

  • 数据会先过激活函数Softmax,做归一化处理得到类似 [1, 0, 0],然后再进入交叉熵函数
  • 假设一个三分类任务,某样本的正确标签是第一类,则p = [1, 0, 0]
  • 模型预测值假设为[0.5, 0.4, 0.1], 则交叉熵计算如下(log是以e为底的2.71828):
image.png

代码

import torch
import torch.nn as nn
import numpy as np

#使用torch计算交叉熵
ce_loss = nn.CrossEntropyLoss()
#假设有3个样本,每个都在做3分类
pred = torch.FloatTensor([[0.3, 0.1, 0.3],
                          [0.9, 0.2, 0.9],
                          [0.5, 0.4, 0.2]])
# 正确的类别分别为1,2,0
target = torch.LongTensor([1,2,0])

# 计算交叉熵, 交叉熵损失的值域是 [0,+∞)。值越小,说明模型预测得越准确
loss = ce_loss(pred, target)
print("torch输出交叉熵:", loss, "\n")

"""
实现softmax函数
1、 np.exp(matrix) 将输入矩阵中的每个元素进行指数计算
2、 np.sum(np.exp(matrix), axis=1, keepdims=True) 对指数化后的矩阵进行行求和
    axis=1表示沿着行的方向进行求和,keepdims=True表示保持求和后结果的维度是二维的
3、 exp_matrix / sum_of_rows 计算softmax概率
"""
def softmax(matrix):
    exp_matrix = np.exp(matrix)
    print("softmax归一化处理 矩阵每个值指数计算:", exp_matrix, "\n")
    sum_of_rows = np.sum(exp_matrix, axis=1, keepdims=True)
    print("softmax归一化处理 矩阵行求和:", sum_of_rows, "\n")
    return exp_matrix / sum_of_rows

"""
    将输入转化为onehot矩阵
    将[1,2,0]转换为
     [0, 1, 0]
     [0, 0, 1]
     [1, 0, 0]
"""
def to_one_hot(target, shape):
    one_hot_target = np.zeros(shape)
    for i, t in enumerate(target):
        one_hot_target[i][t] = 1
    return one_hot_target


# 手动实现交叉熵
def cross_entropy(pred, target):
    print("=======================手动实现交叉熵=======================")
    batch_size, class_num = pred.shape
    print("输入矩阵的维度 batch_size:", batch_size, " class_num:",class_num, "\n")
    print("输入矩阵 pred:", pred, "\n")
    pred = softmax(pred)
    print("softmax归一化处理 输出矩阵 pred:", pred, "\n")
    print("正确类别 target:", target, "\n")
    target = to_one_hot(target, pred.shape)
    print("通过onehot矩阵后的正确类别 target:", target, "\n")
    """
        计算交叉熵
        np.log(pred) 计算预测概率的对数
        target * np.log(pred) 逐元素相乘
        - np.sum( ... , axis=1) 求和并取负, axis=1表示对每个样本的所有类别维度进行求和
    """
    entropy = - np.sum(target * np.log(pred), axis=1)

    """
        sum(entropy):将上一步得到的每个样本的损失值加在一起,得到这个批次的总损失。
        / batch_size:用总损失除以批次中的样本数量,得到平均损失。这个平均损失才是模型本次预测的最终损失值
    """
    return sum(entropy) / batch_size

print("手动实现交叉熵:", cross_entropy(pred.numpy(), target.numpy()))

输出

torch输出交叉熵: tensor(1.0414) 

=======================手动实现交叉熵=======================
输入矩阵的维度 batch_size: 3  class_num: 3 

输入矩阵 pred: [[0.3 0.1 0.3]
 [0.9 0.2 0.9]
 [0.5 0.4 0.2]] 

softmax归一化处理 矩阵每个值指数计算: [[1.3498588 1.105171  1.3498588]
 [2.459603  1.2214028 2.459603 ]
 [1.6487212 1.4918246 1.2214028]] 

softmax归一化处理 矩阵行求和: [[3.8048885]
 [6.140609 ]
 [4.3619485]] 

softmax归一化处理 输出矩阵 pred: [[0.3547696  0.2904608  0.3547696 ]
 [0.40054712 0.19890581 0.40054712]
 [0.37797815 0.34200877 0.2800131 ]] 

正确类别 target: [1 2 0] 

通过onehot矩阵后的正确类别 target: [[0. 1. 0.]
 [0. 0. 1.]
 [1. 0. 0.]] 

手动实现交叉熵: 1.0413764715194702