МАШИННОЕ ОБУЧЕНИЕ

Как извлечь встраивания нейронной сети

Повышение точности прогнозирования с помощью встраивания нейронных сетей

Введение

В нашем предыдущем блоге по разработке функций мы рассмотрели способы ручной разработки функций. В этом блоге мы рассмотрим автоматическую разработку функций, выполняемую нейронными сетями, и то, как извлекать эти вложения и использовать их вместе с функциями, созданными вручную.
Обратите внимание, что мы использовали платформу TensorFlow для всех наших нейронных сетей. конвейеры, поэтому этот метод будет работать только при использовании фреймворка TensorFlow. Прежде чем погрузиться в процесс извлечения вложений, давайте сначала разберемся, что такое вложения и как возникла идея.

Понимание вложений

Хотя идея эмбеддингов была представлена ​​в начале 90-х, в современную эпоху она стала известной, когда в 2013 году Томас Миколов и его коллеги представили алгоритм Word2Vec, который использовал нейронную сеть для генерации эмбеддингов, фиксирующих семантические отношения между слова. Этот прорыв привел к широкому внедрению встраивания слов в приложения NLP. Точно так же мы также можем представить табличные данные в виде вложений, пропустив их через один или несколько плотных слоев.

Мы можем думать о встраиваниях как о выходных данных или закодированных представлениях данных, которые машины могут интерпретировать и которые собирают временную, пространственную и контекстуальную информацию в зависимости от приложения. Эти закодированные представления впоследствии доставляются на уровень или уровни классификатора, которые обеспечивают желаемый результат.

В нашем случае данные получены из обнаружения дефолта по кредиту, а вложения будут выводом всех промежуточных слоев нейронной сети. Обычно эти кодировки будут передаваться в голову классификатора (плотный слой) в нейронных сетях, но мы можем передавать их в другие модели, такие как LGBM (легкий GBM), SVM (машины опорных векторов) и т. д., которые будут действовать как классификатор. голова.

Модель

Мы используем нашу предыдущую модель нейронной сети, которую мы определили в нашем блоге.Сеть вместе со слоем внедрения показана ниже.

Изменения, которые необходимо внести, были внесены в приведенный ниже код.

import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.callbacks import ReduceLROnPlateau, LearningRateScheduler, EarlyStopping
from tensorflow.keras.layers import Dense, Input, InputLayer, Add, Concatenate, Dropout, BatchNormalization

LR_START = 0.01  #defines the learning rate
def my_model(n_inputs=len(features)):
    "neural network with skip connection, 
    Returns a compiled instance of TensorFlow.keras.models.Model."
    activation = 'swish'
    l1 = 1e-7
    l2 = 4e-4
    inputs = Input(shape=(n_inputs, ))
    x0 = BatchNormalization()(inputs)
    x0 = Dense(1024, 
               kernel_regularizer=tf.keras.regularizers.L1L2(l1=l1,l2=l2),
              activation=activation,
             )(x0)
    x0 = Dropout(0.1)(x0)
    x1 = Dense(64, 
              kernel_regularizer=tf.keras.regularizers.L1L2(l1=l1,l2=l2),
              activation=activation,
             )(x0)
    x2 = Dense(64, 
              kernel_regularizer=tf.keras.regularizers.L1L2(l1=l1,l2=l2),
              activation=activation,
             )(x1)
    x3 = Concatenate()([x2, x0])
    x3 = Dropout(0.1)(x3)
    x4 = Dense(16, 
              kernel_regularizer=tf.keras.regularizers.L1L2(l1=l1,l2=l2),
              activation=activation,
             name='embeddings')(x3)#specify the name of the layer
    x5 = Dense(1,
              activation='sigmoid',
             name='output')(x4)  #specify the name of the layer
    model = Model(inputs, [x5,x4])#output x4 to extract embeddings of x4 layer
    model.compile(optimizer=tf.keras.optimizers.Nadam(learning_rate=LR_START,clipvalue= 0.5,clipnorm = 1.0),loss=tf.keras.losses.BinaryCrossentropy(),loss_weights=[1., 0.0])
    return model

Давайте разберемся, какие изменения мы сделали.

Обратите внимание, что мы можем извлечь вложения из любого слоя, который присутствует в нашей нейронной сети(x0,x1,x2,x3, …). Вот пример того, как мы извлекаем встраивание слоя x4.

Чтобы извлечь функции, мы должны указать выходные данные в слое Model переменной x4, как показано ниже.

x4 = Dense(16, 
              kernel_regularizer=tf.keras.regularizers.L1L2(l1=l1,l2=l2),
              activation=activation,
             name='embeddings')(x3)#specify the name of the layer
x5 = Dense(1,
              activation='sigmoid',
             name='output')(x4)  #specify the name of the layer
model = Model(inputs, [x5,x4]) #output x4 to extract embeddings of x4 layer

Обратите внимание, что мы указали веса в нашем слое компиляции модели, чтобы он не оценивался на основе встраивания x4 в качестве вывода, что также выделено на рисунке красным кружком.

model.compile(optimizer=tf.keras.optimizers.Nadam(learning_rate=LR_START,clipvalue= 0.5,clipnorm = 1.0),loss=tf.keras.losses.BinaryCrossentropy(),loss_weights=[1., 0.0])
    return model

Обучение

Теперь, когда мы добавили вставки x4 в наш вывод, мы также должны указать, что наша модель не оценивает встраивания x4, иначе это может привести к логической ошибке.

from sklearn.model_selection import StratifiedKFold, StratifiedGroupKFold
from sklearn.preprocessing import StandardScaler, QuantileTransformer, OneHotEncoder

