深度学习:关于损失函数的一些前置知识(PyTorch Loss)

2024-06-23 16:28

本文主要是介绍深度学习:关于损失函数的一些前置知识(PyTorch Loss),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在之前进行实验的时候发现:调用 Pytorch 中的 Loss 函数之前如果对其没有一定的了解,可能会影响实验效果和调试效率。以 CrossEntropyLoss 为例,最初设计实验的时候没有注意到该函数默认返回的是均值,以为是总和,于是最后计算完 Loss 之后,手动做了个均值,导致实际 Loss 被错误缩放,实验效果不佳,在后来 Debug 排除代码模型架构问题的时候才发觉这一点,着实花费了不少时间。

所以闲暇时准备写一下 Pytorch 中 Loss 函数相关的知识,希望能对初入深度学习的学子们有所帮助,少踩点坑。

这篇文章是用于后续理解的前置知识,在之后有提到新的专业名词时会进行补充。
文章大多以分类模型为例进行叙述。

文章目录

  • 什么是 Logits?
    • Logits 和 Softmax
  • 什么是 One-Hot 编码?
    • 类别不是整数怎么办?

什么是 Logits?

Logits 是指神经网络的最后一个线性层(全连接层)的未经过任何激活函数(例如 softmax 或 sigmoid)处理的输出,可以是任意实数,在分类的任务中,logits 通常是在进行多类别分类任务时的原始输出。

Logits 和 Softmax

在多类别分类问题中,logits 通常会被传递给 softmax 函数,softmax 函数将这些 logits 转换为概率分布:将任意实数的 logits 转换为 [0, 1] 之间的概率值,并且这些概率值的和为 1。

代码示例

为了更好地理解 logits 和 softmax 之间的关系,下面是一个简单的代码示例:

import torch
import torch.nn.functional as F# 样例:分类神经网络,便于对照理解
class Classifier(nn.Module):def __init__(self, input_size, hidden_size, num_classes=3):super(Classifier, self).__init__()self.fc1 = nn.Linear(input_size, hidden_size)  # 输入层到隐藏层self.fc2 = nn.Linear(hidden_size, num_classes)  # 隐藏层到输出层def forward(self, x):out = self.fc1(x)out = F.relu(out)  # ReLU 激活函数logits = self.fc2(out)  # 输出层,不经过 softmaxreturn logits# 假设这是分类神经网络的输出 logits
logits = torch.tensor([[2.0, 1.0, 0.1], [1.0, 3.0, 0.2]])# 使用 softmax 函数将 logits 转换为概率分布
probabilities = F.softmax(logits, dim=1)print("Logits:")
print(logits)
print("\nProbabilities after applying softmax:")
print(probabilities)
>>> Logits:
>>> tensor([[2.0000, 1.0000, 0.1000],
>>>         [1.0000, 3.0000, 0.2000]])>>> Probabilities after applying softmax:
>>> tensor([[0.6590, 0.2424, 0.0986],
>>>         [0.1131, 0.8360, 0.0508]])

输出解释

  1. Logits: [[2.0, 1.0, 0.1], [1.0, 3.0, 0.2]] 是神经网络的输出,未经过 softmax 处理。
  2. Softmax: softmax 函数将 logits 转换为概率分布,每个分布的概率值和为 1。

什么是 One-Hot 编码?

初入深度学习领域的人大多都会有这个疑问:这些所说的类别,究竟是怎么表示成向量的?

One-Hot 是一个很直观的形容,但我当时看到并猜测到相应概念的时候,还是不敢确定,因为太直白了,总觉得编码成向量的过程应该没有这么简单,然而 One-Hot 就是如此,深度学习不是一蹴而就的,看似复杂的概念最初也是由一个个直白的想法发展得来。

具体来说,One-Hot 编码对于每个类别,使用一个与类别数相同长度二进制向量,每个位置对应一个类别。其中,只有一个位置的值为 1(这就是 “One-Hot” 的含义),表示属于该类别,其余位置的值为 0。

例如,对于三个类别的分类问题(类别 A、B 和 C),使用 One-Hot 编码可得:

  • 类别 A: [1, 0, 0]
  • 类别 B: [0, 1, 0]
  • 类别 C: [0, 0, 1]

代码示例

import torch# 假设我们有三个类别:0, 1, 2
num_classes = 3# 样本标签
labels = torch.tensor([0, 2, 1, 0])# 将标签转换为 One-Hot 编码
one_hot_labels = torch.nn.functional.one_hot(labels, num_classes)print("Labels:")
print(labels)
print("\nOne-Hot Encoded Labels:")
print(one_hot_labels)
>>> Labels:
>>> tensor([0, 2, 1, 0])>>> One-Hot Encoded Labels:
>>> tensor([[1, 0, 0],
>>>         [0, 0, 1],
>>>         [0, 1, 0],
>>>         [1, 0, 0]])

输出解释

  1. Labels: [0, 2, 1, 0] 是我们初始的类别标签。
  2. One-Hot Encoded Labels: [[1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0]] 是将标签转换为 One-Hot 编码后的结果。每个向量中只有一个位置的值为 1(One-Hot)。

类别不是整数怎么办?

看了代码示例,可能会有一个疑问:类别大多不会是整数而是字符,应该怎么编码?或许你心中已经有了一个很直白的答案:那就做一个映射,将类别用整数编码,然后再将这些整数标签转换为 One-Hot 编码。

的确可以这样。

代码示例

import torch# 类别映射:A -> 0, B -> 1, C -> 2
category_map = {'A': 0, 'B': 1, 'C': 2}# 样本类别标签
labels = ['A', 'C', 'B', 'A']# 将类别标签转换为整数标签
integer_labels = torch.tensor([category_map[label] for label in labels])# 将整数标签转换为 One-Hot 编码
num_classes = len(category_map)
one_hot_labels = torch.nn.functional.one_hot(integer_labels, num_classes)print("Labels:")
print(labels)
print("\nInteger Labels:")
print(integer_labels)
print("\nOne-Hot Encoded Labels:")
print(one_hot_labels)
>>> Labels:
>>> ['A', 'C', 'B', 'A']>>> Integer Labels:
>>> tensor([0, 2, 1, 0])>>> One-Hot Encoded Labels:
>>> tensor([[1, 0, 0],
>>>         [0, 0, 1],
>>>         [0, 1, 0],
>>>         [1, 0, 0]])

解释

  1. Labels: ['A', 'C', 'B', 'A'] 是我们初始的类别标签。
  2. Integer Labels: [0, 2, 1, 0] 是将类别标签映射到整数后的结果。A 对应 0,B 对应 1,C 对应 2。
  3. One-Hot Encoded Labels: [[1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0]] 是将整数标签转换为 One-Hot 编码后的结果。每个向量中只有一个位置的值为 1,表示该样本的类别,其余位置的值为 0。

这篇关于深度学习:关于损失函数的一些前置知识(PyTorch Loss)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087670

相关文章

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]