Можно ли использовать векторные методы для смещения изображений, хранящихся в массиве numpy, для увеличения данных? - PullRequest
1 голос
/ 12 апреля 2020

Предыстория: Это одна из задач упражнения из учебника Аурелиена Герона «Практические занятия по машинному обучению».

Вопрос в том, чтобы написать функцию, которая может сдвигать изображение MNIST в любом направлении (влево, вправо, вверх, вниз) на один пиксель. Затем для каждого изображения в тренировочном наборе создайте четыре сдвинутые копии (по одной на каждое направление) и добавьте их в тренировочный набор.

Мой мыслительный процесс:

  1. У меня есть numpy массив размера (59500, 784) в X_train (каждая строка представляет собой (28,28) изображение). Для каждой строки X_train:
    1. Изменить форму строки до 28,28
    2. Для каждого направления (вверх, вниз, влево, вправо):
      1. Изменить форму до 784,0
      2. Запись в пустой массив
  2. Добавить новый массив в X_train

Мой код:

import numpy as np
from scipy.ndimage.interpolation import shift

def shift_and_append(X, n):
    x_arr = np.zeros((1, 784))
    for i in range(n):
        for j in range(-1,2):
            for k in range(-1,2):
                if j!=k and j!=-k:
                    x_arr = np.append(x_arr, shift(X[i,:].reshape(28,28), [j, k]).reshape(1, 784), axis=0)
    return np.append(X, x_arr[1:,:], axis=0)

X_train_new = shift_and_append(X_train, X_train.shape[0])
y_train_new = np.append(y_train, np.repeat(y_train, 4), axis=0)

Требуется много времени, чтобы бежать. Я чувствую, что это грубое принуждение. Существует ли эффективный векторный метод для достижения этой цели?

1 Ответ

2 голосов
/ 12 апреля 2020

3 вложенных циклов for с условием if при изменении формы и добавлении явно не очень хорошая идея; numpy.roll прекрасно выполняет работу векторным способом:

import numpy as np
import matplotlib.pyplot as plt 
from keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train.shape
# (60000, 28, 28)

# plot an original image
plt.gray() 
plt.matshow(x_train[0]) 
plt.show() 

enter image description here

Давайте сначала продемонстрируем операции:

# one pixel down:
x_down = np.roll(x_train[0], 1, axis=0)
plt.gray() 
plt.matshow(x_down) 
plt.show() 

enter image description here

# one pixel up:
x_up = np.roll(x_train[0], -1, axis=0)
plt.gray() 
plt.matshow(x_up) 
plt.show() 

enter image description here

# one pixel left:
x_left = np.roll(x_train[0], -1, axis=1)
plt.gray() 
plt.matshow(x_left) 
plt.show() 

enter image description here

# one pixel right:
x_right = np.roll(x_train[0], 1, axis=1)
plt.gray() 
plt.matshow(x_right) 
plt.show() 

enter image description here

Установив это, мы можем генерировать, скажем, "правильные" версии всех тренировочных образов просто путем

x_all_right = [np.roll(x, 1, axis=1) for x in x_train]

и аналогично для других 3 направлений.

Давайте подтвердим, что первое изображение в x_all_right действительно то, что мы хотим:

plt.gray() 
plt.matshow(x_all_right[0]) 
plt.show()

enter image description here

Вы даже можете избежать последнего понимания списка в пользу чистого Numpy кода, как

x_all_right = np.roll(x_train, 1, axis=2)

, который более эффективен, хотя и немного менее интуитивен (просто возьмите соответствующие версии команд с одним изображением и увеличьте axis на 1).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...