1. softmax函数代码
import numpy as np def softmax(a): a -= np.max(a) exp_a = np.exp(a) return exp_a / np.sum(exp_a)
2. 不能正确处理批量样本
我们对比一下处理单个样本和批量样本的情况:
a = np.array([1, 2, 3]) b = np.array([ [1, 2, 3], [1, 2, 3]]) softmax(a), softmax(b)
输出:
(array([0.09003057, 0.24472847, 0.66524096]), array([[0.04501529, 0.12236424, 0.33262048], [0.04501529, 0.12236424, 0.33262048]]))
容易发现,对应的值,后者的结果都是前者的一半。问题就在np.sum(exp_a)这里:
在批量数据(矩阵)情况下,我们本意是每个样本求得一个和值,即按行求和。它却将所有数据相加而仅得到一个和值。
再验证一下:
a = np.array([1, 2, 3]) b = np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]]) softmax(a), softmax(b)
输出:
(array([0.09003057, 0.24472847, 0.66524096]), array([[0.03001019, 0.08157616, 0.22174699], [0.03001019, 0.08157616, 0.22174699], [0.03001019, 0.08157616, 0.22174699]]))
可以看到,样本数增加为 3 个时,后者的输出也相应地变成了前者的三分之一。此时前者输出的 3 个数和为 1 ,而后者是输出的 9 个数和为 1。
现在单样本和批量的输出之间还具有倍数关系,如果每个样本是数据不同,那么将会更加乱套:
a = np.array([1, 2, 3]) b = np.array([[1, 2, 3], [4, 5, 6]]) softmax(a), softmax(b)
输出:
(array([0.09003057, 0.24472847, 0.66524096]), array([[0.00426978, 0.01160646, 0.03154963], [0.08576079, 0.23312201, 0.63369132]]))
3. 解决方案
分情况处理即可:
def softmax(x): if x.ndim == 2: x = x.T x = x - np.max(x, axis=0) y = np.exp(x) / np.sum(np.exp(x), axis=0) return y.T x = x - np.max(x) return np.exp(x) / np.sum(np.exp(x))
注:此代码来自前言提到的书本
我们之前分析了,其实就是求和函数的问题,因此我尝试着能不能写得更加简洁和统一些。
但是我没有成功,因为会遇到一些细节处理上的问题,例如批量情况下:最大值 max 也应当是按行求得;np.sum得到的是一维数组,为了最后相除时能够进行广播,进行转置是有必要的。
不过修改代码的尝试倒是加深了我对它的理解。
感谢阅读
文章知识点与官方知识档案匹配,可进一步学习相关知识
Python入门技能树人工智能基于Python的监督学习146892 人正在系统学习中