ValueError: Tensor("", dtype=float32) is not an element of this graph解决办法Graph设为内部成员并且调用时不设置默认GRAPH

参考:
1. https://github.com/keras-team/keras/issues/2397

今天在把Mask RCNN改成ROS Server来使用的时候,遇到了这个错误,我是根据这个ROS Subscriber版的Mask RCNN的基础上来改的,原代码运行很正常,但是我在改成ROS Node之后出现了这个错误,看了一晚上才意识到,正如参考[1]里有人提到的:

    I had this problem when doing inference in a different thread than where I loaded my model. Here’s how I fixed the problem:

我改完成ROS server之后,load model是在实例化我的调用mask rcnn的类的时候进行的,然而inference是在接收到request的时候才进行,显然不在一个进程里。而那个写成subscriber的版本,他们是在同一个进程里的,subscribe的图片不断的写入一个类成员变量里,这里利用了python多线程中互斥锁确保不会同时读写这个变量,然后就可以让model对当前的图片进行inference了,代码如下:

class MaskRCNNNode(object):
    def __init__(self):
        self._cv_bridge = CvBridge()

        config = InferenceConfig()
        config.display()

        self._visualization = rospy.get_param('~visualization', True)

        # Create model object in inference mode.
        self._model = modellib.MaskRCNN(mode="inference", model_dir="",
                                        config=config)
        # Load weights trained on MS-COCO
        model_path = rospy.get_param('~model_path', COCO_MODEL_PATH)
        # Download COCO trained weights from Releases if needed
        if model_path == COCO_MODEL_PATH and not os.path.exists(COCO_MODEL_PATH):
            utils.download_trained_weights(COCO_MODEL_PATH)

        self._model.load_weights(model_path, by_name=True)

        self._class_names = rospy.get_param('~class_names', CLASS_NAMES)

        self._last_msg = None
        self._msg_lock = threading.Lock()

        self._class_colors = visualize.random_colors(len(CLASS_NAMES))

        self._publish_rate = rospy.get_param('~publish_rate', 100)

    def run(self):
        self._result_pub = rospy.Publisher('~result', Result, queue_size=1)
        vis_pub = rospy.Publisher('~visualization', Image, queue_size=1)
        sub = rospy.Subscriber('~input', Image,
                               self._image_callback, queue_size=1)

        rate = rospy.Rate(self._publish_rate)
        while not rospy.is_shutdown():
            if self._msg_lock.acquire(False):
                msg = self._last_msg
                self._last_msg = None
                self._msg_lock.release()
            else:
                rate.sleep()
                continue

            if msg is not None:
                np_image = self._cv_bridge.imgmsg_to_cv2(msg, 'bgr8')
                # Run detection
                results = self._model.detect([np_image], verbose=0)
                result = results[0]
                result_msg = self._build_result_msg(msg, result)
                self._result_pub.publish(result_msg)

                # Visualize results
                if self._visualization:
                    vis_image = self._visualize(result, np_image)
                    cv_result = np.zeros(shape=vis_image.shape, dtype=np.uint8)
                    cv2.convertScaleAbs(vis_image, cv_result)
                    image_msg = self._cv_bridge.cv2_to_imgmsg(cv_result, 'bgr8')
                    vis_pub.publish(image_msg)

            rate.sleep()

然而我改完之后二者不在同一个进程了,所以按照参考[1]里的方式:

# Right after loading or constructing your model, save the TensorFlow graph:

graph = tf.get_default_graph()

# In the other thread (or perhaps in an asynchronous event handler), do:

global graph
with graph.as_default():
    (... do inference here ...)

对我的代码进行了改动,增加了self.graph这个变量,如下所示:

