Введение
Если вы хотите получить больше информации о своей нейронной сети изображений, как и я, вот 2 хороших способа сделать это. Оба метода подходят к этой проблеме с идеей значимости изображения.
заметность
Оксфордское определение:Выдающееся положение, способность быть особенно заметным или важным.
В нашем случае наша цель состоит в том, чтобы оценить значимость каждого значения пикселя в изображении.
Заметность через окклюзию
Впервые представленный в Zeiler and Fergus, «Visualizing and Understanding Convolutional Networks», ECCV 2014, этот метод привел к идее перекрытия части изображения, чтобы определить, насколько «важным» был этот сегмент для предсказания наша модель.
Мы можем использовать Numpy с таким подходом:
- Добавление карты окклюзии в исходное изображение.
- Расчет количества ошибок, которые добавляются в прогноз.
- Приписывание ошибки закрытым пикселям.
def generateOcclusion(new_img, attrib): """ Adds a gray occlusion patch to an image, given the size and coordinates of the occlusion. Args: new_img: Numpy array of size (NxNx3) attrib: tuple, with (size_of_patch, x coordinate, y coordinate) Returns tuple, with occluded image, and a map of occluded pixels """ n = attrib[0] y = attrib[1] x = attrib[2] img_count = np.zeros((224,224)) # Generate an array of zeros in the size of image img_count[y:y+n,x:x+n] = 1 # Save which pixels were occluded new_img[:, y:y+n,x:x+n, :] = 0.5 # Generate the occlusion in gray return new_img, img_count def schedule(size): """ Args: size (int): Length of original image. Returns List of (size, pos_y, pos_x) """ occ_size = 6 # Occlusion size wrate = 10 diminishing_N = [] for i in range(1): n = occ_size - i*wrate if n > 0: diminishing_N.append(n) schedule = [] for N in diminishing_N: steps = size // N for step_y in range(steps): for step_x in range(steps): schedule.append((N, 0 + step_y*N, 0 + step_x*N)) return schedule def updateSaliency(saliency_err, img_ones, err, output_size): """ Args: saliency_err: array with the previous errors with shape (NxN) img_ones: array with occluded pixels err: Amount of error with occlusion output_size: N. Returns: updated saliency_err """ occluded = np.array([img_ones]*output_size) error = err.reshape(output_size,1,1) new_error = occluded * error saliency_err +=new_error return saliency_err def saliencyViaOcclusion(og_img, model): output_size = model.output.shape[1] og_img = np.array([og_img]) y_hat = model.predict(og_img) # (224, 224, 3) saliency_err = np.zeros((output_size, 224,224)) saliency_cnt = np.zeros((output_size, 224,224)) list_occ_img = [] for attrib in schedule(224): new_img = og_img.copy() occ_img, img_count = generateOcclusion(new_img, attrib) y2_hat = model.predict(occ_img) err = np.absolute(y_hat - y2_hat) saliency_cnt += np.array([img_count]*output_size) saliency_err = updateSaliency(saliency_err, img_count, err, output_size) saliency_map = saliency_err / saliency_cnt # calculate average if maps overlap return saliency_map
Заметность через обратное распространение
Впервые представленный в работе Simonyan, Vedaldi, and Zisserman, «Deep Inside Convolutional Networks: Visualizing Image Classification Models and Saliency Maps», ICLR Workshop 2014, этот подход представил метод, который будет генерировать карту изображения, которая максимизирует выходной балл.
Мы можем использовать Tensorflow GradientTape():
- Получение функции потерь модели и подготовка наших данных.
- Прогнозирование с помощью модели и расчет потерь, а также использование автоматического дифференцирования.
- Вычислите градиент потерь по отношению к исходному изображению.
from keras import backend as k def saliencyViaBackprop(model, loss, y_true, img_example): loss_fn = tf.keras.losses.get(loss) img_example = np.array([img_example]) # keep track of our gradients x_tensor = tf.convert_to_tensor(img_example, dtype=tf.float32) with tf.GradientTape() as tape: tape.watch(x_tensor) # make a prediction using the model and then calculate the # loss pred = model(x_tensor) loss = loss_fn(y_true, pred) # calculate the gradients using our tape and then update the # model weights evaluated_gradients = tape.gradient(loss, x_tensor) res = tf.abs(evaluated_gradients) return evaluated_gradients
В заключение
С помощью этих двух методов вы будете готовы пролить свет на свою модель и сможете интерпретировать ее действия немного за пределами обычных метрик.
Кроме того, если вы не используете Tensorflow, я показал вам способ получить результаты только с помощью numpy. Заметность с помощью обратного распространения также можно выполнить с помощью других фреймворков, таких как PyTorch с autograd(), просто выполнив те же действия.