Skip to main content
 首页 » 编程设计

python之自定义和预训练模型的集合给出了运行时错误

2024年12月31日40bhlsheji

我正在尝试使用 Keras 和 Tensorflow 后端(TF:1.9.0 和 Keras:2.1.6)为医学图像分类任务创建自定义 CNN 和预训练 VGG16 的集合。代码如下:

#load libraries 
from keras.models import Model, Input 
from keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D, Activation, Average, Dense 
from load_data import load_resized_training_data, load_resized_validation_data 
from load_data import load_resized_test_data 
from keras.losses import categorical_crossentropy 
from keras.callbacks import ModelCheckpoint, TensorBoard 
from keras.optimizers import Adam 
from keras.applications.vgg16 import VGG16 
import numpy as np 
################################################################################ 
#load data 
batch_size = 8 
num_epochs = 1 
img_rows= 224 
img_cols = 224 
num_channels = 3 
num_classes = 2 
 
X_train, Y_train = load_resized_training_data(img_rows, img_cols) 
X_valid, Y_valid = load_resized_validation_data(img_rows, img_cols) 
X_test, Y_test = load_resized_test_data(img_rows, img_cols) 
print(X_train.shape, Y_train.shape, X_valid.shape, Y_valid.shape,X_test.shape, Y_test.shape) 
X_train = X_train.astype('float32') 
X_valid = X_valid.astype('float32') 
X_test = X_test.astype('float32') 
X_train /= 255 
X_valid /= 255 
X_test /= 255  
###############################################################################   
'''Since the two models work with the data of the same shape,  
it makes sense to define a single input layer that will be used by every model.''' 
input_shape = X_train[0,:,:,:].shape 
print(input_shape) # 224, 224, 3 
model_input = Input(shape=input_shape) 
print(model_input) # Tensor("input_1:0", shape=(?, 224, 224, 3), dtype=float32) 
 
############################################################################### 
'''define the first model: a simple sequential model in the form of functional api''' 
 
x = Conv2D(16, kernel_size=(3, 3), activation='relu')(model_input) 
x = MaxPooling2D((2, 2))(x) 
x = Conv2D(32, (3, 3), activation='relu')(x) 
x = MaxPooling2D((2, 2))(x) 
x = Conv2D(64, (3, 3), activation='relu')(x) 
x = MaxPooling2D((2, 2))(x) 
x = Conv2D(128, (3, 3), activation='relu')(x) 
x = MaxPooling2D((2, 2))(x) 
x = Conv2D(256, (3, 3), activation='relu')(x) 
x = MaxPooling2D((2, 2))(x) 
x = Conv2D(512, (3, 3), activation='relu')(x) 
x = Conv2D(2, (1, 1))(x) 
x = GlobalAveragePooling2D()(x) 
x = Activation(activation='softmax')(x) 
 
custom_model = Model(inputs=model_input, outputs=x, name='custom_cnn') 
############################################################################### 
def compile_and_train(model, num_epochs):  
 
    model.compile(loss=categorical_crossentropy, optimizer=Adam(), metrics=['acc'])  
    filepath = 'weights/' + model.name + '.{epoch:02d}-{val_acc:.2f}.hdf5' 
    checkpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_weights_only=True, save_best_only=True, mode='auto', period=1) 
    tensor_board = TensorBoard(log_dir='logs/', histogram_freq=0, batch_size=batch_size) 
    history = model.fit(X_train, Y_train, batch_size=batch_size, epochs=num_epochs, verbose=1, callbacks=[checkpoint, tensor_board], validation_data=(X_valid, Y_valid)) 
    return history 
 
#compile and train the model 
_ = compile_and_train(custom_model, num_epochs=num_epochs) 
############################################################################### 
def evaluate_error(model): 
    pred = model.predict(X_test, batch_size = batch_size) 
    pred = np.argmax(pred, axis=1) 
    pred = np.expand_dims(pred, axis=1) # make same shape as y_test 
    error = np.sum(np.not_equal(pred, Y_test)) / Y_test.shape[0]   
 
    return error 
 
evaluate_error(custom_model) 
############################################################################### 
'''second model is a pretrained vgg16 model initialized with imagenet weights and going to be trained from the first layer''' 
 
vgg16_model = VGG16(weights='imagenet', include_top=False, input_shape=(img_rows, img_cols, 3)) 
x = vgg16_model.output 
x = GlobalAveragePooling2D()(x) 
predictions = Dense(num_classes, activation='softmax')(x) 
vgg16_custom_model = Model(inputs=vgg16_model.input, outputs=predictions, name='vgg16_cnn') 
 
#compile and train the model 
_ = compile_and_train(vgg16_custom_model, num_epochs=num_epochs) 
 
#Evaluate the model by calculating the error on the test set 
evaluate_error(vgg16_custom_model) 
############################################################################### 
custom_model.load_weights('weights/custom_cnn.01-0.60.hdf5') 
vgg16_custom_model.load_weights('weights/vgg16_cnn.01-0.50.hdf5') 
 
models = [custom_model, vgg16_custom_model] 
############################################################################### 
def ensemble(models, model_input): 
 
    outputs = [model.outputs[0] for model in models] 
    y = Average()(outputs) 
 
    model = Model(inputs=model_input, outputs=y, name='ensemble') 
 
    return model 
 
ensemble_model = ensemble(models, model_input) 
evaluate_error(ensemble_model) 
############################################################################### 

在创建整体定义之前,代码工作正常。定义集成时出现以下错误:

RuntimeError: Graph disconnected: cannot obtain value for tensor Tensor("input_7:0", shape=(?, 224, 224, 3), dtype=float32) at layer "input_7". The following previous layers were accessed without issue: [] 

我不确定我是否可以通过这种方式将 model_input 传递给预训练的 VGG16。集成定义需要如何修改?

请您参考如下方法:

问题是 ensemble_model 的输入层没有提供 VGG 模型的输入。要解决此问题,您需要修改 ensemble_model 的定义并创建一个新的输入层,然后将其传递给两个模型:

def ensemble(models): 
    input_img = Input(shape=input_shape) 
 
    outputs = [model(input_img) for model in models] # get the output of model given the input image 
    y = Average()(outputs) 
 
    model = Model(inputs=input_img, outputs=y, name='ensemble') 
    return model 
 
ensemble_model = ensemble(models)