Как визуализировать внимание LSTM с помощью пакета keras-self-Внимание? - PullRequest
5 голосов
/ 12 октября 2019

Я использую (keras-self-Внимание) для реализации LSTM внимания в KERAS. Как я могу визуализировать часть внимания после тренировки модели? Это случай прогнозирования временного ряда.

from keras.models import Sequential
from keras_self_attention import SeqWeightedAttention
from keras.layers import LSTM, Dense, Flatten

model = Sequential()
model.add(LSTM(activation = 'tanh' ,units = 200, return_sequences = True, 
               input_shape = (TrainD[0].shape[1], TrainD[0].shape[2])))
model.add(SeqSelfAttention())
model.add(Flatten())    
model.add(Dense(1, activation = 'relu'))

model.compile(optimizer = 'adam', loss = 'mse')

1 Ответ

4 голосов
/ 12 октября 2019

Один из подходов заключается в извлечении выходных данных SeqSelfAttention для заданного входа и их организации так, чтобы отображать прогнозы на канал (см. Ниже). Для более продвинутых взгляните на библиотеку iNNvestigate (примеры использования включены).


Объяснение : show_features_1D fetches layer_name (можнобыть подстрокой) выводит уровень и показывает прогнозы для каждого канала (помеченные) с временными шагами по оси x и значениями по оси y.
  • input_data = один пакет данных формы (1, input_shape)
  • prefetched_outputs = выходы уже полученного слоя;переопределения input_data
  • max_timesteps = максимальное количество отображаемых временных шагов
  • max_col_subplots = максимальное количество вспомогательных участков по горизонтали
  • equate_axes = принудительное выполнение всех x-и оси Y должны быть равны (рекомендуется для достоверного сравнения)
  • show_y_zero = показывать ли y = 0 в виде красной линии
  • channel_axis = размерность элементов слоя (например, * 1039)* для LSTM, который является последним)
  • scale_width, scale_height = масштабировать ширину и высоту отображаемого изображения
  • dpi = качество изображения (точек на дюйм)

Объяснение (см. Ниже) :

  • Сначала полезно просмотреть фигур выделенных объектов, независимо от величины, - дать информацию, например, о частота содержание
  • Секунда полезно для просмотра взаимосвязей элементов - например, относительных величин, смещений и частот. Приведенный ниже результат резко контрастирует с изображением над ним, так как выполнение print(outs_1) показывает, что все величины очень малы и мало меняются, поэтому включение точки y = 0 и уравнивающих осей приводит к линейному визуальному эффекту, который можетбыть интерпретированным как само-внимание, ориентированное на предвзятость.
  • Третий полезен для визуализации функций, которых слишком много, чтобы их можно было визуализировать, как указано выше;определение модели с batch_shape вместо input_shape удаляет все ? в печатных формах, и мы можем видеть, что форма первого вывода (10, 60, 240), форма второго (10, 240, 240). Другими словами, первый выход возвращает внимание канала LSTM, а второй - «внимание временных шагов». Результат тепловой карты, приведенный ниже, можно интерпретировать как показ «внимания к охлаждению» по временным шагам.

SeqWeightedAttention намного проще визуализировать, но не так уж многовизуализации;вам нужно избавиться от Flatten выше, чтобы оно заработало. Формы вывода внимания становятся (10, 60) и (10, 240) - для которых вы можете использовать простую гистограмму plt.hist (просто убедитесь, что вы исключаете размер партии - т.е. подача (60,) или (240,)).


from keras.layers import Input, Dense, LSTM, Flatten, concatenate
from keras.models import Model
from keras.optimizers import Adam
from keras_self_attention = SeqSelfAttention
import numpy as np 

ipt   = Input(shape=(240,4))
x     = LSTM(60, activation='tanh', return_sequences=True)(ipt)
x     = SeqSelfAttention(return_attention=True)(x)
x     = concatenate(x)
x     = Flatten()(x)
out   = Dense(1, activation='sigmoid')(x)
model = Model(ipt,out)
model.compile(Adam(lr=1e-2), loss='binary_crossentropy')

X = np.random.rand(10,240,4) # dummy data
Y = np.random.randint(0,2,(10,1)) # dummy labels
model.train_on_batch(X, Y)

