为分类任务实施 Siamese 网络(ValueError: Layer "model_27" expects 2 input(s), but it received 1 input tensors)

问题描述 投票:0回答:0

我想使用孪生网络对 CIFAR10 数据集进行分类任务。 训练数据包含来自不同类别的 5K 对图像,验证数据包含 10K 单图像。我的任务是获取任何给定图像的“softmax”向量。

我试图实现下面的代码,但由于某些形状和类似问题,我无法适应它。

# Loading CIFAR10 dataset
(x_train, y_train), (x_test, y_test) = cifar10.load_data() # load the data

# Normalize pixel values to be between 0 and 1
x_train, x_test = x_train / 255.0, x_test / 255.0
#Parameters:
num_of_training_pairs=5000
valdation_size=10000
img_shape=(x_train[0].shape)
classes=len(np.unique(y_train))
epochs=100
batch_size=32
# Converting labels to one hot vectors
def to_1_hot(labels):
    return np.eye(10)[labels][:,0,:]

# Creating the new dataset
y_train_one_hot = to_1_hot(y_train)
y_test_one_hot = to_1_hot(y_test)

def create_pairs(num_of_training_pairs):
    with tf.device("/gpu:0"):
        copy_x_train=x_train.copy()
        copy_y_train=y_train_one_hot.copy() #labels in distribution format
        labels=y_train.copy() #pure labels

        x_train_pairs=[]
        y_train_pairs=[]

        category_indeices=[np.where(labels == i)[0] for i in range(0, 10)] #list of all indices per category

        for i in range (0,num_of_training_pairs):
            # ============== element 1 ===========================
            idx1=np.random.choice(len(copy_x_train),1) #randomly select index out of all samples
            x1=copy_x_train[idx1] 
            y1=copy_y_train[idx1] #label in distribution format
            label=np.argmax(y1)

            # ============== element 2 ===========================
            #choose random category other then the category chosen above
            # (so in each pair we will have 2 different categories)
            def choice_excluding(exception):
                lst=range(0,classes)
                possible_choices = [v for v in lst if v != exception]
                return np.random.choice(possible_choices)
            
            c = choice_excluding(label)
            idx2=np.random.choice(category_indeices[c],1)
            x2=copy_x_train[idx2] 
            y2=copy_y_train[idx2] #label in distribution format

            # ============== pair them ===========================

            x_train_pairs.append([x1,x2]) 
            y_train_pairs.append([y1,y2])

    return x_train_pairs, y_train_pairs

# Create train data
x_train_pairs, y_train_pairs=create_pairs(num_of_training_pairs)

# Create validation data
val_images, val_labels=shuffle(x_test,y_test_one_hot, random_state=0)
val_images = val_images[:valdation_size]
val_labels = val_labels[:valdation_size] 

class siamese_model():
    def __init__(self,classes=10,dropout=0.2, stride=2):
        self.classes=classes
        self.dropout=dropout
        self.stride=stride

    def euclidean_distance(vectorA, vectorB):
        # unpack the vectors into separate lists
        # (vectorA, vectorB) = vectors
        # compute the sum of squared distances between the vectors
        sumSquared = K.sum(K.square(vectorA - vectorB), axis=1,
            keepdims=True)
        # return the euclidean distance between the vectors
        return K.sqrt(K.maximum(sumSquared, K.epsilon()))
    
    def euclidean_distance(vectorA,vectorB):
        # unpack the vectors into separate lists
        # (vectorA, vectorB) = vectors
        # compute the sum of squared distances between the vectors
        sumSquared = K.sum(K.square(vectorA - vectorB), axis=1,
            keepdims=True)
        # return the euclidean distance between the vectors
        return K.sqrt(K.maximum(sumSquared, K.epsilon()))
    
    def embedded_network(self,input_shape):
        input = Input (shape=input_shape)
        x = Conv2D(64, 2, strides = self.stride, padding = 'same')(input) #Conv2D(64, 7, strides = 2, padding = 'same')(input) 
        x = MaxPool2D(2, strides = self.stride, padding = 'same')(x)
        x = Dropout(0.3)(x)
        x = Conv2D(64, 2, strides = self.stride, padding = 'same')(x) #originallyy only 1 conv layer of 7*7
        x = MaxPool2D(2, strides = self.stride, padding = 'same')(x)
        x = Dropout(0.3)(x)
        pooledOutput = GlobalAveragePooling2D()(x)
        out = Dense(10, activation = 'sigmoid')(pooledOutput)
        # model = None
        model = Model(input, out)
        output=Model.output
        return model, output
    
    def siamese_network (self,input_shape):
        shape=img_shape
        input1 = Input(input_shape)
        input2 = Input(input_shape)

        print("\n==================================================")
        print("Each one of the individual network:")
        print("==================================================\n")

        base_network1,output  = self.embedded_network(img_shape)
        base_network2,output  = self.embedded_network(img_shape)
        vector1 = base_network1 (input1)
        vector2 = base_network2 (input2)
        base_network1.summary()

        print("\n==================================================")
        print("Siamese Network: ")
        print("==================================================\n")

        #con = tf.keras.layers.concatenate([vector1,vector2], axis=1)
        #output = Dense(classes, activation="sigmoid")(con)
        siamese_net = Model([input1,input2],[vector1 ,vector2])
        siamese_net.summary()
        
        return siamese_net
     

s=siamese_model(classes=classes)
model=s.siamese_network(input_shape=img_shape)

# Compile the model
model.compile(loss=siamese_model.euclidean_distance, optimizer='adam')


# Train the model
history = model.fit( x=[np.array(x_train_pairs)[:,0].squeeze(), np.array(x_train_pairs)[:,0].squeeze()], 
                     y=[np.array(y_train_pairs)[:,0].squeeze(), np.array(y_train_pairs)[:,1].squeeze()],
                    # y_train_pairs, 
                    epochs=epochs, 
                    batch_size=batch_size, 
                    validation_data=(val_images, val_labels))

# Evaluate the model on test data
test_loss = model.evaluate([x_test[:,0], x_test[:,1]], y_test_one_hot, verbose=0)
print(f"Test loss: {test_loss}")

我得到的值错误:ValueError: Layer "model_27" expects 2 input(s), but it received 1 input tensors.收到的输入:[]

我发现这是因为验证数据和训练数据的形状不一样。 如上所述,我的限制是训练数据包含来自不同类别的 5K 对图像,验证数据包含 10K 单个图像。

如何在这些条件下运行 model.fit()?

python keras tensor siamese-network
© www.soinside.com 2019 - 2024. All rights reserved.