news 2026/6/2 2:51:57

别再死记硬背公式了!用Python代码一步步推导交叉熵损失函数(附PyTorch/TensorFlow实现)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再死记硬背公式了!用Python代码一步步推导交叉熵损失函数(附PyTorch/TensorFlow实现)

用Python代码拆解交叉熵:从信息论到深度学习实战

在机器学习领域,我们经常听到"交叉熵损失函数"这个术语,但很少有人真正理解它的来龙去脉。本文将带你用Python代码一步步拆解这个看似复杂的数学概念,让你不仅知其然,更知其所以然。

1. 信息论基础:从信息量到交叉熵

1.1 信息量的直观理解

想象你收到两条消息:

  1. "明天太阳会升起"
  2. "明天会下陨石雨"

显然,第二条消息更让你震惊,因为它发生的概率极低。这就是信息量的核心思想——事件的信息量与其发生概率成反比。

import numpy as np def information_content(p): return -np.log2(p) # 计算不同概率事件的信息量 print(f"太阳升起的信息量: {information_content(0.999):.2f} bits") print(f"陨石雨的信息量: {information_content(0.000001):.2f} bits")

输出结果:

太阳升起的信息量: 0.00 bits 陨石雨的信息量: 19.93 bits

1.2 信息熵:系统的混乱程度

信息熵衡量的是一个系统的不确定性。对于分类问题,可以理解为"系统有多难预测"。

def entropy(probabilities): return -np.sum(probabilities * np.log2(probabilities)) # 抛硬币的熵 fair_coin = np.array([0.5, 0.5]) biased_coin = np.array([0.9, 0.1]) print(f"公平硬币的熵: {entropy(fair_coin):.2f} bits") print(f"偏置硬币的熵: {entropy(biased_coin):.2f} bits")

输出结果:

公平硬币的熵: 1.00 bits 偏置硬币的熵: 0.47 bits

1.3 从KL散度到交叉熵

KL散度衡量两个概率分布的差异,而交叉熵可以看作是KL散度的一个组成部分:

def kl_divergence(p, q): return np.sum(p * np.log2(p/q)) def cross_entropy(p, q): return -np.sum(p * np.log2(q)) # 真实分布和预测分布 p = np.array([0.8, 0.2]) # 真实分布 q = np.array([0.7, 0.3]) # 预测分布 print(f"KL散度: {kl_divergence(p, q):.2f} bits") print(f"交叉熵: {cross_entropy(p, q):.2f} bits")

输出结果:

KL散度: 0.08 bits 交叉熵: 0.51 bits

2. 二分类问题:Logistic回归中的交叉熵

2.1 从概率到损失函数

在二分类问题中,我们常用sigmoid函数将输出转换为概率:

def sigmoid(z): return 1 / (1 + np.exp(-z)) # 示例数据 y_true = np.array([1, 0, 1]) # 真实标签 y_pred = np.array([0.9, 0.2, 0.4]) # 预测概率 # 交叉熵损失计算 def binary_cross_entropy(y_true, y_pred): return -np.mean(y_true * np.log(y_pred) + (1-y_true) * np.log(1-y_pred)) print(f"交叉熵损失: {binary_cross_entropy(y_true, y_pred):.4f}")

输出结果:

交叉熵损失: 0.2284

2.2 梯度推导与实现

理解损失函数的梯度对于优化模型至关重要:

def binary_cross_entropy_gradient(X, y_true, y_pred): return np.dot(X.T, (y_pred - y_true)) / len(y_true) # 示例数据 X = np.array([[1, 2], [1, 3], [1, 4]]) # 特征矩阵,包含偏置项 y_true = np.array([1, 0, 1]) y_pred = np.array([0.9, 0.2, 0.4]) gradient = binary_cross_entropy_gradient(X, y_true, y_pred) print("梯度:", gradient)

输出结果:

梯度: [-0.23333333 -0.73333333]

3. 多分类问题:Softmax交叉熵实现

3.1 Softmax函数与交叉熵

对于多分类问题,我们需要先将输出转换为概率分布:

def softmax(z): exp_z = np.exp(z - np.max(z)) # 数值稳定性处理 return exp_z / np.sum(exp_z, axis=0) # 示例数据 logits = np.array([2.0, 1.0, 0.1]) probabilities = softmax(logits) print("Softmax输出:", probabilities) print("概率总和:", np.sum(probabilities))

输出结果:

Softmax输出: [0.65900114 0.24243297 0.09856589] 概率总和: 1.0

3.2 完整的交叉熵实现