outs = get_layer_outputs(model, 'seq', X[0:1], 1)
outs_1 = outs[0]
outs_2 = outs[1]

show_features_1D(model,'lstm',X[0:1],max_timesteps=100,equate_axes=False,show_y_zero=False)
show_features_1D(model,'lstm',X[0:1],max_timesteps=100,equate_axes=True, show_y_zero=True)
show_features_2D(outs_2[0])  # [0] for 2D since 'outs_2' is 3D

image image image


def show_features_1D(model, layer_name, input_data, prefetched_outputs=None,
                     max_timesteps=100, max_col_subplots=10, equate_axes=False,
                     show_y_zero=True, channel_axis=-1,
                     scale_width=1, scale_height=1, dpi=76):
    if prefetched_outputs is None:
        layer_outputs = get_layer_outputs(model, layer_name, input_data, 1)[0]
    else:
        layer_outputs = prefetched_outputs
    n_features    = layer_outputs.shape[channel_axis]

    for _int in range(1, max_col_subplots+1):
      if (n_features/_int).is_integer():
        n_cols = int(n_features/_int)
    n_rows = int(n_features/n_cols)

    fig, axes = plt.subplots(n_rows,n_cols,sharey=equate_axes,dpi=dpi)
    fig.set_size_inches(24*scale_width,16*scale_height)

    subplot_idx = 0
    for row_idx in range(axes.shape[0]):
      for col_idx in range(axes.shape[1]): 
        subplot_idx += 1
        feature_output = layer_outputs[:,subplot_idx-1]
        feature_output = feature_output[:max_timesteps]
        ax = axes[row_idx,col_idx]

        if show_y_zero:
            ax.axhline(0,color='red')
        ax.plot(feature_output)

        ax.axis(xmin=0,xmax=len(feature_output))
        ax.axis('off')

        ax.annotate(str(subplot_idx),xy=(0,.99),xycoords='axes fraction',
                    weight='bold',fontsize=14,color='g')
    if equate_axes:
        y_new = []
        for row_axis in axes:
            y_new += [np.max(np.abs([col_axis.get_ylim() for 
                                     col_axis in row_axis]))]
        y_new = np.max(y_new)
        for row_axis in axes:
            [col_axis.set_ylim(-y_new,y_new) for col_axis in row_axis]
    plt.show()
def show_features_2D(data, cmap='bwr', norm=None,
                     scale_width=1, scale_height=1):
    if norm is not None:
        vmin, vmax = norm
    else:
        vmin, vmax = None, None  # scale automatically per min-max of 'data'

    plt.imshow(data, cmap=cmap, vmin=vmin, vmax=vmax)
    plt.xlabel('Timesteps', weight='bold', fontsize=14)
    plt.ylabel('Attention features', weight='bold', fontsize=14)
    plt.colorbar(fraction=0.046, pad=0.04)  # works for any size plot

    plt.gcf().set_size_inches(8*scale_width, 8*scale_height)
    plt.show()

def get_layer_outputs(model, layer_name, input_data, learning_phase=1):
    outputs   = [layer.output for layer in model.layers if layer_name in layer.name]
    layers_fn = K.function([model.input, K.learning_phase()], outputs)
    return layers_fn([input_data, learning_phase])

SeqWeightedAttention пример за запрос:

ipt   = Input(batch_shape=(10,240,4))
x     = LSTM(60, activation='tanh', return_sequences=True)(ipt)
x     = SeqWeightedAttention(return_attention=True)(x)
x     = concatenate(x)
out   = Dense(1, activation='sigmoid')(x)
model = Model(ipt,out)
model.compile(Adam(lr=1e-2), loss='binary_crossentropy')

X = np.random.rand(10,240,4) # dummy data
Y = np.random.randint(0,2,(10,1)) # dummy labels
model.train_on_batch(X, Y)

outs = get_layer_outputs(model, 'seq', X, 1)
outs_1 = outs[0][0] # additional index since using batch_shape
outs_2 = outs[1][0]

plt.hist(outs_1, bins=500); plt.show()
plt.hist(outs_2, bins=500); plt.show()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...