我想使用孪生网络对 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()?