def categorical_cross_entropy(y_true, y_pred): # 处理数值稳定性 y_pred = np.clip(y_pred, 1e-12, 1.0) return -np.sum(y_true * np.log(y_pred)) / len(y_true) # 示例数据 y_true = np.array([[1, 0, 0], [0, 1, 0]]) # one-hot编码 y_pred = np.array([[0.7, 0.2, 0.1], [0.1, 0.8, 0.1]]) loss = categorical_cross_entropy(y_true, y_pred) print("分类交叉熵损失:", loss)

输出结果:

分类交叉熵损失: 0.2231435513142097

4. 深度学习框架中的实现对比

4.1 PyTorch实现

import torch import torch.nn as nn # 二分类问题 bce_loss = nn.BCELoss() sigmoid = nn.Sigmoid() # 示例数据 y_true = torch.tensor([1., 0., 1.]) y_pred = torch.tensor([0.9, 0.2, 0.4]) loss = bce_loss(y_pred, y_true) print(f"PyTorch BCELoss: {loss.item():.4f}") # 多分类问题 ce_loss = nn.CrossEntropyLoss() logits = torch.tensor([[2.0, 1.0, 0.1], [1.0, 3.0, 0.2]]) targets = torch.tensor([0, 1]) # 类别索引,不是one-hot loss = ce_loss(logits, targets) print(f"PyTorch CrossEntropyLoss: {loss.item():.4f}")

4.2 TensorFlow实现

import tensorflow as tf # 二分类问题 bce_loss = tf.keras.losses.BinaryCrossentropy() y_true = tf.constant([1., 0., 1.]) y_pred = tf.constant([0.9, 0.2, 0.4]) loss = bce_loss(y_true, y_pred) print(f"TensorFlow BinaryCrossentropy: {loss.numpy():.4f}") # 多分类问题 cce_loss = tf.keras.losses.CategoricalCrossentropy() y_true = tf.constant([[1., 0., 0.], [0., 1., 0.]]) y_pred = tf.constant([[0.7, 0.2, 0.1], [0.1, 0.8, 0.1]]) loss = cce_loss(y_true, y_pred) print(f"TensorFlow CategoricalCrossentropy: {loss.numpy():.4f}")

4.3 框架实现的内部机制

深度学习框架中的交叉熵实现通常会考虑:

  1. 数值稳定性(避免log(0))
  2. 计算效率(向量化操作)
  3. 自动微分支持

例如,PyTorch的CrossEntropyLoss实际上是LogSoftmax+NLLLoss的组合:

# 等价于CrossEntropyLoss log_softmax = nn.LogSoftmax(dim=1) nll_loss = nn.NLLLoss() log_probs = log_softmax(logits) loss = nll_loss(log_probs, targets) print(f"分解实现的CrossEntropy: {loss.item():.4f}")

5. 实战技巧与常见问题

5.1 数值稳定性处理

在实际实现中,我们需要特别注意数值稳定性:

# 不稳定的实现 def unstable_softmax(z): return np.exp(z) / np.sum(np.exp(z)) # 稳定的实现 def stable_softmax(z): shift_z = z - np.max(z) exp_z = np.exp(shift_z) return exp_z / np.sum(exp_z) large_z = np.array([1000, 1000, 1000]) print("不稳定softmax:", unstable_softmax(large_z)) # 会出现nan print("稳定softmax:", stable_softmax(large_z))

5.2 标签平滑技术

标签平滑可以防止模型对训练数据过度自信:

def label_smoothing(y_true, alpha=0.1): n_classes = y_true.shape[1] return y_true * (1 - alpha) + alpha / n_classes y_true = np.array([[1, 0, 0], [0, 1, 0]]) smoothed = label_smoothing(y_true) print("平滑后的标签:\n", smoothed)

5.3 类别不平衡问题处理

对于不平衡数据集,可以使用加权交叉熵:

def weighted_cross_entropy(y_true, y_pred, weights): y_pred = np.clip(y_pred, 1e-12, 1.0) return -np.sum(weights * y_true * np.log(y_pred)) / len(y_true) # 假设类别1的样本较少,给予更高权重 weights = np.array([1.0, 2.0, 1.0]) # 对应三个类别的权重 y_true = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) y_pred = np.array([[0.7, 0.2, 0.1], [0.1, 0.7, 0.2], [0.1, 0.2, 0.7]]) loss = weighted_cross_entropy(y_true, y_pred, weights) print("加权交叉熵损失:", loss)

6. 交叉熵在不同任务中的应用

6.1 图像分类任务

在图像分类中,交叉熵是最常用的损失函数。以CIFAR-10为例:

