Spaces:
Running
Running
import numpy as np | |
from scipy.special import softmax | |
class CELoss(object): | |
def compute_bin_boundaries(self, probabilities = np.array([])): | |
#uniform bin spacing | |
if probabilities.size == 0: | |
bin_boundaries = np.linspace(0, 1, self.n_bins + 1) | |
self.bin_lowers = bin_boundaries[:-1] | |
self.bin_uppers = bin_boundaries[1:] | |
else: | |
#size of bins | |
bin_n = int(self.n_data/self.n_bins) | |
bin_boundaries = np.array([]) | |
probabilities_sort = np.sort(probabilities) | |
for i in range(0,self.n_bins): | |
bin_boundaries = np.append(bin_boundaries,probabilities_sort[i*bin_n]) | |
bin_boundaries = np.append(bin_boundaries,1.0) | |
self.bin_lowers = bin_boundaries[:-1] | |
self.bin_uppers = bin_boundaries[1:] | |
def get_probabilities(self, output, labels, logits): | |
#If not probabilities apply softmax! | |
if logits: | |
self.probabilities = softmax(output, axis=1) | |
else: | |
self.probabilities = output | |
self.labels = labels | |
self.confidences = np.max(self.probabilities, axis=1) | |
self.predictions = np.argmax(self.probabilities, axis=1) | |
self.accuracies = np.equal(self.predictions,labels) | |
def binary_matrices(self): | |
idx = np.arange(self.n_data) | |
#make matrices of zeros | |
pred_matrix = np.zeros([self.n_data,self.n_class]) | |
label_matrix = np.zeros([self.n_data,self.n_class]) | |
#self.acc_matrix = np.zeros([self.n_data,self.n_class]) | |
pred_matrix[idx,self.predictions] = 1 | |
label_matrix[idx,self.labels] = 1 | |
self.acc_matrix = np.equal(pred_matrix, label_matrix) | |
def compute_bins(self, index = None): | |
self.bin_prop = np.zeros(self.n_bins) | |
self.bin_acc = np.zeros(self.n_bins) | |
self.bin_conf = np.zeros(self.n_bins) | |
self.bin_score = np.zeros(self.n_bins) | |
if index == None: | |
confidences = self.confidences | |
accuracies = self.accuracies | |
else: | |
confidences = self.probabilities[:,index] | |
accuracies = self.acc_matrix[:,index] | |
for i, (bin_lower, bin_upper) in enumerate(zip(self.bin_lowers, self.bin_uppers)): | |
# Calculated |confidence - accuracy| in each bin | |
in_bin = np.greater(confidences,bin_lower.item()) * np.less_equal(confidences,bin_upper.item()) | |
self.bin_prop[i] = np.mean(in_bin) | |
if self.bin_prop[i].item() > 0: | |
self.bin_acc[i] = np.mean(accuracies[in_bin]) | |
self.bin_conf[i] = np.mean(confidences[in_bin]) | |
self.bin_score[i] = np.abs(self.bin_conf[i] - self.bin_acc[i]) | |
class MaxProbCELoss(CELoss): | |
def loss(self, output, labels, n_bins = 15, logits = True): | |
self.n_bins = n_bins | |
super().compute_bin_boundaries() | |
super().get_probabilities(output, labels, logits) | |
super().compute_bins() | |
#http://people.cs.pitt.edu/~milos/research/AAAI_Calibration.pdf | |
class ECELoss(MaxProbCELoss): | |
def loss(self, output, labels, n_bins = 15, logits = True): | |
super().loss(output, labels, n_bins, logits) | |
return np.dot(self.bin_prop,self.bin_score) | |
class MCELoss(MaxProbCELoss): | |
def loss(self, output, labels, n_bins = 15, logits = True): | |
super().loss(output, labels, n_bins, logits) | |
return np.max(self.bin_score) | |
#https://arxiv.org/abs/1905.11001 | |
#Overconfidence Loss (Good in high risk applications where confident but wrong predictions can be especially harmful) | |
class OELoss(MaxProbCELoss): | |
def loss(self, output, labels, n_bins = 15, logits = True): | |
super().loss(output, labels, n_bins, logits) | |
return np.dot(self.bin_prop,self.bin_conf * np.maximum(self.bin_conf-self.bin_acc,np.zeros(self.n_bins))) | |
#https://arxiv.org/abs/1904.01685 | |
class SCELoss(CELoss): | |
def loss(self, output, labels, n_bins = 15, logits = True): | |
sce = 0.0 | |
self.n_bins = n_bins | |
self.n_data = len(output) | |
self.n_class = len(output[0]) | |
super().compute_bin_boundaries() | |
super().get_probabilities(output, labels, logits) | |
super().binary_matrices() | |
for i in range(self.n_class): | |
super().compute_bins(i) | |
sce += np.dot(self.bin_prop,self.bin_score) | |
return sce/self.n_class | |
class TACELoss(CELoss): | |
def loss(self, output, labels, threshold = 0.01, n_bins = 15, logits = True): | |
tace = 0.0 | |
self.n_bins = n_bins | |
self.n_data = len(output) | |
self.n_class = len(output[0]) | |
super().get_probabilities(output, labels, logits) | |
self.probabilities[self.probabilities < threshold] = 0 | |
super().binary_matrices() | |
for i in range(self.n_class): | |
super().compute_bin_boundaries(self.probabilities[:,i]) | |
super().compute_bins(i) | |
tace += np.dot(self.bin_prop,self.bin_score) | |
return tace/self.n_class | |
#create TACELoss with threshold fixed at 0 | |
class ACELoss(TACELoss): | |
def loss(self, output, labels, n_bins = 15, logits = True): | |
return super().loss(output, labels, 0.0 , n_bins, logits) | |