123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- from .imports import *
- from .torch_imports import *
- from sklearn.metrics import confusion_matrix
- def ceildiv(a, b):
- return -(-a // b)
- def plots(ims, figsize=(12,6), rows=1, interp=False, titles=None, maintitle=None):
- if type(ims[0]) is np.ndarray:
- ims = np.array(ims)
- if (ims.shape[-1] != 3): ims = ims.transpose((0,2,3,1))
- f = plt.figure(figsize=figsize)
- if maintitle is not None:
- plt.suptitle(maintitle, fontsize=16)
- for i in range(len(ims)):
- sp = f.add_subplot(rows, ceildiv(len(ims), rows), i+1)
- sp.axis('Off')
- if titles is not None: sp.set_title(titles[i], fontsize=16)
- plt.imshow(ims[i], interpolation=None if interp else 'none')
- def plots_from_files(imspaths, figsize=(10,5), rows=1, titles=None, maintitle=None):
- """Plots images given image files.
- Arguments:
- im_paths (list): list of paths
- figsize (tuple): figure size
- rows (int): number of rows
- titles (list): list of titles
- maintitle (string): main title
- """
- f = plt.figure(figsize=figsize)
- if maintitle is not None: plt.suptitle(maintitle, fontsize=16)
- for i in range(len(imspaths)):
- sp = f.add_subplot(rows, ceildiv(len(imspaths), rows), i+1)
- sp.axis('Off')
- if titles is not None: sp.set_title(titles[i], fontsize=16)
- img = plt.imread(imspaths[i])
- plt.imshow(img)
- def plot_confusion_matrix(cm, classes, normalize=False, title='Confusion matrix', cmap=plt.cm.Blues, figsize=None):
- """
- This function prints and plots the confusion matrix.
- Normalization can be applied by setting `normalize=True`.
- (This function is copied from the scikit docs.)
- """
- plt.figure(figsize=figsize)
- plt.imshow(cm, interpolation='nearest', cmap=cmap)
- plt.title(title)
- plt.colorbar()
- tick_marks = np.arange(len(classes))
- plt.xticks(tick_marks, classes, rotation=45)
- plt.yticks(tick_marks, classes)
- if normalize: cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
- print(cm)
- thresh = cm.max() / 2.
- for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
- plt.text(j, i, cm[i, j], horizontalalignment="center", color="white" if cm[i, j] > thresh else "black")
- plt.tight_layout()
- plt.ylabel('True label')
- plt.xlabel('Predicted label')
- def plots_raw(ims, figsize=(12,6), rows=1, titles=None):
- f = plt.figure(figsize=figsize)
- for i in range(len(ims)):
- sp = f.add_subplot(rows, ceildiv(len(ims), rows), i+1)
- sp.axis('Off')
- if titles is not None: sp.set_title(titles[i], fontsize=16)
- plt.imshow(ims[i])
- def load_img_id(ds, idx, path): return np.array(PIL.Image.open(os.path.join(path, ds.fnames[idx])))
- class ImageModelResults():
- """ Visualize the results of an image model
- Arguments:
- ds (dataset): a dataset which contains the images
- log_preds (numpy.ndarray): predictions for the dataset in log scale
- Returns:
- ImageModelResults
- """
- def __init__(self, ds, log_preds):
- """Initialize an ImageModelResults class instance"""
- self.ds = ds
- # returns the indices of the maximum value of predictions along axis 1, representing the predicted class
- # log_preds.shape = (number_of_samples, number_of_classes);
- # preds.shape = (number_of_samples,)
- self.preds = np.argmax(log_preds, axis=1)
- # computes the probabilities
- self.probs = np.exp(log_preds)
- # extracts the number of classes
- self.num_classes = log_preds.shape[1]
- def plot_val_with_title(self, idxs, y):
- """ Displays the images and their probabilities of belonging to a certain class
- Arguments:
- idxs (numpy.ndarray): indexes of the image samples from the dataset
- y (int): the selected class
- Returns:
- Plots the images in n rows [rows = n]
- """
- # if there are any samples to be displayed
- if len(idxs) > 0:
- imgs = np.stack([self.ds[x][0] for x in idxs])
- title_probs = [self.probs[x,y] for x in idxs]
- return plots(self.ds.denorm(imgs), rows=1, titles=title_probs)
- # if idxs is empty return false
- else:
- return False;
- def most_by_mask(self, mask, y, mult):
- """ Extracts the first 4 most correct/incorrect indexes from the ordered list of probabilities
- Arguments:
- mask (numpy.ndarray): the mask of probabilities specific to the selected class; a boolean array with shape (num_of_samples,) which contains True where class==selected_class, and False everywhere else
- y (int): the selected class
- mult (int): sets the ordering; -1 descending, 1 ascending
- Returns:
- idxs (ndarray): An array of indexes of length 4
- """
- idxs = np.where(mask)[0]
- cnt = min(4, len(idxs))
- return idxs[np.argsort(mult * self.probs[idxs,y])[:cnt]]
- def most_uncertain_by_mask(self, mask, y):
- """ Extracts the first 4 most uncertain indexes from the ordered list of probabilities
- Arguments:
- mask (numpy.ndarray): the mask of probabilities specific to the selected class; a boolean array with shape (num_of_samples,) which contains True where class==selected_class, and False everywhere else
- y (int): the selected class
- Returns:
- idxs (ndarray): An array of indexes of length 4
- """
- idxs = np.where(mask)[0]
- # the most uncertain samples will have abs(probs-1/num_classes) close to 0;
- return idxs[np.argsort(np.abs(self.probs[idxs,y]-(1/self.num_classes)))[:4]]
- def most_by_correct(self, y, is_correct):
- """ Extracts the predicted classes which correspond to the selected class (y) and to the specific case (prediction is correct - is_true=True, prediction is wrong - is_true=False)
- Arguments:
- y (int): the selected class
- is_correct (boolean): a boolean flag (True, False) which specify the what to look for. Ex: True - most correct samples, False - most incorrect samples
- Returns:
- idxs (numpy.ndarray): An array of indexes (numpy.ndarray)
- """
- # mult=-1 when the is_correct flag is true -> when we want to display the most correct classes we will make a descending sorting (argsort) because we want that the biggest probabilities to be displayed first.
- # When is_correct is false, we want to display the most incorrect classes, so we want an ascending sorting since our interest is in the smallest probabilities.
- mult = -1 if is_correct==True else 1
- return self.most_by_mask(((self.preds == self.ds.y)==is_correct)
- & (self.ds.y == y), y, mult)
- def plot_by_correct(self, y, is_correct):
- """ Plots the images which correspond to the selected class (y) and to the specific case (prediction is correct - is_true=True, prediction is wrong - is_true=False)
- Arguments:
- y (int): the selected class
- is_correct (boolean): a boolean flag (True, False) which specify the what to look for. Ex: True - most correct samples, False - most incorrect samples
- """
- return self.plot_val_with_title(self.most_by_correct(y, is_correct), y)
- def most_by_uncertain(self, y):
- """ Extracts the predicted classes which correspond to the selected class (y) and have probabilities nearest to 1/number_of_classes (eg. 0.5 for 2 classes, 0.33 for 3 classes) for the selected class.
- Arguments:
- y (int): the selected class
- Returns:
- idxs (numpy.ndarray): An array of indexes (numpy.ndarray)
- """
- return self.most_uncertain_by_mask((self.ds.y == y), y)
- def plot_most_correct(self, y):
- """ Plots the images which correspond to the selected class (y) and are most correct.
- Arguments:
- y (int): the selected class
- """
- return self.plot_by_correct(y, True)
- def plot_most_incorrect(self, y):
- """ Plots the images which correspond to the selected class (y) and are most incorrect.
- Arguments:
- y (int): the selected class
- """
- return self.plot_by_correct(y, False)
- def plot_most_uncertain(self, y):
- """ Plots the images which correspond to the selected class (y) and are most uncertain i.e have probabilities nearest to 1/number_of_classes.
- Arguments:
- y (int): the selected class
- """
- return self.plot_val_with_title(self.most_by_uncertain(y), y)
|