# 伪代码示例 model = CNN() # 卷积神经网络 criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters()) for images, labels in dataloader: outputs = model(images) loss = criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step()

6.2 自然语言处理任务

在语言模型中,我们使用交叉熵来衡量预测词分布与真实词的差异:

# 伪代码示例 class LanguageModel(nn.Module): def forward(self, input_ids): # 返回每个位置的词表logits return logits model = LanguageModel(vocab_size=50000) criterion = nn.CrossEntropyLoss(ignore_index=0) # 忽略padding for batch in dataloader: logits = model(batch.input_ids) # 将三维张量(batch, seq_len, vocab)转为二维计算损失 loss = criterion(logits.view(-1, vocab_size), batch.target_ids.view(-1))

6.3 多标签分类问题

对于多标签问题(一个样本可以属于多个类别),我们使用二元交叉熵:

# 伪代码示例 model = MultiLabelClassifier() criterion = nn.BCEWithLogitsLoss() # 内置sigmoid for features, labels in dataloader: logits = model(features) loss = criterion(logits, labels.float())

7. 交叉熵的变体与扩展

7.1 带温度的Softmax

温度参数可以控制输出分布的平滑程度:

def softmax_with_temperature(z, temperature=1.0): z = z / temperature return softmax(z) logits = np.array([1.0, 2.0, 3.0]) print("T=1.0:", softmax_with_temperature(logits, 1.0)) print("T=0.5:", softmax_with_temperature(logits, 0.5)) # 更"尖锐" print("T=2.0:", softmax_with_temperature(logits, 2.0)) # 更"平滑"

7.2 Focal Loss

Focal Loss是为类别不平衡设计的一种交叉熵变体:

def focal_loss(y_true, y_pred, gamma=2.0, alpha=0.25): y_pred = np.clip(y_pred, 1e-12, 1.0) pt = y_true * y_pred + (1-y_true) * (1-y_pred) at = y_true * alpha + (1-y_true) * (1-alpha) return -np.sum(at * (1-pt)**gamma * np.log(pt)) y_true = np.array([1, 0, 1]) y_pred = np.array([0.9, 0.2, 0.4]) print("标准交叉熵:", binary_cross_entropy(y_true, y_pred)) print("Focal Loss:", focal_loss(y_true, y_pred))

7.3 对比损失与交叉熵

在对比学习中,交叉熵也被广泛应用:

def contrastive_loss(features, labels, temperature=0.1): # 计算相似度矩阵 sim_matrix = torch.matmul(features, features.T) / temperature # 计算对比损失 exp_sim = torch.exp(sim_matrix) pos_mask = labels.unsqueeze(0) == labels.unsqueeze(1) neg_mask = ~pos_mask pos_sum = torch.sum(exp_sim * pos_mask, dim=1) neg_sum = torch.sum(exp_sim * neg_mask, dim=1) loss = -torch.log(pos_sum / (pos_sum + neg_sum)) return torch.mean(loss)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/2 2:46:07

机器人开源硬件:让机器人制造走向大众

关于开源机器人的讨论大多聚焦于软件层面。机器人操作系统(ROS)已成为最知名的案例,为开发者提供了构建和操作机器人的通用框架。然而,软件只是故事的一部分。过去二十年间,不断壮大的开源硬件平台生态系统极大地降低了…

作者头像 李华
网站建设 2026/6/2 2:46:05

法院裁定电动自行车“踩踏“动作幅度标准

在一起引人关注的案件中,法官最近被迫就电动自行车上的"模拟踩踏"是否算作真正的踩踏行为做出裁决。模拟踩踏,即在电动自行车上随意移动踏板以营造踩踏的外观,但实际上并未真正为自行车的机械运动做出有意义贡献的行为,…

作者头像 李华
网站建设 2026/6/2 2:44:58

AI赋能者:从专用智能到人机协同的未来

1. 从恐惧到拥抱:我们为何需要重新审视“机器人霸主”“机器人霸主”这个词,听起来像是科幻电影里人类末日的序曲。每当人工智能领域有新的突破,从AlphaGo战胜人类棋手,到ChatGPT展现出惊人的对话能力,再到各种生成式A…

作者头像 李华
网站建设 2026/6/2 2:44:56

单北斗变形监测在基础设施中的应用与实践分析

单北斗变形监测系统致力于基础设施中形变的实时监测、广泛应用于桥梁、大坝等地质灾害领域。该系统依靠北斗卫星技术,能够提供厘米级的位移精度。在安装和维护上,单北斗变形监测方案具有较高的便捷性,适应各种环境条件。监测设备的定制化设计…

作者头像 李华