我在尝试使用Keras函数式API构建CNN模型时,每当执行以下这行代码时:model = CNN(settings, np.expand_dims(x_train, axis = 3)).build_network()
都会遇到以下问题:
ValueError: 图形断开:无法为张量 Tensor(“input_11:0”, shape=(?, 28, 28, 1), dtype=float32) 在层 “input_11” 处获取值。之前访问的层没有问题:[]
这是我的代码:
class CNN: def __init__(self, settings, data): self.flag = False self.settings = settings if self.check_network_settings() == False: self.flag = True return self.data = data if K.image_data_format() == "channels_first": self.data = self.data.reshape(data.shape[0], data.shape[3], data.shape[2], data.shape[1]) self.build_network() def show_model_chart(self): if not os.path.isfile('model.png'): plot_model(self.model, to_file = 'model.png') model_pic = cv2.imread('model.png') plt.imshow(model_pic) plt.show() def build_network(self): print('正在构建卷积神经网络 ...') inputs = Input(shape = (self.data.shape[1], self.data.shape[2], self.data.shape[3])) final_output = None for layer_idx in range(self.settings['conv']['layers']): inputs = Conv2D( filters = self.settings['conv']['filters'][layer_idx], kernel_size = self.settings['conv']['kernel_size'][layer_idx], strides = self.settings['conv']['strides'][layer_idx], padding = self.settings['conv']['padding'] )(inputs) if self.settings['pooling']['apply'] == True: inputs = MaxPooling2D( pool_size = self.settings['pooling']['pool_size'][layer_idx], strides = self.settings['pooling']['strides'][layer_idx], padding = self.settings['pooling']['padding'] )(inputs) inputs = Activation( activation = self.settings['detector_stage'][layer_idx] )(inputs) inputs = Flatten()(inputs) for dense_layer_idx in range(self.settings['dense']['layers']): if self.settings['dense']['activations'][dense_layer_idx] != 'softmax': inputs = Dense( units = self.settings['dense']['output_units'][dense_layer_idx], activation = self.settings['dense']['activations'][dense_layer_idx] )(inputs) else: final_output = Dense( units = self.settings['dense']['output_units'][dense_layer_idx], activation = self.settings['dense']['activations'][dense_layer_idx] )(inputs) self.model = Model(inputs = inputs, outputs = final_output) def check_network_settings(self): for key in self.settings: if key == 'conv': if set(self.settings['conv'].keys()) != {'layers', 'filters', 'kernel_size', 'strides', 'padding'}: print('[设置错误]: 卷积层 ...') return False elif key == 'pooling': if set(self.settings['pooling'].keys()) != {'apply', 'pool_size', 'strides', 'padding'}: print('[设置错误]: 池化层 ...') return False if len(self.settings['pooling']['apply']) != self.settings['conv']['layers']: print('请为每个卷积层指定是否应用池化') return False elif key == 'detector_stage': if self.settings['conv']['layers'] != len(self.settings['detector_stage']): print('您指定的激活函数数量与网络中的卷积层数量不匹配 ...') return False elif key == 'dense': if set(self.settings['dense'].keys()) != {'layers', 'output_units', 'activations'}: print('[设置错误]: 全连接层 ...') return False if 'softmax' != self.settings['dense']['activations'][len(self.settings['dense']['activations'])-1]: print('您的网络必须在最后一个全连接层包含Softmax激活函数,以便生成类别概率 ...') return False print('网络设置已正确指定 ...') return True
这是我提供给类构造函数的设置参数:
settings = { 'conv': { 'layers': 3, 'filters': [32, 64, 128], 'kernel_size':[(3,3), (5,5), (5,5)], 'strides': [1, 1, 1], 'padding': 'same', }, 'pooling': { 'apply': [True, True, True], 'pool_size': [(2,2), (3,3), (3,3)], 'strides': [1, 1, 1], 'padding': 'same' }, 'detector_stage': ['relu', 'relu', 'relu'], 'dense': { 'layers': 2, 'output_units': [500, 10], 'activations': ['relu', 'softmax'], }, 'batch_norm': [False, False, False, False]}
回答:
问题在于inputs
变量保存了第一个全连接层的输出张量,而不是实际的输入。