[PYTHON] J'ai essayé AdaNet pour les données de table

introduction

Récemment, j'ai découvert AdaNet (https://github.com/tensorflow/adanet), une bibliothèque de construction automatique pour l'apprentissage en profondeur, mais comme l'échantillon contenait beaucoup de données d'image et que l'échantillon était petit pour les données de table, j'ai rédigé un mémorandum. Je vais également faire une note.

Les programmes suivants sont basés sur cet article. https://towardsdatascience.com/modeling-banks-churn-rate-with-adanet-a-scalable-flexible-auto-ensemble-learning-framework-700fa1e6df74

environnement

J'ai utilisé Google Colaboratory.

Ce que j'ai fait

Installation de la bibliothèque

Installez avec pip et vous avez terminé.

! pip install adanet

Dans la sortie, j'ai eu une ERREUR, mais à la fin cela a fonctionné sans problème.

(réduction)
Successfully built rednose termstyle
ERROR: datascience 0.10.6 has requirement coverage==3.7.1, but you'll have coverage 4.5.4 which is incompatible.
ERROR: datascience 0.10.6 has requirement folium==0.2.1, but you'll have folium 0.8.3 which is incompatible.
ERROR: coveralls 0.5 has requirement coverage<3.999,>=3.6, but you'll have coverage 4.5.4 which is incompatible.
Installing collected packages: nose, termstyle, colorama, rednose, coverage, mock, adanet
  Found existing installation: coverage 3.7.1
    Uninstalling coverage-3.7.1:
      Successfully uninstalled coverage-3.7.1
Successfully installed adanet-0.8.0 colorama-0.4.3 coverage-4.5.4 mock-3.0.5 nose-1.3.7 rednose-1.3.0 termstyle-0.1.11

Préparation

Créez un répertoire pour enregistrer les informations du modèle lors de la création du modèle.

!mkdir ./models

Importer la bibliothèque

Tout d'abord, importez les bibliothèques requises.

from __future__ import division
from __future__ import print_function

import functools
import os
import shutil

import adanet
from adanet.examples import simple_dnn
import matplotlib.pyplot as plt
import tensorflow as tf
import pandas as pd
from sklearn.model_selection import train_test_split


# The random seed to use.
RANDOM_SEED = 42

LOG_DIR = './models'

Chargement des données

Cette fois, nous utiliserons l'ensemble de données sur le cancer du sein fourni par scicit-learn. Consultez la page sklearn pour obtenir des instructions. https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_breast_cancer.html#sklearn.datasets.load_breast_cancer


from sklearn.datasets import load_breast_cancer
data = load_breast_cancer()
df_X = pd.DataFrame(data.data, columns=data.feature_names)
df_y = pd.DataFrame(data.target, columns=['target'])
x_train, x_test, y_train, y_test = train_test_split(df_X, df_y, test_size=0.2, random_state=100)

Dans ces données, la variable objectif est 0 ou 1, c'est donc une question de classification binaire.

df_y['target'].unique()
array([0, 1])

Préparation des fonctions utilisées dans AdaNet

Ecrivez une fonction pour transmettre les données à AdaNet. Les données sont passées en type dict à from_tensor_slices of tensorflow.

FEATURES_KEY = "x"
_NUM_LAYERS_KEY = "num_layers"

def input_fn(partition, training, batch_size):
  """Generate an input function for the Estimator."""

  def _input_fn():

    if partition == "train":
      dataset = tf.data.Dataset.from_tensor_slices(({FEATURES_KEY: x_train}, y_train))
    else:
      dataset = tf.data.Dataset.from_tensor_slices(({FEATURES_KEY: x_test},  y_test))

    # repeat is called after shuffling,to prevent separate epochs from blending together.
    if training:
      dataset = dataset.shuffle(10 * batch_size, seed=RANDOM_SEED).repeat()

    dataset = dataset.batch(batch_size)
    iterator = dataset.make_one_shot_iterator()
    features, labels = iterator.get_next()
    return features, labels

  return _input_fn

Préparez une classe pour le Deep Learning.


