Python 如何将多个输入(四个)合并到神经网络中进行二值图像分类?

Python 如何将多个输入(四个)合并到神经网络中进行二值图像分类?,python,tensorflow,keras,conv-neural-network,Python,Tensorflow,Keras,Conv Neural Network,我将如何构造一个具有四个输入的二值分类神经网络(即,不是输入一个完整图像,而是输入四个大小相等的贴片/贴片,标记为类别1或类别2) 我当前的实现遵循一个简单的二进制类顺序模型,我想将其转换为上面提到的方案 train_generator = train_datagen.flow_from_directory( r'MY\\TRAINING\\PATH', classes = ['Class1', 'Class2'], target_size=(10

我将如何构造一个具有四个输入的二值分类神经网络(即,不是输入一个完整图像,而是输入四个大小相等的贴片/贴片,标记为类别1或类别2)

我当前的实现遵循一个简单的二进制类顺序模型,我想将其转换为上面提到的方案

train_generator = train_datagen.flow_from_directory(
        r'MY\\TRAINING\\PATH',
        classes = ['Class1', 'Class2'],
        target_size=(100, 100), 
        batch_size=16,
        shuffle=False,
        class_mode='binary')

validation_generator = validation_datagen.flow_from_directory(
        r'MY\\VALIDATION\\PATH',
        classes = ['Class1', 'Class2'],
        target_size=(100, 100), 
        batch_size=8,
        # Use binary labels
        shuffle=False,
        class_mode='binary')

model = tf.keras.models.Sequential([
                                    tf.keras.layers.Conv2D(8, (3, 3), activation='relu', input_shape=(100, 100, 3)),
                                    tf.keras.layers.MaxPooling2D((2, 2)),
                                    tf.keras.layers.Conv2D(16, (3, 3), activation='relu'),
                                    tf.keras.layers.MaxPooling2D((2, 2)),
                                    tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),
                                    tf.keras.layers.Flatten(),
                                    tf.keras.layers.Dense(1, activation='sigmoid')
                                    ])

例如,我的数据的文件结构如下所示:

├── training
│   ├── Class1_Quadrant1
│   │   ├── IMG_1.jpg
│   │   ├── IMG_2.jpg
│   │   ├── IMG_3.jpg
│   │   ├── etc.jpg
│   ├── Class1_Quadrant2
│   │   ├── IMG_1.jpg
│   │   ├── IMG_2.jpg
│   │   ├── IMG_3.jpg
│   │   ├── etc.jpg
│   ├── Class1_Quadrant3
│   │   ├── IMG_1.jpg
│   │   ├── IMG_2.jpg
│   │   ├── IMG_3.jpg
│   │   ├── etc.jpg
│   ├── Class1_Quadrant4
│   │   ├── IMG_1.jpg
│   │   ├── IMG_2.jpg
│   │   ├── IMG_3.jpg
│   │   ├── etc.jpg
和我的验证集具有相同的精确结构

理想情况下,如果有帮助,可以使用类似于此图像的内容:

编辑:

# Input Model 1
input1 = Input(shape=(100, 100, 3))
conv11 = Conv2D(32, kernel_size = 4, activation = 'relu')(input1)
pool11 = MaxPooling2D(pool_size = (2, 2))(conv11)
conv12 = Conv2D(16, kernel_size = 4, activation = 'relu')(pool11)
pool12 = MaxPooling2D(pool_size = (2, 2))(conv12)
conv12 = Conv2D(8, kernel_size = 4, activation = 'relu')(pool11)
pool12 = MaxPooling2D(pool_size = (2, 2))(conv12)
flat1 = Flatten()(pool12)
dense1 = Dense(1)(flat1)

# ... same structure repeated up to Input 4


# Merge All Input Models
merge = concatenate([flat1, flat2, flat3, flat4])

# Dense layers
hidden1 = Dense(1, activation = 'relu')(merge)
hidden2 = Dense(1, activation = 'relu')(hidden1)
hidden3 = Dense(1, activation = 'relu')(hidden2)
hidden4 = Dense(1, activation = 'relu')(hidden3)
output = Dense(1, activation = 'sigmoid')(hidden4)
model = Model(inputs = [input1, input2, input3, input4], outputs = output)

# Lastly my data comes from 

train_datagen = ImageDataGenerator(1 / 255.0)
validation_datagen = ImageDataGenerator(1 / 255.0)

train_generator1 = train_datagen.flow_from_directory(
    r'training\\path\\Q1',  
    classes = ['D1', 'D2'],
    target_size = (100, 100),  
    batch_size = 16,
    shuffle = False,
    class_mode = 'binary'
    )

validation_generator1 = validation_datagen.flow_from_directory(
    r'validation\\path\\Q1',  
    classes = ['D1', 'D2'],
    target_size = (100, 100), 
    batch_size = 8,
    shuffle = False,
    class_mode = 'binary'
    )

# this continues on for the 4 training and 4 validation generators
# until I get the error thrown here

model.compile(
    optimizer = tensorflow.optimizers.Adam(learning_rate = 1e-4),
    loss = 'binary_crossentropy',
    metrics = ['accuracy']
    )

history = model.fit(
    [train_generator1, train_generator2, train_generator3, train_generator4],  
    epochs = 100,
    verbose = 1,
    validation_data = [validation_generator1, validation_generator2, validation_generator3, validation_generator4],
    )

回溯:

history = model.fit(
    [train_generator1, train_generator2, train_generator3, train_generator4],  
    epochs = 100,
    verbose = 1,
    validation_data = [validation_generator1, validation_generator2, validation_generator3, validation_generator4],
    )
Traceback (most recent call last):

  File "<ipython-input-23-332d3f7e4bba>", line 5, in <module>
    validation_data = [validation_generator1, validation_generator2, validation_generator3, validation_generator4],

  File "C:\Users\Eitan Flor\anaconda3\lib\site-packages\tensorflow\python\keras\engine\training.py", line 108, in _method_wrapper
    return method(self, *args, **kwargs)

  File "C:\Users\Eitan Flor\anaconda3\lib\site-packages\tensorflow\python\keras\engine\training.py", line 1063, in fit
    steps_per_execution=self._steps_per_execution)

  File "C:\Users\Eitan Flor\anaconda3\lib\site-packages\tensorflow\python\keras\engine\data_adapter.py", line 1104, in __init__
    adapter_cls = select_data_adapter(x, y)

  File "C:\Users\Eitan Flor\anaconda3\lib\site-packages\tensorflow\python\keras\engine\data_adapter.py", line 971, in select_data_adapter
    _type_name(x), _type_name(y)))