class MaskRCNNNode(object):
    def __init__(self):
        self._cv_bridge = CvBridge()

        config = InferenceConfig()
        config.display()

        self._visualization = rospy.get_param('~visualization', True)

        # Create model object in inference mode.
        self._model = modellib.MaskRCNN(mode="inference", model_dir="",
                                        config=config)
        # Load weights trained on MS-COCO
        rospack = rospkg.RosPack()
        model_path = rospack.get_path('mask_rcnn_ros')+'/models/mask_rcnn_coco.h5'

        self._model.load_weights(model_path, by_name=True)
        self.graph = tf.get_default_graph()
        self._class_names = rospy.get_param('~class_names', CLASS_NAMES)
        self._class_colors = visualize.random_colors(len(CLASS_NAMES))

        self.vis_pub = rospy.Publisher('~visualization', Image, queue_size=1)
        self.server = rospy.Service('instance_segmentation', InstanceSegmentation, self.handle_instance_segmentation)
        rospy.loginfo("Waiting for request!")

    def handle_instance_segmentation(self, req):
        rospy.loginfo("Request received!")

        np_image = self._cv_bridge.imgmsg_to_cv2(req.color_image, "bgr8")
        # Run detection
        with self.graph.as_default():
            results = self._model.detect([np_image], verbose=0)
        print "got result!"
        result = results[0]
        resp = InstanceSegmentationResponse()
        resp.segmentation_result = self._build_result_msg(req.color_image, result)

        # Visualize results
        if self._visualization:
            vis_image = self._visualize(result, np_image)
            cv_result = np.zeros(shape=vis_image.shape, dtype=np.uint8)
            cv2.convertScaleAbs(vis_image, cv_result)
            image_msg = self._cv_bridge.cv2_to_imgmsg(cv_result, 'bgr8')
            self.vis_pub.publish(image_msg)

        return resp

然后问题就顺利解决了。
 

### 解决方案 `ValueError: Invalid dtype: float32_ref` 的错误通常发生在 TensorFlow 或其他深度学习框架中,当操作的数据类型匹配或者某些张量被意外地指定为 `float32_ref` 类型。这种问题可能是由于旧版本的 TensorFlow 中的一些 API 使用了 `_ref` 后缀来表示可变变量的结果。 以下是可能导致此问题的原因以及解决方案: #### 原因分析 1. **API 更新冲突** 如果使用的 TensorFlow 版本较新,而代码是基于旧版编写的,则可能会遇到此类问题。例如,在 TensorFlow 2.x 中,默认启用了 Eager Execution,这改变了许多函数的行为[^4]。 2. **张量可变性** 在 TensorFlow 中,`_ref` 表示该对象是可以修改的变量。如果尝试对一个可变的对象执行需要 `_ref` 的操作,就会引发上述错误[^1]。 3. **数据类型的显式声明缺失** 某些情况下,未正确设置输入或中间计算结果的数据类型也可能导致类似的错误消息。 --- #### 解决方法 ##### 方法一:升级到最新版本的 TensorFlow 并启用兼容模式 确保安装的是最新稳定版本的 TensorFlow,并考虑切换回图模式(Graph Mode)。可以通过以下命令禁用默认的急切执行(Eager Execution): ```python import tensorflow as tf tf.compat.v1.disable_eager_execution() ``` ##### 方法二:替换过的操作符或函数 检查是否有任何已弃用的功能正在使用。例如,早期版本中的 `K.variable()` 应逐步迁移到更现代的方式定义变量,比如通过 `tf.Variable()` 替代: ```python from tensorflow.keras import backend as K # 过写法 old_var = K.variable(value) # 推荐替代 new_var = tf.Variable(initial_value=value, trainable=True) ``` ##### 方法三:验证并修正所有涉及数值运算的部分 确认所有的数学表达式都指定了适当的数据格式。对于大多数情况来说,应该统一转换成标准浮点数形式——即 `dtype=tf.float32` 而是带有特殊标记的形式如 `float32_ref`。举个例子,假设存在如下片段: ```python box_xy = (K.sigmoid(feats[..., :2]) + grid) / K.cast(grid_shape[..., ::-1], K.dtype(feats)) ``` 这里需特别注意 `grid`, `feats` 和 `input_shape` 是否一致且均为合法数值数组。必要强制转型处理: ```python grid_casted = tf.cast(grid, dtype=tf.float32) feats_casted = tf.cast(feats, dtype=tf.float32) result = (tf.nn.sigmoid(feats_casted[..., :2]) + grid_casted) \ / tf.cast(grid_shape[..., ::-1], dtype=tf.float32)[^1] ``` ##### 方法四:调试工具辅助定位具体位置 利用断言语句排查潜在隐患区域。例如加入临打印日志查看实际传递过来的内容是否符合预期: ```python assert isinstance(box_xy, tf.Tensor), f"Expected Tensor got {type(box_xy)}" print(f"DType check passed! Current DType={box_xy.dtype}") ``` --- ### 总结 综上所述,“Invalid dtype: float32_ref”的根本原因多源于环境配置当或是遗留代码风格所致。建议按照前述步骤逐一排查直至彻底消除异常现象为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值