class _SimpleDNNBuilder(adanet.subnetwork.Builder):
  """Builds a DNN subnetwork for AdaNet."""

  def __init__(self, optimizer, layer_size, num_layers, learn_mixture_weights,
               seed):

    self._optimizer = optimizer
    self._layer_size = layer_size
    self._num_layers = num_layers
    self._learn_mixture_weights = learn_mixture_weights
    self._seed = seed

  def build_subnetwork(self,
                       features,
                       labels,
                       logits_dimension,
                       training,
                       iteration_step,
                       summary,
                       previous_ensemble=None):

    input_layer = tf.to_float(features[FEATURES_KEY])
    kernel_initializer = tf.glorot_uniform_initializer(seed=self._seed)
    last_layer = input_layer
    for _ in range(self._num_layers):
      last_layer = tf.layers.dense(
          last_layer,
          units=self._layer_size,
          activation=tf.nn.relu,
          kernel_initializer=kernel_initializer)
    logits = tf.layers.dense(
        last_layer,
        units=logits_dimension,
        kernel_initializer=kernel_initializer)
    persisted_tensors = {_NUM_LAYERS_KEY: tf.constant(self._num_layers)}
    return adanet.Subnetwork(
        last_layer=last_layer,
        logits=logits,
        complexity=self._measure_complexity(),
        persisted_tensors=persisted_tensors)

  def _measure_complexity(self):
    """Approximates Rademacher complexity as the square-root of the depth."""
    return tf.sqrt(tf.to_float(self._num_layers))

  def build_subnetwork_train_op(self, subnetwork, loss, var_list, labels,
                                iteration_step, summary, previous_ensemble):
    return self._optimizer.minimize(loss=loss, var_list=var_list)

  def build_mixture_weights_train_op(self, loss, var_list, logits, labels,
                                     iteration_step, summary):
    if not self._learn_mixture_weights:
      return tf.no_op()
    return self._optimizer.minimize(loss=loss, var_list=var_list)

  @property
  def name(self):
    if self._num_layers == 0:
      # A DNN with no hidden layers is a linear model.
      return "linear"
    return "{}_layer_dnn".format(self._num_layers)  

class SimpleDNNGenerator(adanet.subnetwork.Generator):
  """Generates a two DNN subnetworks at each iteration.
  """

  def __init__(self,
               optimizer,
               layer_size=32,
               learn_mixture_weights=False,
               seed=None):

    self._seed = seed
    self._dnn_builder_fn = functools.partial(
        _SimpleDNNBuilder,
        optimizer=optimizer,
        layer_size=layer_size,
        learn_mixture_weights=learn_mixture_weights)
  def generate_candidates(self, previous_ensemble, iteration_number,
                          previous_ensemble_reports, all_reports, config):
    """See `adanet.subnetwork.Generator`."""

    num_layers = 0
    seed = self._seed
    if previous_ensemble:
      num_layers = tf.contrib.util.constant_value(
          previous_ensemble.weighted_subnetworks[
              -1].subnetwork.persisted_tensors[_NUM_LAYERS_KEY])
    if seed is not None:
      seed += iteration_number
    return [
        self._dnn_builder_fn(num_layers=num_layers, seed=seed),
        self._dnn_builder_fn(num_layers=num_layers + 1, seed=seed),
    ]

