You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TensorFlow Lite模型兼容性问题:Feedback Manager与oneDNN算子报错求助

解决MediaPipe手部关键点采集代码中的TensorFlow Lite相关报错

问题说明

运行基于MediaPipe的手部关键点采集Python代码时,遇到两类TensorFlow Lite相关日志提示:

  1. oneDNN自定义算子启用提示:提示浮点运算结果可能因计算顺序的浮点舍入误差产生细微差异
  2. Feedback Manager警告:提示模型需为单签名推理,已自动禁用反馈张量支持

已尝试设置TF_ENABLE_ONEDNN_OPTS=0及配置absl日志,但问题仍存在。


报错信息

2024-07-15 17:11:36.038742: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable TF_ENABLE_ONEDNN_OPTS=0.
2024-07-15 17:11:37.182406: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable TF_ENABLE_ONEDNN_OPTS=0.
INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
W0000 00:00:1721043702.427399   30320 inference_feedback_manager.cc:114] Feedback manager requires a model with a single signature inference. Disabling support for feedback tensors.
W0000 00:00:1721043702.450288   30320 inference_feedback_manager.cc:114] Feedback manager requires a model with a single signature inference. Disabling support for feedback tensors.

运行代码

import cv2
import mediapipe as mp
import csv
import copy
import itertools
import string
from pathlib import Path


mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands


# functions
def calc_landmark_list(image, landmarks):
    image_width, image_height = image.shape[1], image.shape[0]

    landmark_point = []

    # Keypoint
    for _, landmark in enumerate(landmarks.landmark):
        landmark_x = min(int(landmark.x * image_width), image_width - 1)
        landmark_y = min(int(landmark.y * image_height), image_height - 1)
        # landmark_z = landmark.z

        landmark_point.append([landmark_x, landmark_y])

    return landmark_point

def pre_process_landmark(landmark_list):
    temp_landmark_list = copy.deepcopy(landmark_list)

    # Convert to relative coordinates
    base_x, base_y = 0, 0
    for index, landmark_point in enumerate(temp_landmark_list):
        if index == 0:
            base_x, base_y = landmark_point[0], landmark_point[1]

        temp_landmark_list[index][0] = temp_landmark_list[index][0] - base_x
        temp_landmark_list[index][1] = temp_landmark_list[index][1] - base_y

    # Convert to a one-dimensional list
    temp_landmark_list = list(
        itertools.chain.from_iterable(temp_landmark_list))

    # Normalization
    max_value = max(list(map(abs, temp_landmark_list)))

    def normalize_(n):
        return n / max_value

    temp_landmark_list = list(map(normalize_, temp_landmark_list))

    return temp_landmark_list

def logging_csv(letter, landmark_list):
    csv_path = 'keypoint.csv'
    with open(csv_path, 'a', newline="") as f:
        writer = csv.writer(f)
        writer.writerow([letter, *landmark_list])


alphabet = list(string.ascii_uppercase)
alphabet +=  ['1','2','3','4','5','6','7','8','9']
# For static images:
address = 'images/data/'
address = Path() / 'images' / 'data/'

IMAGE_FILES = []
for i in alphabet:
  for j in range(1199):
    filepath = address / str(i) / f'{j}.jpg'
    IMAGE_FILES.append(filepath)

with mp_hands.Hands(
    static_image_mode=True,
    max_num_hands=2,
    min_detection_confidence=0.5) as hands:
    for idx, file in enumerate(IMAGE_FILES):
        # Read an image, flip it around y-axis for correct handedness output (see
        # above).
        image = cv2.flip(cv2.imread(file), 1)
        # Convert the BGR image to RGB before processing.
        results = hands.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))

        # Print handedness and draw hand landmarks on the image.
        # print('Handedness:', results.multi_handedness)
        if not results.multi_hand_landmarks:
            continue
        image_height, image_width, _ = image.shape
        annotated_image = image.copy()
        for hand_landmarks, handedness in zip(results.multi_hand_landmarks,results.multi_handedness):
            landmark_list = calc_landmark_list(annotated_image, hand_landmarks)
            # Conversion to relative coordinates / normalized coordinates
            pre_processed_landmark_list = pre_process_landmark(landmark_list)
            logging_csv(file[12],pre_processed_landmark_list)

已尝试的解决代码

import absl.logging
absl.logging.set_verbosity(absl.logging.INFO)
absl.logging.use_absl_handler()
import os
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'

解决方案

1. 解决oneDNN自定义算子提示

问题出在环境变量设置时机太晚——MediaPipe和TensorFlow在导入时就已经加载了相关模块,后续设置的环境变量不会生效。

修正方法:将环境变量设置放在所有导入语句的最开头:

import os
# 先关闭oneDNN算子
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
# 再导入其他模块
import cv2
import mediapipe as mp
# ... 其余代码保持不变

2. 解决Feedback Manager警告与absl日志提示

Feedback Manager警告是MediaPipe内部TF Lite模型的兼容性问题,不影响功能;absl日志提示是初始化顺序导致的。可以通过调整日志级别屏蔽这些无关输出:

完整前置配置代码:

import os
# 关闭oneDNN算子
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
# 屏蔽TensorFlow的Info和Warning级日志
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# 配置absl日志只输出错误信息
import absl.logging
absl.logging.set_verbosity(absl.logging.ERROR)
absl.logging.use_absl_handler()

# 之后再导入业务模块
import cv2
import mediapipe as mp
# ... 其余代码保持不变

补充说明

这些日志提示本身不会影响代码的功能运行,只是会干扰控制台输出。如果不需要完全屏蔽,也可以保留日志,但调整级别后会让控制台输出更简洁。


内容的提问来源于stack exchange,提问作者Ratnesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 01:00:54