如何解决Keras中‘Graph disconnected:无法获取张量值’错误?
Pix2Pix模型构建中Graph disconnected错误的解决方法
问题描述
运行Pix2Pix模型时出现如下错误:
ValueError: Graph disconnected: cannot obtain value for tensor Tensor("input_1:0", shape=(None, 256, 256, 3), dtype=float32) at layer "conv2d". The following previous layers were accessed without issue: []
报错栈跟踪信息:
Traceback (most recent call last): File "C:/Users/sanjay.g/PycharmProjects/Rethinking_Net/MIMO_Model2.py", line 99, in <module> gan = Pix2Pix() File "C:/Users/sanjay.g/PycharmProjects/Rethinking_Net/MIMO_Model2.py", line 21, in __init__ self.generator = self.build_generator File "C:/Users/sanjay.g/PycharmProjects/Rethinking_Net/MIMO_Model2.py", line 97, in build_generator return Model(b3, S3) File "C:\Users\sanjay.g\Miniconda3\envs\pythonProject1\lib\site-packages\tensorflow\python\keras\engine\training.py", line 242, in __new__ return functional.Functional(*args, **kwargs) File "C:\Users\sanjay.g\Miniconda3\envs\pythonProject1\lib\site-packages\tensorflow\python\training\tracking\base.py", line 457, in _method_wrapper result = method(self, *args, **kwargs) File "C:\Users\sanjay.g\Miniconda3\envs\pythonProject1\lib\site-packages\tensorflow\python\keras\engine\functional.py", line 115, in __init__ self._init_graph_network(inputs, outputs) File "C:\Users\sanjay.g\Miniconda3\envs\pythonProject1\lib\site-packages\tensorflow\python\training\tracking\base.py", line 457, in _method_wrapper result = method(self, *args, **kwargs) File "C:\Users\sanjay.g\Miniconda3\envs\pythonProject1\lib\site-packages\tensorflow\python\keras\engine\functional.py", line 190, in _init_graph_network nodes, nodes_by_depth, layers, _ = _map_graph_network( File "C:\Users\sanjay.g\Miniconda3\envs\pythonProject1\lib\site-packages\tensorflow\python\keras\engine\functional.py", line 926, in _map_graph_network raise ValueError('Graph disconnected: ' ValueError: Graph disconnected: cannot obtain value for tensor Tensor("input_1:0", shape=(None, 256, 256, 3), dtype=float32) at layer "conv2d". The following previous layers were accessed without issue: []
模型代码:
from __future__ import print_function, division import tensorflow as tf from tensorflow.keras.layers import Input, Dense, Reshape, Flatten, Dropout, Concatenate from tensorflow.keras.layers import BatchNormalization, Activation, ZeroPadding2D from tensorflow.keras.models import Sequential, Model from data_loader import DataLoader from tensorflow.keras.layers import Conv2D, LeakyReLU, UpSampling2D, ReLU, Conv2DTranspose class Pix2Pix(): def __init__(self): # Input shape self.img_rows = 256 self.img_cols = 256 self.channels = 3 self.img_shape = (self.img_rows, self.img_cols, self.channels) self.dataset_name = 'nayadata' self.data_loader = DataLoader(dataset_name=self.dataset_name, img_res=(self.img_rows, self.img_cols)) self.gf = 32 self.df = 32 self.generator = self.build_generator img_A = Input(shape=self.img_shape) img_B = Input(shape=self.img_shape) fake_A = self.generator(img_B) self.combined = Model(inputs=[img_A, img_B], outputs=[fake_A]) @property def build_generator(self): def convolutionLayer(layer_input, filters, kernel_size=3, stride=1, relu=True, bn=False, tran=False, bias=True): if bn and bias: bias = False if tran: d = Conv2DTranspose(filters, kernel_size=kernel_size, strides=stride, padding='same', use_bias=bias)(layer_input) else: d = Conv2D(filters, kernel_size=kernel_size, strides=stride, padding='same', use_bias=bias)(layer_input) if relu: d = ReLU()(d) if bn: d = BatchNormalization()(d) return d def residualBlocks(layer_input, filters, kernel_size=3, stride=1): d = convolutionLayer(layer_input, filters, kernel_size=kernel_size, stride=stride, relu=True) d = convolutionLayer(d, filters, kernel_size=kernel_size, stride=stride, relu=False) return d def SCM_Block(layer_input, filters, kernel_size=3, stride=1, relu=True, bn=False, tran=False, bias=True): d = convolutionLayer(layer_input, filters, kernel_size=kernel_size, stride=stride, relu=True) d = convolutionLayer(d, filters, kernel_size=kernel_size - 2, stride=stride, relu=True) d = convolutionLayer(d, filters, kernel_size=kernel_size, stride=stride, relu=True) d = convolutionLayer(d, filters, kernel_size=kernel_size - 2, stride=stride, relu=True) return d def eBlock(layer_input, filters, num_res=8): e = layer_input for num1 in range(num_res): e = residualBlocks(e, filters, kernel_size=3, stride=1) return e def dBlock(layer_input, filters, num_res=8): d = layer_input for num1 in range(num_res): d = residualBlocks(d, filters, kernel_size=3, stride=1) return d # Input Image b1 = Input(shape=self.img_shape) b2 = tf.image.resize(b1, [128, 128]) b3 = tf.image.resize(b2, [64, 64]) print(b3.shape) # Downsampling d1 = eBlock(b1, self.gf) #print(d1.shape) d1 = Conv2D(self.gf, kernel_size=3, strides=2, padding='same')(d1) #print(d1.shape) b_scm1 = SCM_Block(b2, self.gf) #print(b_scm1.shape) d2 = Concatenate()([b_scm1, d1]) #print(d2.shape) d2 = eBlock(d2, self.gf*2) #print(d2.shape) d2 = Conv2D(self.gf*2, kernel_size=3, strides=2, padding='same')(d2) #print(d2.shape) b_scm2 = SCM_Block(b3, self.gf*2) #print(b_scm2.shape) d3 = Concatenate()([b_scm2, d2]) #print(d3.shape) d3 = eBlock(d3, self.gf * 4) print(d3.shape) # # Upsampling u3 = dBlock(d3, self.gf * 4) print(u3.shape) S3 = Conv2D(3, kernel_size=3, strides=1, padding='same')(u3) print(S3.shape) return Model(b3, S3) if __name__ == '__main__': gan = Pix2Pix() gan.train(epochs=201, batch_size=4, sample_interval=50)
错误原因及解决方法
核心问题
生成器输入输出链路断裂:生成器的计算逻辑从
b1(256x256输入)开始,但最终返回的模型却把b3(64x64下采样图)作为输入。Keras无法建立b3到输出S3的完整连接——因为S3依赖的所有上游张量最终都追溯到b1,而b1没有被纳入模型输入,导致计算图断开。build_generator定义错误:使用
@property装饰器后,self.build_generator返回的是函数本身,而非构建好的模型实例。后续调用self.generator(img_B)时,函数内部自行创建的b1和外部传入的img_B完全无关,进一步加剧了图断开问题。
修复步骤
1. 修正生成器的输入
将生成器的输入改为原始的b1,确保计算链路完整:
# 原代码 return Model(b3, S3) # 修改为 return Model(b1, S3)
2. 移除@property装饰器,将build_generator改为普通方法
删除@property,让build_generator成为可调用的方法:
# 原代码 @property def build_generator(self): # 修改为 def build_generator(self):
同时在__init__中调用方法构建生成器:
# 原代码 self.generator = self.build_generator # 修改为 self.generator = self.build_generator()
3. 让生成器接受外部传入的输入张量
如果需要生成器使用外部的img_B作为输入,调整build_generator结构,让它接受输入张量参数:
def build_generator(self, input_tensor): # 移除内部的b1 = Input(shape=self.img_shape) b1 = input_tensor b2 = tf.image.resize(b1, [128, 128]) b3 = tf.image.resize(b2, [64, 64]) # 其余计算逻辑保持不变 # ... return Model(input_tensor, S3)
然后在__init__中调用:
img_B = Input(shape=self.img_shape) self.generator = self.build_generator(img_B) fake_A = self.generator(img_B)
完整修正后的关键代码片段
class Pix2Pix(): def __init__(self): # 其他初始化代码不变 self.gf = 32 self.df = 32 img_A = Input(shape=self.img_shape) img_B = Input(shape=self.img_shape) # 传入img_B构建生成器 self.generator = self.build_generator(img_B) fake_A = self.generator(img_B) self.combined = Model(inputs=[img_A, img_B], outputs=[fake_A]) def build_generator(self, input_tensor): # 内部辅助函数保持不变 def convolutionLayer(layer_input, filters, kernel_size=3, stride=1, relu=True, bn=False, tran=False, bias=True): if bn and bias: bias = False if tran: d = Conv2DTranspose(filters, kernel_size=kernel_size, strides=stride, padding='same', use_bias=bias)(layer_input) else: d = Conv2D(filters, kernel_size=kernel_size, strides=stride, padding='same', use_bias=bias)(layer_input) if relu: d = ReLU()(d) if bn: d = BatchNormalization()(d) return d def residualBlocks(layer_input, filters, kernel_size=3, stride=1): d = convolutionLayer(layer_input, filters, kernel_size=kernel_size, stride=stride, relu=True) d = convolutionLayer(d, filters, kernel_size=kernel_size, stride=stride, relu=False) return d def SCM_Block(layer_input, filters, kernel_size=3, stride=1, relu=True, bn=False, tran=False, bias=True): d = convolutionLayer(layer_input, filters, kernel_size=kernel_size, stride=stride, relu=True) d = convolutionLayer(d, filters, kernel_size=kernel_size - 2, stride=stride, relu=True) d = convolutionLayer(d, filters, kernel_size=kernel_size, stride=stride, relu=True) d = convolutionLayer(d, filters, kernel_size=kernel_size - 2, stride=stride, relu=True) return d def eBlock(layer_input, filters, num_res=8): e = layer_input for num1 in range(num_res): e = residualBlocks(e, filters, kernel_size=3, stride=1) return e def dBlock(layer_input, filters, num_res=8): d = layer_input for num1 in range(num_res): d = residualBlocks(d, filters, kernel_size=3, stride=1) return d # 使用外部传入的输入张量 b1 = input_tensor b2 = tf.image.resize(b1, [128, 128]) b3 = tf.image.resize(b2, [64, 64]) # 后续计算逻辑不变 d1 = eBlock(b1, self.gf) d1 = Conv2D(self.gf, kernel_size=3, strides=2, padding='same')(d1) b_scm1 = SCM_Block(b2, self.gf) d2 = Concatenate()([b_scm1, d1]) d2 = eBlock(d2, self.gf*2) d2 = Conv2D(self.gf*2, kernel_size=3, strides=2, padding='same')(d2) b_scm2 = SCM_Block(b3, self.gf*2) d3 = Concatenate()([b_scm2, d2]) d3 = eBlock(d3, self.gf * 4) u3 = dBlock(d3, self.gf * 4) S3 = Conv2D(3, kernel_size=3, strides=1, padding='same')(u3) # 返回以外部输入为起点的模型 return Model(input_tensor, S3)
额外注意事项
- 确保所有张量操作都在连续的计算链路中,避免出现孤立的张量节点。
- 检查生成器输出尺寸是否与输入一致,符合Pix2Pix的任务要求。
内容的提问来源于stack exchange,提问作者Sanjay Kumar Gupta Res Scholar
相关产品推荐
相关产品推荐