''' function for scaling data, training of model and validating it
code ref: https://www.kaggle.com/code/ambrosm/amex-keras-quickstart-1-training
'''
def fit_model(X_tr, y_tr, X_va=None, y_va=None, fold=0, run=0):

    global y_va_pred
    gc.collect()
    start_time = datetime.datetime.now()
    
    scaler = StandardScaler()  #scales the training data
    X_tr = scaler.fit_transform(X_tr)
    
    if X_va is not None:
        X_va = scaler.transform(X_va)  #scales the validation data
        validation_data = (X_va,[y_va, np.zeros((len(y_va),16))])
    else:
        validation_data = None
    # Define the learning rate schedule and EarlyStopping
    if USE_PLATEAU and X_va is not None: # use early stopping
        epochs = EPOCHS
        lr = ReduceLROnPlateau(monitor="val_output_loss", factor=0.7,  # scheduler  #specify in 
                               patience=4, verbose=VERBOSE)
        es = EarlyStopping(monitor="val_output_loss",    #stop training if results does not improve for 12 epochs
                           patience=12, 
                           verbose=1,
                           mode="min", 
                           restore_best_weights=True)
        callbacks = [lr, es, tf.keras.callbacks.TerminateOnNaN()]

    else: # use exponential learning rate decay rather than early stopping
        epochs = EPOCHS_EXPONENTIALDECAY

        def exponential_decay(epoch):
            # v decays from e^a to 1 in every cycle
            # w decays from 1 to 0 in every cycle
            # epoch == 0                  -> w = 1 (first epoch of cycle)
            # epoch == epochs_per_cycle-1 -> w = 0 (last epoch of cycle)
            # higher a -> decay starts with a steeper decline
            # ref:
            a = 3
            epochs_per_cycle = epochs // CYCLES
            epoch_in_cycle = epoch % epochs_per_cycle
            if epochs_per_cycle > 1:
                v = math.exp(a * (1 - epoch_in_cycle / (epochs_per_cycle-1)))
                w = (v - 1) / (math.exp(a) - 1)
            else:
                w = 1
            return w * LR_START + (1 - w) * LR_END

        lr = LearningRateScheduler(exponential_decay, verbose=0)
        callbacks = [lr, tf.keras.callbacks.TerminateOnNaN()]
        
    # Construct and compile the model
    model = my_model(X_tr.shape[1])   #define and compile model
    # Train the model

    history = model.fit(X_tr, [y_tr,np.zeros((len(y_tr),16))],    #fit model 
                        validation_data=validation_data, 
                        epochs=epochs,
                        verbose=VERBOSE,
                        batch_size=BATCH_SIZE,
                        shuffle=True,
                        callbacks=callbacks)
    del X_tr, y_tr
    with open(f"scaler_{fold}.pickle", 'wb') as f: pickle.dump(scaler, f)  #save standard scaler for real-time interaction 
    model.save(f"model_{fold}") #save model weights
    history_list.append(history.history)
    callbacks, es, lr, history = None, None, None, None

    lastloss = f"Training loss: {history_list[-1]['loss'][-1]:.4f} | Val loss: {history_list[-1]['val_loss'][-1]:.4f}"
        
        # Inference for validation
        y_va_pred = model.predict(X_va, batch_size=len(X_va), verbose=0)[0].ravel()
        
        # Evaluation: Execution time, loss and metrics
        score = evaluation_metric(y_va, y_va_pred)
        print(f"{Fore.GREEN}{Style.BRIGHT}Fold {run}.{fold} | {str(datetime.datetime.now() - start_time)[-12:-7]}"
              f" | {len(history_list[-1]['loss']):3} ep"
              f" | {lastloss} | Score: {score:.5f}{Style.RESET_ALL}")
        score_list.append(score)
        
        if DIAGRAMS and fold == 0 and run == 0:
            # Plot training history
            plot_history(history_list[-1], 
                         title=f"Learning curve",
                         plot_lr=True)

        # Scale and predict
        y_pred_list.append(model.predict(scaler.transform(test), batch_size=128*1024, verbose=0).ravel())

Изменения, которые нам нужно внести в наш обучающий код,

  • Измените форму validation_data, как указано ниже.
validation_data = (X_va,[y_va, np.zeros((len(y_va),16))])
  • Измените model.fit и измените форму тренировочных меток.
history = model.fit(X_tr, [y_tr,np.zeros((len(y_tr),16))],    #fit model 
                        validation_data=validation_data, 
                        epochs=epochs,
                        verbose=VERBOSE,
                        batch_size=BATCH_SIZE,
                        shuffle=True,
                        callbacks=callbacks)
  • Измените планировщик на раннюю остановку, чтобы модель оценивала только истинные метки, а не вложения.
lr = ReduceLROnPlateau(monitor="val_output_loss", factor=0.7,  # scheduler  #specify in 
                               patience=4, verbose=VERBOSE)
es = EarlyStopping(monitor="val_output_loss",    #stop training if results does not improve for 12 epochs
                           patience=12, 
                           verbose=1,
                           mode="min", 
                           restore_best_weights=True)

Теперь все готово, мы извлекли наши вложения.

Как использовать вложения?

Вложения, сгенерированные нейронными сетями, имеют табличный формат. Следовательно, их использование можно просто объединить с функциями, созданными вручную в наших предыдущих блогах.

Мы также можем извлечь вложения из модели GRU, которую мы создали здесь, и использовать эти функции в нашей окончательной модели. Сочетание признаков, несущих временную информацию, и созданных вручную признаков может иметь большое значение для модели.

Заключение

Теперь мы знаем, что использование вложений, созданных нейронной сетью, может стать практической заменой ручного проектирования функций. Мы можем повысить эффективность и точность наших моделей машинного обучения, используя вложения, что в конечном итоге приведет к лучшим результатам и большему разнообразию в нашем конвейере.