МАШИННОЕ ОБУЧЕНИЕ
Как извлечь встраивания нейронной сети
Повышение точности прогнозирования с помощью встраивания нейронных сетей
Введение
В нашем предыдущем блоге по разработке функций мы рассмотрели способы ручной разработки функций. В этом блоге мы рассмотрим автоматическую разработку функций, выполняемую нейронными сетями, и то, как извлекать эти вложения и использовать их вместе с функциями, созданными вручную.
Обратите внимание, что мы использовали платформу 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, которую мы создали здесь, и использовать эти функции в нашей окончательной модели. Сочетание признаков, несущих временную информацию, и созданных вручную признаков может иметь большое значение для модели.
Заключение
Теперь мы знаем, что использование вложений, созданных нейронной сетью, может стать практической заменой ручного проектирования функций. Мы можем повысить эффективность и точность наших моделей машинного обучения, используя вложения, что в конечном итоге приведет к лучшим результатам и большему разнообразию в нашем конвейере.