OptKeras (Keras Optuna Wrapper) - использовать optkeras внутри моего собственного класса AttributeError: объект типа 'FrozenTrial' не имеет атрибута '_field_types'

Я написал простой код Keras, в котором я использую CNN для набора данных fashion mnist. Все отлично работает. Я реализовал свой собственный класс, и классификация в порядке.

Однако я хотел использовать Optuna в качестве OptKeras (оболочка Optuna для Keras), вы можете увидеть пример здесь: https://medium.com/@Minyus86/optkeras-112bcc34ec73.

Однако что-то не так с моим кодом. Когда я пытаюсь использовать optKeras внутри своего класса. Вот код: (обычныйrun метод работает, но optuna_run выдает ошибку: AttributeError: type object 'FrozenTrial' has no attribute '_field_types'.

! pip install optkeras
# -*- coding: utf-8 -*- 
#!/usr/bin/env python3

import tensorflow as tf
from tensorflow import keras

from keras.models import Sequential
from keras.layers import Dense, SimpleRNN 
from keras.callbacks import ModelCheckpoint
from keras import backend as K

from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
import sklearn.metrics

import optuna
from optkeras.optkeras import OptKeras

import sys
import math
import numpy
import scipy.io as sio   
import matplotlib.pyplot as plt

class OptunaTest():

  def __init__(self):
    self.fashion_mnist = keras.datasets.fashion_mnist
    (self.train_images, self.train_labels), (self.test_images, self.test_labels) = self.fashion_mnist.load_data()
    self.class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
    self.train_images = self.train_images / 255.0
    self.test_images = self.test_images / 255.0
    self.model = None 
    self.study_name = 'FashionMnist' + '_Simple'
    self.ok = OptKeras(study_name=self.study_name)

  def run(self):
    self.model = keras.Sequential()
    self.model.add(keras.layers.Flatten(input_shape=(28, 28)))
    self.model.add(keras.layers.Dense(128, activation='relu'))
    self.model.add(keras.layers.Dense(10))
    self.model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
    self.model.fit(self.train_images, self.train_labels, epochs=5)
    test_loss, test_acc = self.model.evaluate(self.test_images, self.test_labels, verbose=0)
    predictions = self.model.predict(self.test_images)

    INDEX = 10
    print("\nPREDICTION: " + str(predictions[INDEX]))
    print("\nMAX PREDICTION VAL: " + str(numpy.argmax(predictions[INDEX])))
    print("\nLABEL: " + str(self.test_labels[INDEX]))

  def optuna_run(self, trial):
    K.clear_session() 
    
    self.model = keras.Sequential()
    self.model.add(keras.layers.Flatten(input_shape=(28, 28)))
    self.model.add(keras.layers.Dense(units = trial.suggest_categorical('units', [32, 64, 128]), activation = trial.suggest_categorical('activation', ['relu', 'linear'])))
    self.model.add(keras.layers.Dense(units = trial.suggest_categorical('units', [32, 64, 128]), activation = trial.suggest_categorical('activation', ['relu', 'linear'])))

    self.model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
    self.model.fit(self.train_images, self.train_labels, epochs=5, callbacks = self.ok.callbacks(trial), verbose = self.ok.keras_verbose)
    test_loss, test_acc = self.model.evaluate(self.test_images, self.test_labels, verbose=0)
    predictions = self.model.predict(self.test_images)
    print(ok.trial_best_value)
    
    INDEX = 10
    print("\nPREDICTION: " + str(predictions[INDEX]))
    print("\nMAX PREDICTION VAL: " + str(numpy.argmax(predictions[INDEX])))
    print("\nLABEL: " + str(self.test_labels[INDEX]))


if __name__ == "__main__":
  ot = OptunaTest()
  ot.run()

  ot.ok.optimize(ot.optuna_run,  timeout = 60)

Код также можно найти здесь: https://colab.research.google.com/drive/1uibWa80BdjatA5Kcw27eMUsS7SmwxaDk?usp=sharing.

Полное сообщение об ошибке:

[W 2020-06-30 11:09:26,959] Setting status of trial#0 as TrialState.FAIL because of the following error: AttributeError("type object 'FrozenTrial' has no attribute '_field_types'",)
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/optkeras/optkeras.py", line 230, in synch_with_optuna
    self.best_trial = self.study.best_trial
  File "/usr/local/lib/python3.6/dist-packages/optuna/study.py", line 97, in best_trial
    return copy.deepcopy(self._storage.get_best_trial(self._study_id))
  File "/usr/local/lib/python3.6/dist-packages/optuna/storages/in_memory.py", line 293, in get_best_trial
    raise ValueError("No trials are completed yet.")
ValueError: No trials are completed yet.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/optuna/study.py", line 734, in _run_trial
    result = func(trial)
  File "/usr/local/lib/python3.6/dist-packages/optkeras/optkeras.py", line 130, in fun_tf
    return fun(trial)
  File "<ipython-input-11-45495c9f2ae9>", line 65, in optima_run
    self.model.fit(self.train_images, self.train_labels, epochs=10, callbacks = self.ok.callbacks(trial), verbose = self.ok.keras_verbose)
  File "/usr/local/lib/python3.6/dist-packages/optkeras/optkeras.py", line 172, in callbacks
    self.synch_with_optuna()
  File "/usr/local/lib/python3.6/dist-packages/optkeras/optkeras.py", line 232, in synch_with_optuna
    self.best_trial = get_trial_default()
  File "/usr/local/lib/python3.6/dist-packages/optkeras/optkeras.py", line 367, in get_trial_default
    num_fields = optuna.structs.FrozenTrial._field_types.__len__()
AttributeError: type object 'FrozenTrial' has no attribute '_field_types'

---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

/usr/local/lib/python3.6/dist-packages/optkeras/optkeras.py in synch_with_optuna(self)
    229         try:
--> 230             self.best_trial = self.study.best_trial
    231         except:

12 frames

ValueError: No trials are completed yet.


During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)