Je décrirai la partie exécution. Les paramètres au début définissent le RMSPropOptimizer utilisé pour ajuster le taux d'apprentissage et le nombre total de formations. Puisque cette fois c'est une classification binaire, binary_classification_head est utilisé pour la tête de ʻadanet.Estimator`.


# AdaNet parameters
LEARNING_RATE = 0.001
TRAIN_STEPS = 100000 
BATCH_SIZE = 32 

LEARN_MIXTURE_WEIGHTS = False
ADANET_LAMBDA = 0 
BOOSTING_ITERATIONS = 5

def train_and_evaluate(learn_mixture_weights=LEARN_MIXTURE_WEIGHTS,
                       adanet_lambda=ADANET_LAMBDA):
  """Trains an `adanet.Estimator` to predict churn yes/no."""

  estimator = adanet.Estimator(
      # Since we are predicting churn, we'll use a regression
      # head that optimizes for MSE.
      head=tf.contrib.estimator.binary_classification_head(
          loss_reduction=tf.losses.Reduction.SUM_OVER_BATCH_SIZE),

      # Define the generator, which defines our search space of subnetworks
      # to train as candidates to add to the final AdaNet model.
      subnetwork_generator=SimpleDNNGenerator(
          optimizer=tf.train.RMSPropOptimizer(learning_rate=LEARNING_RATE),
          learn_mixture_weights=learn_mixture_weights,
          seed=RANDOM_SEED),

  
      adanet_lambda=adanet_lambda,
      # The number of train steps per iteration.
      max_iteration_steps=TRAIN_STEPS // BOOSTING_ITERATIONS,

      # The evaluator will evaluate the model on the full training set to
      # compute the overall AdaNet loss (train loss + complexity
      # regularization) to select the best candidate to include in the
      # final AdaNet model.
      evaluator=adanet.Evaluator(
          input_fn=input_fn("train", training=False, batch_size=BATCH_SIZE)),

      # The report materializer will evaluate the subnetworks' metrics
      # using the full training set to generate the reports that the generator
      # can use in the next iteration to modify its search space.
      report_materializer=adanet.ReportMaterializer(
          input_fn=input_fn("train", training=False, batch_size=BATCH_SIZE)),

      # Configuration for Estimators.
      config=tf.estimator.RunConfig(
          save_checkpoints_steps=50000,
          save_summary_steps=50000,
          tf_random_seed=RANDOM_SEED))

  # Train and evaluate using using the tf.estimator tooling.
  train_spec = tf.estimator.TrainSpec(
      input_fn=input_fn("train", training=True, batch_size=BATCH_SIZE),
      max_steps=TRAIN_STEPS)
  eval_spec = tf.estimator.EvalSpec(
      input_fn=input_fn("test", training=False, batch_size=BATCH_SIZE),
      steps=None)
  return tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)

def ensemble_architecture(result):
  """Extracts the ensemble architecture from evaluation results."""

  architecture = result["architecture/adanet/ensembles"]
  # The architecture is a serialized Summary proto for TensorBoard.
  summary_proto = tf.summary.Summary.FromString(architecture)
  return summary_proto.value[0].tensor.string_val[0]


results, _ = train_and_evaluate()
print("Loss:", results["average_loss"])
print("Results:", results)
print("Architecture:", ensemble_architecture(results))

Le résultat de l'exécution est le suivant. Puisqu'il y a beaucoup de sortie standard, seule la dernière partie est affichée. La précision est d'environ 93%.

(réduction)
Loss: 0.1722714
Results: {'accuracy': 0.9298246, 'accuracy_baseline': 0.5701754, 'architecture/adanet/ensembles': b'\n1\n\x13architecture/adanetB\x10\x08\x07\x12\x00B\n| linear |J\x08\n\x06\n\x04text', 'auc': 0.99623233, 'auc_precision_recall': 0.9973264, 'average_loss': 0.1722714, 'best_ensemble_index_0': 0, 'iteration': 0, 'label/mean': 0.5701754, 'loss': 0.16755146, 'precision': 1.0, 'prediction/mean': 0.49755728, 'recall': 0.8769231, 'global_step': 20000}
Architecture: b'| linear |'

Résumé

J'ai essayé AdaNet contre les données de table. J'ai senti que c'était une image à écrire dans un programme à l'exception de la couche d'apprentissage en profondeur et de la partie implémentation du nœud.

Recommended Posts

J'ai essayé AdaNet pour les données de table
J'ai essayé MLflow sur Databricks
J'ai essayé Cython sur Ubuntu sur VirtualBox
J'ai essayé de visualiser les données BigQuery à l'aide de Jupyter Lab avec GCP
J'ai essayé de récupérer les données de conversation d'ASKfm
J'ai essayé d'utiliser l'API de données YOUTUBE V3
J'ai essayé l'analyse factorielle avec des données Titanic!
J'ai essayé de gratter
J'ai essayé PyQ
J'ai essayé AutoKeras
J'ai essayé le moulin à papier
J'ai essayé django-slack
J'ai essayé Django
J'ai essayé spleeter
J'ai essayé cgo
J'ai essayé la fonction de tableau croisé dynamique des pandas
J'ai essayé d'utiliser l'API à distance avec GAE / J
J'ai essayé de sauvegarder les données avec discorde
J'ai essayé d'exécuter YOLO v3 avec Google Colab
J'ai essayé d'analyser les principaux composants avec les données du Titanic!
J'ai essayé d'obtenir des données CloudWatch avec Python
J'ai essayé de lancer jupyter nteract sur le serveur heroku
[Pythonocc] J'ai essayé d'utiliser la CAO sur un notebook Jupyter
J'ai essayé l'API de message LINE (line-bot-sdk-python) avec GAE
J'ai essayé DBM avec Pylearn 2 en utilisant des données artificielles
J'ai essayé de jouer avec la calculatrice avec tkinter
[IBM Cloud] J'ai essayé d'accéder à la table Db2 on Cloud à partir de Cloud Funtions (python)
J'ai essayé de récupérer les données de l'ordinateur portable en le démarrant sur Ubuntu
J'ai essayé d'utiliser paramétré
J'ai essayé d'utiliser argparse
J'ai essayé d'utiliser la mimesis
J'ai essayé d'utiliser anytree
J'ai essayé d'exécuter pymc
J'ai essayé Python sur Mac pour la première fois.
J'ai essayé le spoofing ARP
J'ai essayé d'exécuter l'application sur la plateforme IoT "Rimotte"
J'ai essayé d'implémenter Mine Sweeper sur un terminal avec python
J'ai essayé d'utiliser aiomysql
J'ai essayé d'utiliser Summpy
J'ai essayé de prédire le match de la J League (analyse des données)
J'ai essayé Python> autopep8
J'ai essayé python pour la première fois avec heroku
J'ai essayé d'utiliser coturn
J'ai essayé d'utiliser Pipenv
J'ai essayé d'utiliser matplotlib
J'ai essayé d'utiliser "Anvil".
J'ai essayé d'utiliser Hubot
J'ai essayé d'utiliser ESPCN
J'ai essayé PyCaret2.0 (pycaret-nightly)
J'ai essayé d'utiliser openpyxl
J'ai essayé un test de régression visuelle sur les pages GitHub
J'ai essayé de regrouper les données ECG en utilisant la méthode K-Shape
J'ai essayé le deep learning
J'ai essayé AWS CDK!
J'ai essayé d'utiliser Ipython
J'ai essayé de déboguer.
J'ai essayé d'utiliser PyCaret
J'ai essayé d'utiliser cron