ValueError: Failed to find data adapter that can handle input: (<class 'list'> containing values of types {"<class 'tensorflow.python.keras.preprocessing.image.DirectoryIterator'>"}), <class 'NoneType'>
history=model.fit(
[第1列、第2列、第3列、第4列发电机],
纪元=100,
verbose=1,
验证数据=[validation_generator1、validation_generator2、validation_generator3、validation_generator4],
)
回溯(最近一次呼叫最后一次):
文件“”,第5行,在
验证数据=[validation_generator1、validation_generator2、validation_generator3、validation_generator4],
文件“C:\Users\Eitan Flor\anaconda3\lib\site packages\tensorflow\python\keras\engine\training.py”,第108行,在方法包装中
返回方法(self、*args、**kwargs)
文件“C:\Users\Eitan Flor\anaconda3\lib\site packages\tensorflow\python\keras\engine\training.py”,第1063行
每执行一步=自。\每执行一步)
文件“C:\Users\Eitan Flor\anaconda3\lib\site packages\tensorflow\python\keras\engine\data\u adapter.py”,第1104行,在\uu init中__
适配器\u cls=选择数据\u适配器(x,y)
文件“C:\Users\Eitan Flor\anaconda3\lib\site packages\tensorflow\python\keras\engine\data\u adapter.py”,第971行,在select\u data\u adapter中
_类型\名称(x),\类型\名称(y)))
ValueError:找不到可以处理输入的数据适配器:(包含{“”}类型的值),

使用顺序API是不可能的(每个层应该有一个输入):


尝试功能性API:

使用顺序API是不可能的(每一层应该有一个输入):


尝试函数式API:

我怀疑您必须创建一个具有4个输入的模型,每个图像象限一个输入。然后,可以根据需要按层独立处理每个输入。然后展平每个输入流的输出,并将它们连接起来。然后处理连接层输出和一个具有1个节点的密集层。 下面的代码是关于如何生成输入的一种想法。 有一个培训目录,其中包含类的子目录,并将图像放入这些子目录中。下面的示例显示如何从ImageDataGenerator获取图像,并将图像分割为象限

# function below splits an image into 4 quadrants and returns them in imgq
def quad_split (img, width, height):
    mid_width=width//2
    mid_height=height//2
    imgq=[]
    imgq.append(img[0:mid_height, 0:mid_width])
    imgq.append(img[0:mid_height, mid_width:])
    imgq.append(img[mid_height:, 0:mid_width])
    imgq.append(img[mid_height:, mid_width:])
    return imgq
