Keras: использование пользовательского значения metri c для l oop - ValueError: невозможно интерпретировать идентификатор функции metri c - PullRequest
0 голосов
/ 09 апреля 2020

Keras CNN для двоичного семанти c сегментация

Я использую для l oop, чтобы перебрать различные разделы обучения-проверки, и, похоже, он работает на первом проходе через l oop, но перерывы на второй проход. Когда model.fit () выполняется, я получаю ошибку значения

ValueError: Невозможно интерпретировать metri c идентификатор функции: 0.752065122127533

Я думаю, что это, вероятно, связано с пользовательскими метриками, которые я использую. не имеет значения, какой пользовательский метри c я пытаюсь, (dice_loss, F1), кажется, он сломается, если я просто не использую стандартную (точность) метри c, но из-за дисбаланса класса это не очень хороший показатель c для моя проблема.

Я пытался удалять модель после каждой итерации, но это тоже не решает.

Также странно, что она запускается без проблем в первый раз, выполняя все 5 сгибов, но все Последующая попытка не работает.

%tensorflow_version 2.x
import tensorflow as tf

from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D, BatchNormalization
from tensorflow.keras.layers import Concatenate, Conv2DTranspose, Flatten, Activation, Add
from tensorflow.keras.models import Model
from tensorflow.keras.callbacks import ReduceLROnPlateau, EarlyStopping, ModelCheckpoint
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, Conv2DTranspose
from tensorflow.keras.constraints import max_norm
from tensorflow.keras import backend as K
from statistics import mean
import sklearn.metrics
from sklearn.model_selection import train_test_split, KFold
import numpy as np
import matplotlib.pyplot as plt
import os
from PIL import Image
import random
import cv2
from random import shuffle
from glob import glob
from imageio import imread, imwrite
import datetime


x = sorted(os.listdir(image_dir))
y = sorted(os.listdir(label_dir))
# create lists with full paths
X = []
Y = []
for image in x:
  full_path = os.path.join(image_dir + os.sep + image)
  X.append(full_path)

for label in y:
  full_path = os.path.join(label_dir + os.sep + label)
  Y.append(full_path)

# train- test split
train_images, TEST_images, train_labels, TEST_labels = train_test_split(X,Y,train_size = .8, random_state = 2)
train_images = np.array(train_images)
TEST_images = np.array(TEST_images)
train_labels = np.array(train_labels)
TEST_labels = np.array(TEST_labels)

ct = datetime.datetime.now() # current time
date =  str(ct.month) +"_" + str(ct.day) + "_" +str(ct.year)
sz = (128,128)
batch_size = 5
epochs = 10
optimizer = 'adam'
model_name = 'unet'
filepath = model_name + '.h5'
run_name = date +"_" + model_name +"_" +optimizer 
print(f"This is model run: {run_name}")

def image_generator(image_files, label_files ,batch_size, sz):
  while True:
    batch_index = np.random.choice(len(image_files), size = batch_size, replace = False)
    batch_x = []
    batch_y = []
    for i in batch_index:
        mask = Image.open(glob(label_files[i])[0])
        mask = np.array(mask.resize(sz))
        mask[mask == 0 ] = 0
        mask[mask > 0] = 1
        batch_y.append(mask)
        #preprocess the raw images
        raw = Image.open(image_files[i])
        raw = raw.resize(sz)
        raw = np.array(raw)
        #check the number of channels because some of the images are RGBA or GRAY
        if len(raw.shape) == 2:
          raw = np.stack((raw,)*3, axis=-1)
        else:
          raw = raw[:,:,0:3]
        #raw = ((raw - np.mean(raw))/np.std(raw))#.astype('uint8')
        batch_x.append(raw/255.)
    #preprocess a batch of images and masks
    batch_x = np.array(batch_x)#/255.
    batch_y = np.array(batch_y)
    batch_y = np.expand_dims(batch_y,3)#/255.
    yield (batch_x, batch_y)

test_generator = image_generator(TEST_images,TEST_labels,batch_size = batch_size,sz = sz)