/usr/local/lib/python3.6/dist-packages/optkeras/optkeras.py in get_trial_default()
    365 
    366 def get_trial_default():
--> 367     num_fields = optuna.structs.FrozenTrial._field_types.__len__()
    368     assert num_fields in (10, 11, 12)
    369     if num_fields == 12: # possible future version

AttributeError: type object 'FrozenTrial' has no attribute '_field_types'

1 ответ

Решение

Похоже, что optkeras (версия, которую я получил, была 0.0.7), не совсем обновленная с библиотекой optuna, является причиной проблемы. Мне удалось заставить его работать с optuna 1.5.0, выполнив следующие изменения:

Во-первых, вам понадобится обезьяна-патч get_default_trial вот так перед запуском кода:

import optkeras
optkeras.optkeras.get_trial_default = lambda: optuna.trial.FrozenTrial(
            None, None, None, None, None, None, None, None, None, None, None)

После этого я получаю сообщение об ошибке Callback говоря:

AttributeError: 'OptKeras' object has no attribute '_implements_train_batch_hooks'

Чтобы решить эту проблему, вам придется вручную отредактировать optkeras.py, но не слишком много - просто добавьте tensorflow. в первые две строки импортировать, т.е. сделать их:

import tensorflow.keras.backend as K
from tensorflow.keras.callbacks import Callback, CSVLogger, ModelCheckpoint

вместо того:

import keras.backend as K
from keras.callbacks import Callback, CSVLogger, ModelCheckpoint

Если вы не можете изменить код после установки, это может быть проблемой - я бы, вероятно, просто рекомендовал скопировать полный код библиотеки optkeras (это всего лишь один файл optkeras.py) и использовать фиксированную версию этого в своем скрипте или что-то такое. К сожалению, я не вижу хорошего способа исправить эту проблему импорта. Тем не менее, я думаю, что довольно легко изменить это на лету даже с python (т.е.optkeras.py строки изнутри python перед импортом optkeras) или копирование optkeras.py (также из скрипта python) + замена строк на лету, а затем импорт из нового местоположения.

После этого мне оставалось только:

  • исправить опечатку в коде (print(ok.trial_best_value) действительно должно быть print(self.ok.trial_best_value))
  • Добавить validation_split=0.1 к self.model.fit вызовите (или вы можете использовать что-то еще для своей настройки - просто с существующим примером кода обратный вызов не получит val_loss значение, потому что нет набора проверки и optkeras использует val_loss по умолчанию - см. monitor аргумент в пользу OptKerasконструктор). Я предполагаю, что вы, вероятно, захотите вместо этого создать фиксированный набор проверки или отслеживать потерю обучения.loss вместо того val_loss.
  • Добавить return test_loss в конце optuna_run метод.

После всех этих изменений все вроде работает.

Другие вопросы по тегам