# function below just  displays the 4 quadrants 
def quad_plot(quad):
    fig = plt.figure(figsize=( 10, 10))
    for i in range (4):
        imgn=(quad[i]+1)/2
        fig.add_subplot(2, 2, i+1)
        plt.imshow(imgn)
train_dir=r'c:\temp\people\train' # point this to your training directory
train_gen=ImageDataGenerator(preprocessing_function=tf.keras.applications.mobilenet.preprocess_input, horizontal_flip=True)
train_gen=train_gen.flow_from_directory( train_dir, target_size=(224, 224), batch_size=32, seed=123, )
# you can make similar generators for validation and test data
images, labels=next(train_gen) # fetch the next batch of images and labels
for image in images:
    quads=quad_split (image, 224, 224) # split each image into quadrants
    quad_plot(quads) # just used to display the quadrants of an image

您必须构建一个生成器来创建模型的4个输入,包括标签,但这应该不难实现。祝你好运

我想你必须创建一个有4个输入的模型,每个图像象限一个输入。然后,可以根据需要按层独立处理每个输入。然后展平每个输入流的输出,并将它们连接起来。然后处理连接层输出和一个具有1个节点的密集层。 下面的代码是关于如何生成输入的一种想法。 有一个培训目录,其中包含类的子目录,并将图像放入这些子目录中。下面的示例显示如何从ImageDataGenerator获取图像,并将图像分割为象限

# function below splits an image into 4 quadrants and returns them in imgq
def quad_split (img, width, height):
    mid_width=width//2
    mid_height=height//2
    imgq=[]
    imgq.append(img[0:mid_height, 0:mid_width])
    imgq.append(img[0:mid_height, mid_width:])
    imgq.append(img[mid_height:, 0:mid_width])
    imgq.append(img[mid_height:, mid_width:])
    return imgq
# function below just  displays the 4 quadrants 
def quad_plot(quad):
    fig = plt.figure(figsize=( 10, 10))
    for i in range (4):
        imgn=(quad[i]+1)/2
        fig.add_subplot(2, 2, i+1)
        plt.imshow(imgn)
train_dir=r'c:\temp\people\train' # point this to your training directory
train_gen=ImageDataGenerator(preprocessing_function=tf.keras.applications.mobilenet.preprocess_input, horizontal_flip=True)
train_gen=train_gen.flow_from_directory( train_dir, target_size=(224, 224), batch_size=32, seed=123, )
# you can make similar generators for validation and test data
images, labels=next(train_gen) # fetch the next batch of images and labels
for image in images:
    quads=quad_split (image, 224, 224) # split each image into quadrants
    quad_plot(quads) # just used to display the quadrants of an image

您必须构建一个生成器来创建模型的4个输入,包括标签,但这应该不难实现。祝你好运

谢谢,我继续使用函数式API方法开始转换。我现在一直在训练模型,它抛出“ValueError:无法找到可以处理输入的数据适配器:(包含类型{”“}的值)”,我将在我的原始帖子中添加回溯和更新的代码以供参考。@EitanFlor如何生成标签?这就是我使用数据生成器的原因,例如,如果我检查“train_generator1.labels”,它会生成一个标签数组,如:array([0,0,0,…1,1,1,…])。我最近尝试在model.fit()中输入图像的实际numpy数组(我将其加载到四个临时变量中,而不是直接传递datagen,它解决了这个问题)。我几乎明白了,现在我正试图解决一个大小不匹配的问题:ValueError:layer dense_4的输入0与layer不兼容:输入形状的轴-1的值应为15488,但收到的输入是形状[None,964800]。@EitanFlor请查看。你需要自己调查才行posting@IvanAracki谢谢你的评论。在问题的上下文中,函数API的基本部分是,它可以用来创建带有少量输入的模型。答案中包括了这一点。正如您所看到的,它帮助了Hanks,我继续使用functional API方法开始转换。我现在一直在训练模型,它抛出“ValueError:无法找到可以处理输入的数据适配器:(包含类型{”“}的值)”,我将在我的原始帖子中添加回溯和更新的代码以供参考。@EitanFlor如何生成标签?这就是我使用数据生成器的原因,例如,如果我检查“train_generator1.labels”,它会生成一个标签数组,如:array([0,0,0,…1,1,1,…])。我最近尝试在model.fit()中输入图像的实际numpy数组(我将其加载到四个临时变量中,而不是直接传递datagen,它解决了这个问题)。我几乎明白了,现在我正试图解决一个大小不匹配的问题:ValueError:layer dense_4的输入0与layer不兼容:输入形状的轴-1的值应为15488,但收到的输入是形状[None,964800]。@EitanFlor请查看。你需要自己去调查