# custom metric 
smooth = 1.
def dice_coef(y_true, y_pred):
    y_true_f = tf.reshape(tf.dtypes.cast(y_true, tf.float32), [-1])
    y_pred_f = tf.reshape(tf.dtypes.cast(y_pred, tf.float32), [-1])
    intersection = tf.reduce_sum(y_true_f * y_pred_f)
    return (2. * intersection + smooth) / (tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_f) + smooth)


def dice_coef_loss(y_true, y_pred):
    return 1.0 - dice_coef(y_true, y_pred)

def build_callbacks(filepath):
        checkpointer = ModelCheckpoint(filepath=filepath, verbose=2, save_best_only=True, save_weights_only=True)
        callbacks = [checkpointer, PlotLearning()]
        callbacks = [PlotLearning()]
        return callbacks
# inheritance for training process plot 
class PlotLearning(tf.keras.callbacks.Callback):

    def on_train_begin(self, logs={}):
        self.i = 0
        self.x = []
        self.losses = []
        self.val_losses = []
        self.acc = []
        self.val_acc = []
        #self.fig = plt.figure()
        self.logs = []
    def on_epoch_end(self, epoch, logs={}):
        self.logs.append(logs)
        self.x.append(self.i)
        self.losses.append(logs.get('loss'))
        self.val_losses.append(logs.get('val_loss'))
        self.acc.append(logs.get('dice_coef'))
        self.val_acc.append(logs.get('val_dice_coef'))
        self.i += 1
        print('i=',self.i,'loss=',logs.get('loss'),'val_loss=',logs.get('val_loss'),'dice_coef=',logs.get('dice_coef'),'val_dice_coef=',logs.get('val_dice_coef'))


        #choose a random test image and preprocess
        path = np.random.choice(VAL_images)
        raw = Image.open(path) # open image
        raw = np.array(raw.resize(sz[:2]))/255.
        raw = raw[:,:,0:3]
        #predict the mask 
        pred = model.predict(np.expand_dims(raw, 0))
        #mask post-processing 
        msk  = pred.squeeze() 
        msk = np.stack((msk,)*3, axis=-1) 
        msk = msk*25
        msk[msk >= 0.5] = 1 
        msk[msk < 0.5] = 0 

        #show the mask and the segmented image 
        combined = np.concatenate([raw, msk, raw* msk], axis = 1)
        plt.axis('off')
        plt.imshow(combined)
        plt.show()

def unet(sz):
    inputs = Input(sz)
    _ = inputs
    f = 8 
    layers = []
    for i in range(0, 6): 
      _ = Conv2D(f, 3, activation='relu', padding='same') (_) # c1
      _ = Conv2D(f, 3, activation='relu', padding='same') (_) # c1
      layers.append(_)
      _ = MaxPooling2D() (_) # p1
      f = f*2
    ff2 = 64 
    j = len(layers) - 1
    _ = Conv2D(f, 3, activation='relu', padding='same') (_) # c2
    _ = Conv2D(f, 3, activation='relu', padding='same') (_) # c2
    _ = Conv2DTranspose(ff2, 2, strides=(2, 2), padding='same') (_) # ?
    _ = Concatenate(axis=3)([_, layers[j]])  # ?
    j = j -1 
    for i in range(0, 5):
      ff2 = ff2//2
      f = f // 2 
      _ = Conv2D(f, 3, activation='relu', padding='same') (_) # u3
      _ = Conv2D(f, 3, activation='relu', padding='same') (_) # u3
      _ = Conv2DTranspose(ff2, 2, strides=(2, 2), padding='same') (_) # u3
      _ = Concatenate(axis=3)([_, layers[j]]) # u3
      j = j -1  
    _ = Conv2D(f, 3, activation='relu', padding='same') (_) #?
    _ = Conv2D(f, 3, activation='relu', padding='same') (_) #?
    outputs = Conv2D(1, 1, activation='sigmoid') (_) #?
    model = Model(inputs=[inputs], outputs=[outputs])
    return model  

