TensorFlow: не реализовано: преобразование строки в float не поддерживается - PullRequest
0 голосов
/ 06 мая 2020

У меня были значительные проблемы с тем, чтобы моя модель TensorFlow действительно работала с моими собственными входными данными.

Я рисую изображения из помеченных каталогов. У меня есть два класса изображений, «хорошие» и «плохие», которые хранятся в их собственных каталогах.

Я читаю их, используя встроенный list_files(glob) TensorFlow, и обрабатываю их строго с помощью TensorFlow. операции. Однако теперь, когда я пытаюсь запустить свою модель, она перестает работать в первую эпоху и выводит код ошибки: tensorflow/core/framework/op_kernel.cc:1730] OP_REQUIRES failed at cast_op.cc:123 : Unimplemented: Cast string to float is not supported

Мой код выглядит следующим образом:

import numpy as np
import matplotlib.pyplot as plt
import pathlib

import tensorflow as tf
from tensorflow.keras import layers, models

import random

import os

class E6Classifier:
    image_size = 256
    train_test_proportion = .8
    current_working_directory = pathlib.Path.cwd()
    data_directory = current_working_directory.parent / 'Jupyter Notebooks' / 'Tensorflow' / 'e6Classifier' / 'data'
    categories = ['good', 'bad']
    good_images = []
    bad_images = []
    batch_size = 32

    total_dataset = None
    train_dataset = None
    test_dataset = None

    def __init__(self):
        self.read_images()
        self.print_statistics()

        #TensorFlow implementation
        self.make_tensorflow_dataset()
        self.train_test_split()
        self.create_model()
        self.train_model()

    def read_images(self):
        good_path = self.data_directory / self.categories[0]
        bad_path = self.data_directory / self.categories[1]
        filetypes = ('*.jpg', '*.png')

        for filetype in filetypes:
            self.good_images.extend(good_path.glob(filetype))
            self.bad_images.extend(bad_path.glob(filetype))

    def print_statistics(self):
        self.num_good_images = len(self.good_images)
        self.num_bad_images = len(self.bad_images)
        self.total_images = self.num_good_images + self.num_bad_images
        self.proportion_good = round(self.num_good_images / self.total_images * 100, 2)

        print(str(self.total_images) + ' total images | ' + str(self.num_good_images) + ' good images, ' + str(self.num_bad_images) + ' bad images | ' + str(self.proportion_good) + ' percent good to bad')

    def make_tensorflow_dataset(self):
        directory_strings = []
        for filetype in ['*.jpg', '*.png']:
            directory_strings.append(str(self.data_directory / 'good' / filetype))
            directory_strings.append(str(self.data_directory / 'bad' / filetype))

        list_dataset = tf.data.Dataset.list_files(directory_strings)

        labeled_dataset = list_dataset.map(self.process_tensor_path)

        self.total_dataset = labeled_dataset

    def process_tensor_path(self, filepath):
        label = tf.strings.split(filepath, os.sep)[-2]

        image = tf.io.read_file(filepath)
        image = tf.image.decode_image(image, channels = 3)
        image = tf.image.convert_image_dtype(image, tf.float32)
        image = tf.image.resize_with_pad(image, target_width = self.image_size, target_height = self.image_size)

        return image, label

    def train_test_split(self):
        num_training_images = int(round(self.total_images * self.train_test_proportion,0))

        self.total_dataset.shuffle(buffer_size = self.total_images)

        self.train_dataset = self.total_dataset.take(num_training_images)
        self.test_dataset = self.total_dataset.skip(num_training_images)

    def create_model(self):
        #Batch datasets
        self.train_dataset = self.train_dataset.batch(self.batch_size, drop_remainder = True)
        self.test_dataset = self.test_dataset.batch(self.batch_size, drop_remainder = True)
        self.total_dataset = self.total_dataset.batch(self.batch_size, drop_remainder = True)

        #Create model
        self.model = models.Sequential()
        #Add a convolutional layer to detect features in the image
        self.model.add(layers.Conv2D(32, (3, 3), activation = 'relu', input_shape = (self.image_size, self.image_size, 3)))
        #Add a pooling layer to remove sensitivity to position in the image of the feature
        self.model.add(layers.MaxPooling2D((2, 2)))
        #Repeat ad nauseum
        self.model.add(layers.Conv2D(64, (3, 3), activation = 'relu'))
        self.model.add(layers.MaxPooling2D(2, 2))
        self.model.add(layers.Conv2D(64, (3, 3), activation = 'relu'))
        self.model.add(layers.MaxPooling2D(2, 2))
        self.model.add(layers.Conv2D(64, (3, 3), activation = 'relu'))
        self.model.add(layers.MaxPooling2D(2, 2))
        self.model.add(layers.Conv2D(64, (3, 3), activation = 'relu'))

        #Add dense layers
        self.model.add(layers.Flatten())
        self.model.add(layers.Dense(64, activation = 'relu'))
        self.model.add(layers.Dense(2))

        #Compile the model for training
        self.model.compile(optimizer = 'adam', loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits = True), metrics = ['accuracy'])

    def train_model(self):
        #self.train_dataset.repeat()
        #self.test_dataset.repeat()

        self.model.fit(self.train_dataset, epochs = 1, validation_data = self.test_dataset, verbose = True)

def main():
    E6Classifier()

if __name__ == '__main__':
    main()

Я не понимаю, что вызывает эту ошибку, и, похоже, нет огромного количества информации о том, где на самом деле происходит сбой вызова. Я просмотрел типы данных моих наборов данных TensorFlow, и они указывают, что они являются кортежами Tensors с типами float32 и string соответственно.

Это проблема, связанная с наличием строк для названий категорий? Если да, то как мне go заменить названия категорий номерами?

1 Ответ

1 голос
/ 06 мая 2020

Вы хотите разделить свои изображения на две категории: хорошие и плохие. Поскольку обучение сети включает в себя вычисление значения потерь (которое является числовым значением), а затем его обратное распространение для обновления весов (также числовых значений), у вас должны быть числовые выходные данные и метки. Преобразуйте свой «хороший» лейбл, например, в. 1, а метка «плохой» - 0. Это можно сделать в тензорном потоке (см. Пример ниже) или в структуре папок (переименуйте папки и соответствующим образом измените код).

string_label = tf.strings.split(filepath, os.sep)[-2]
label = tf.constant(1.) if tf.math.equal(string_label, tf.constant('good', dtype=tf.string)) else tf.constant(0.)
...