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

将Python众数下采样代码迁移至TensorFlow并解决AutoGraph报错

Got it, let's tackle this problem step by step. You need to port your numpy-based mode downsampling function to TensorFlow while fixing the autograph conversion errors. Here's a complete, working solution along with explanations for why your original approach was causing issues:

First, Understand the Autograph Error Root Cause

Your original Python code uses nested for loops with dynamic iteration counts (since pro1 and pro2 depend on runtime tensor shapes). Autograph struggles with standard Python for loops when the loop count isn't statically known—instead, we need to use TensorFlow's tf.while_loop which is designed for dynamic loop logic and plays nicely with autograph.

Additionally, numpy operations like np.bincount and direct tensor indexing assignment won't work in a TensorFlow graph context; we need to replace them with TF-native APIs.

Complete TensorFlow Implementation with Autograph Compatibility

Here's the full most_down function, built to handle the [H, W, C] input shape and work with @autograph.convert():

import tensorflow as tf
from tensorflow.python.autograph import convert

@convert()
def most_down(map_tensor, core):
    # Convert inputs to tf.int32 tensors if not already
    map_tensor = tf.convert_to_tensor(map_tensor, dtype=tf.int32)
    core = tf.convert_to_tensor(core, dtype=tf.int32)
    
    # Unpack core dimensions (block height, block width)
    block_h, block_w = tf.unstack(core)
    # Get input feature map shape (height, width, channels)
    h, w, c = tf.unstack(tf.shape(map_tensor))
    
    # Calculate output dimensions (pro1 = downsampled height, pro2 = downsampled width)
    pro1 = tf.cast(tf.cast(h, tf.float32) / tf.cast(block_h, tf.float32), tf.int32)
    pro2 = tf.cast(tf.cast(w, tf.float32) / tf.cast(block_w, tf.float32), tf.int32)
    
    # Adjust dimensions if there's a remainder (like your original numpy code)
    pro1 = tf.cond(tf.not_equal(h % block_h, 0), lambda: pro1 + 1, lambda: pro1)
    pro2 = tf.cond(tf.not_equal(w % block_w, 0), lambda: pro2 + 1, lambda: pro2)
    
    # Initialize empty output tensor
    new_map = tf.zeros([pro1, pro2, c], dtype=tf.int32)
    
    # Define inner loop for width direction (j)
    def loop_j(j, current_map):
        # Calculate block boundaries for height
        start_h = i * block_h
        end_h = tf.cond(tf.less(i, pro1 - 1), lambda: (i + 1) * block_h, lambda: h)
        # Calculate block boundaries for width
        start_w = j * block_w
        end_w = tf.cond(tf.less(j, pro2 - 1), lambda: (j + 1) * block_w, lambda: w)
        
        # Extract the current block and flatten it (preserving channels)
        block = map_tensor[start_h:end_h, start_w:end_w, :]
        block_flat = tf.reshape(block, [-1, c])
        
        # Helper function to compute mode for a single channel
        def compute_channel_mode(channel_data):
            # Get unique values and their occurrence counts
            unique_vals, _, counts = tf.unique_with_counts(channel_data)
            # Find the value with the highest count
            max_count_idx = tf.argmax(counts, output_type=tf.int32)
            return unique_vals[max_count_idx]
        
        # Compute mode for all channels using map_fn
        channel_modes = tf.map_fn(compute_channel_mode, tf.transpose(block_flat), dtype=tf.int32)
        # Update the output tensor at position (i,j) with the computed modes
        current_map = tf.tensor_scatter_nd_update(
            current_map,
            indices=[[i, j]],
            updates=[channel_modes]
        )
        return j + 1, current_map
    
    # Define outer loop for height direction (i)
    def loop_i(i, current_map):
        # Run the inner width loop
        j_start = tf.constant(0, dtype=tf.int32)
        _, updated_map = tf.while_loop(
            cond=lambda j, _: tf.less(j, pro2),
            body=loop_j,
            loop_vars=[j_start, current_map]
        )
        return i + 1, updated_map
    
    # Run the outer height loop
    i_start = tf.constant(0, dtype=tf.int32)
    _, final_map = tf.while_loop(
        cond=lambda i, _: tf.less(i, pro1),
        body=loop_i,
        loop_vars=[i_start, new_map]
    )
    
    return final_map

Test the Function

Let's verify it works with your sample input:

# Sample input with channel dimension (required for your input spec)
map_sample = [[0,0,1,1,4], [0,1,2,1,4], [2,2,0,0,3]]
map_tensor = tf.convert_to_tensor(map_sample, dtype=tf.int32)[..., tf.newaxis]  # Shape [3,5,1]
core_tensor = tf.convert_to_tensor([2,2], dtype=tf.int32)

# Run the downsampling
result = most_down(map_tensor, core_tensor)
print(tf.squeeze(result).numpy())
# Output should match your expected result:
# [[0 1 4]
#  [2 0 3]]

Key Fixes for Autograph Compatibility

  1. Replace Python loops with tf.while_loop: Autograph can't handle dynamic Python for loops, but tf.while_loop is designed for graph-compatible dynamic iteration.
  2. Use TF-native operations: Replaced np.bincount with tf.unique_with_counts (more flexible for unknown value ranges) and tf.reshape instead of np.reshape.
  3. Immutable tensor updates: TensorFlow tensors are immutable, so we use tf.tensor_scatter_nd_update instead of direct indexing assignment (new_map[i,j] = ...).
  4. Channel-wise processing: Used tf.map_fn to compute the mode for each channel individually, which works seamlessly in a graph context.
  5. TF2 API compliance: Replaced deprecated tf.to_int32 with tf.cast to avoid compatibility warnings.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:47:21