kf = KFold(5)
fold = 0
for train, val in kf.split(train_images):
  fold+=1
  nfilepath = '_'+str(fold)+'_' + filepath
  print(f"Fold #{fold}")
  run_name_fold = run_name + 'fold' + str(fold)
  TRAIN_images = train_images[train]
  TRAIN_labels = train_labels[train]
  VAL_images = train_images[val]
  VAL_labels = train_labels[val]
  train_generator = image_generator(TRAIN_images,TRAIN_labels, batch_size=batch_size, sz = sz)
  val_generator = image_generator(VAL_images,VAL_labels, batch_size=batch_size, sz = sz)
  model = unet(sz=sz + (3,))
  model.compile(optimizer = optimizer, loss = 'binary_crossentropy', metrics = [dice_coef ,'acc'])
  train_steps = len(TRAIN_images) //batch_size # note // is floor division, and thus provides no remainder
  val_steps = len(VAL_images) //batch_size
  history = model.fit(train_generator, epochs = epochs, steps_per_epoch=train_steps,
                    validation_data=val_generator, validation_steps=val_steps,
                    callbacks= build_callbacks(filepath = nfilepath),
                    verbose = 2)
  plot_name = 'Fig_' + run_name_fold + '.PNG'
  print(plot_name)
  #plot 1
  plt.figure(figsize=(12,4))
  plt.subplot(121)
  plt.plot(history.history['dice_coef'])
  plt.plot(history.history['acc'])
  plt.title('training set')
  plt.xlabel('epoch')
  plt.legend(['dice loss','Accuracy'])
  plt.subplot(122)
  plt.plot(history.history['val_dice_coef'])
  plt.plot(history.history['val_acc'])
  plt.title('validation set')
  plt.xlabel('epoch')
  plt.legend(['dice loss','Accuracy'])
  plt.savefig(plot_name)
  test_steps = len(TEST_images) //batch_size
  loss, dice_coef, acc = model.evaluate(test_generator, batch_size=batch_size, steps = test_steps, verbose = 2)
  print(f"Model loss:{loss} - fold {fold}")
  print(f"Dice-loss coefficent:{dice_coef} - fold {fold}")
  print(f"Accuracy: {acc} - fold {fold}")

ValueError Traceback (последний последний вызов) в () 19 validation_data = val_generator, validation_steps = val_steps, 20 callbacks = build_callbacks (filepath = nfilepath), ---> 21 verbose = 2 ) 22 plot_name = 'Fig_' + run_name_fold + '.PNG' 23 print (plot_name)

10 кадров /usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/ func_graph.py в оболочке (* args, ** kwargs) 966 за исключением Исключения как e: # pylint: disable = broad-кроме 967, если hasattr (e, "ag_error_metadata"): -> 968 поднять e.ag_error_metadata.to_exception (e ) 969 остальное: 970 повышение

ValueError: в коде пользователя:

/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py:505 train_function  *
    outputs = self.distribute_strategy.run(
/usr/local/lib/python3.6/dist-packages/tensorflow/python/distribute/distribute_lib.py:951 run  **
    return self._extended.call_for_each_replica(fn, args=args, kwargs=kwargs)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/distribute/distribute_lib.py:2290 call_for_each_replica
    return self._call_for_each_replica(fn, args, kwargs)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/distribute/distribute_lib.py:2649 _call_for_each_replica
    return fn(*args, **kwargs)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py:477 train_step  **
    self.compiled_metrics.update_state(y, y_pred, sample_weight)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/compile_utils.py:386 update_state
    self._build(y_pred, y_true)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/compile_utils.py:317 _build
    self._metrics, y_true, y_pred)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/util/nest.py:1118 map_structure_up_to
    **kwargs)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/util/nest.py:1214 map_structure_with_tuple_paths_up_to
    *flat_value_lists)]
/usr/local/lib/python3.6/dist-packages/tensorflow/python/util/nest.py:1213 <listcomp>
    results = [func(*args, **kwargs) for args in zip(flat_path_list,
/usr/local/lib/python3.6/dist-packages/tensorflow/python/util/nest.py:1116 <lambda>
    lambda _, *values: func(*values),  # Discards the path arg.
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/compile_utils.py:416 _get_metric_objects
    return [self._get_metric_object(m, y_t, y_p) for m in metrics]
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/compile_utils.py:416 <listcomp>
    return [self._get_metric_object(m, y_t, y_p) for m in metrics]
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/compile_utils.py:435 _get_metric_object
    metric_obj = metrics_mod.get(metric)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/metrics.py:3364 get
    raise ValueError(error_msg)

ValueError: Could not interpret metric function identifier: 0.7213095426559448
...