Questo articolo fa parte di una raccolta che esamina in modo approfondito il funzionamento interno di Vision Transformers. Ciascuno di questi articoli è disponibile anche come Jupyter Notebook con codice eseguibile. Gli altri articoli della serie sono:
Sommario
L’attenzione è tutto ciò di cui hai bisogno¹ afferma che i trasformatori, a causa della loro mancanza di ricorrenza o convoluzione, non sono in grado di apprendere informazioni sull’ordine di un insieme di token. Senza incorporamento di posizione, i trasformatori sono invarianti rispetto all’ordine dei token. Per le immagini, ciò significa che le parti di un’immagine possono essere codificate senza influire sull’output previsto.
Diamo un’occhiata a un esempio di ordine delle patch su questa pixel art Montagna al tramonto di Luis Zuno (@ansimuz)³. L’opera d’arte originale è stata ritagliata e convertita in un’immagine a canale singolo. Ciò significa che ogni pixel ha un valore compreso tra zero e uno. Le immagini a canale singolo vengono generalmente visualizzate in scala di grigi; tuttavia, lo visualizzeremo con una combinazione di colori viola perché è più facile da vedere.
mountains = np.load(os.path.join(figure_path, 'mountains.npy'))H = mountains.shape(0)
W = mountains.shape(1)
print('Mountain at Dusk is H =', H, 'and W =', W, 'pixels.')
print('\n')
fig = plt.figure(figsize=(10,6))
plt.imshow(mountains, cmap='Purples_r')
plt.xticks(np.arange(-0.5, W+1, 10), labels=np.arange(0, W+1, 10))
plt.yticks(np.arange(-0.5, H+1, 10), labels=np.arange(0, H+1, 10))
plt.clim((0,1))
cbar_ax = fig.add_axes((0.95, .11, 0.05, 0.77))
plt.clim((0, 1))
plt.colorbar(cax=cbar_ax);
#plt.savefig(os.path.join(figure_path, 'mountains.png'), bbox_inches='tight')
Mountain at Dusk is H = 60 and W = 100 pixels.
Possiamo dividere questa immagine in porzioni di dimensione 20. (Per una spiegazione più approfondita sulla suddivisione delle immagini in porzioni, vedere la Articolo sui trasformatori di visione.)
P = 20
N = int((H*W)/(P**2))
print('There will be', N, 'patches, each', P, 'by', str(P)+'.')
print('\n')fig = plt.figure(figsize=(10,6))
plt.imshow(mountains, cmap='Purples_r')
plt.clim((0,1))
plt.hlines(np.arange(P, H, P)-0.5, -0.5, W-0.5, color='w')
plt.vlines(np.arange(P, W, P)-0.5, -0.5, H-0.5, color='w')
plt.xticks(np.arange(-0.5, W+1, 10), labels=np.arange(0, W+1, 10))
plt.yticks(np.arange(-0.5, H+1, 10), labels=np.arange(0, H+1, 10))
x_text = np.tile(np.arange(9.5, W, P), 3)
y_text = np.repeat(np.arange(9.5, H, P), 5)
for i in range(1, N+1):
plt.text(x_text(i-1), y_text(i-1), str(i), color='w', fontsize='xx-large', ha='center')
plt.text(x_text(2), y_text(2), str(3), color='k', fontsize='xx-large', ha='center');
#plt.savefig(os.path.join(figure_path, 'mountain_patches.png'), bbox_inches='tight')
There will be 15 patches, each 20 by 20.
L’affermazione è che i trasformatori di visione non sarebbero in grado di distinguere l’immagine originale da una versione in cui le patch erano state codificate.
np.random.seed(21)
scramble_order = np.random.permutation(N)
left_x = np.tile(np.arange(0, W-P+1, 20), 3)
right_x = np.tile(np.arange(P, W+1, 20), 3)
top_y = np.repeat(np.arange(0, H-P+1, 20), 5)
bottom_y = np.repeat(np.arange(P, H+1, 20), 5)
scramble = np.zeros_like(mountains)
for i in range(N):
t = scramble_order(i)
scramble(top_y(i):bottom_y(i), left_x(i):right_x(i)) = mountains(top_y
Fonte: towardsdatascience.com