tensoflow随笔——softmax和交叉熵

本文详细介绍了softmax函数的工作原理及其导数计算方法,并探讨了如何解决softmax函数在数值计算中的稳定性问题。此外,还深入解析了交叉熵的概念及其在评估模型输出准确性中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

softmax函数

softmax函数接收一个N维向量作为输入,然后把每一维的值转换到(0, 1)之间的一个实数。假设模型全连接网络输出为a,有C个类别,则输出为a1,a2,...,aC,对于每个样本,属于类别i的输出概率为:

属于各个类别的概率和为1。

贴一张形象的说明图:

如图将原来输入的3,1,-3通过softmax函数的作用,映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),我们可以将它理解成概率,在最后选取输出结点的时候,我们就可以选取概率值最大的结点,作为我们的预测目标。

softmax导数

对softmax求导即:

当i = j 时:

当i ≠ j时:

softmax数值稳定性

传入数据[1, 2, 3, 4, 5]时

传入数据[1000, 2000, 3000, 4000, 5000]时

导致输出是nan的原因是exp(x)对较大的数求指数溢出的问题。

一般的做法是额外加上一个非零常数,使所有的输入在0的附近。

比如:

def softmax(x):
    shift_x = x - np.max(x)
    exp_x = np.exp(shift_x)
    return exp_x / np.sum(exp_x)

 

交叉熵:用来判定实际的输出与期望的输出的接近程度!

刻画的是实际输出与期望输出的距离,也就是交叉熵的值越小,两个概率分布就越接近,假设概率分布p为期望输出,概率分布q为实际输出,H(p,q)为交叉熵,则:

或者:

 

Tensorflow中对交叉熵的计算可以采用两种方式

1.手动实现:

import tensorflow as tf

input = tf.placeholder(dtype=tf.float32, shape=[None, 28*28])
output = tf.placeholder(dtype=tf.float32, shape=[None, 10])

w_fc1 = tf.Variable(tf.truncated_normal([28*28, 1024], stddev=0.1))
b_fc1 = tf.Variable(tf.constant(0.1, shape=[1024]))
h_fc1 = tf.matmul(input, w_fc1) + b_fc1

w_fc2 = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1))
b_fc2 = tf.Variable(tf.constant(0.1, shape=[10]))
logits = tf.nn.softmax(tf.matmul(h_fc1, w_fc2) + b_fc2)

cross_entropy = -tf.reduce_sum(output * tf.log(logits))

output是one-hot类型的实际输出,logits是对全连接的输出用softmax进行转换为概率值的预测,最后通过cross_entropy = -tf.reduce_sum(label * tf.log(y))求出交叉熵的。

2.tf.nn.softmax_cross_entropy_with_logits:

tensorflow已经对softmax和交叉熵进行了封装

import tensorflow as tf

input = tf.placeholder(dtype=tf.float32, shape=[None, 28*28])
output = tf.placeholder(dtype=tf.float32, shape=[None, 10])

w_fc1 = tf.Variable(tf.truncated_normal([28*28, 1024], stddev=0.1))
b_fc1 = tf.Variable(tf.constant(0.1, shape=[1024]))
h_fc1 = tf.matmul(input, w_fc1) + b_fc1

w_fc2 = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1))
b_fc2 = tf.Variable(tf.constant(0.1, shape=[10]))
logits = tf.matmul(h_fc1, w_fc2) + b_fc2

cross_entropy = -tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=output, logits=logits))

函数的参数logits在函数内会用softmax进行处理,所以传进来时不能是softmax的输出。

官方的封装函数会在内部处理数值不稳定等问题,如果选择方法1,需要自己在softmax函数里面添加trick。

### Softmax 函数与交叉熵损失函数的求导 #### 背景介绍 Softmax 函数通常用于多分类问题中的最后一层激活函数,它能够将输入转换成概率分布形式。而交叉熵损失函数则衡量预测的概率分布与真实标签之间的差异。 #### 数学推导 对于给定的一个样本 \( \mathbf{x} \),其经过网络后的输出记作向量 \( z = (z_1, ..., z_K)^T \),其中 K 是类别数量。应用 softmax 后得到的概率分布为: \[ p_i = \frac{e^{z_i}}{\sum_{j=1}^K e^{z_j}}, i = 1,...,K \] 设真实的标签表示为独热编码的形式 \( y=(y_1,y_2,\ldots ,y_k)\in\left\{0,1\right\} ^k\) ,那么交叉熵损失可以定义如下: \[ L(\theta)= -\sum _i y_ilog(p_i)=-log(p_y), \text {where }p_y=p(y|x;\theta )=\prod_ip_i^{yi}\] 为了计算梯度下降所需的偏导数,考虑单个训练样例的情况下,针对第 k 类别的权重参数 w 的更新规则可由链式法则得出: \[ \begin{aligned} \nabla_wL &= (\partial/\partial w)L \\ &= (\partial /\partial p_k)(-\ln p_k)\cdot(\partial / \partial z_k)p_k\cdot(\partial/ \partial w)z_k\\ &=(-1/p_k)\times(e^{-z_k}/S)\times x\\ &=-(x/S)e^{-z_k}\\ &= -(x/S)p_ke^{-z_k}(1-p_k)/p_k\\ &= -xp_k(1-p_k) \end{aligned}[^1]\] 这里 S 表示分母部分即所有指数项之;\( x \)代表当前特征向量。当处理多个类时,则需累加各个类对应的贡献值来获得最终的结果。 #### 实现细节 在实际编程实现中,为了避免数值溢出或者下溢的情况发生,在计算过程中会采用一些技巧性的变换方法。比如先减去最大值再做 exp 运算,从而保证后续运算的安全性稳定性。 ```python import numpy as np def stable_softmax(z): """Compute the softmax of vector z in a numerically stable way.""" shift_z = z - np.max(z) exp_scores = np.exp(shift_z) return exp_scores / np.sum(exp_scores) def compute_loss_and_gradient(scores, labels): """ Compute cross-entropy loss and gradients. Args: scores: A matrix containing raw predictions from model. Shape should be NxD where D is num_classes. labels: True label indices for each example. Length must match N. Returns: Tuple with scalar representing average CE loss across all samples, plus gradient wrt input logits `scores`. """ n_samples = scores.shape[0] probs = stable_softmax(scores) log_likelihoods = -np.log(probs[np.arange(n_samples),labels]) avg_ce_loss = np.mean(log_likelihoods) dscores = probs.copy() dscores[np.arange(n_samples),labels] -= 1 grad_avg = dscores/n_samples return avg_ce_loss,grad_avg ``` 上述代码实现了稳定版的 softmax 计算以及相应的交叉熵损失及其反向传播所需的一阶导数矩阵。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值