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

能否在tf.keras的Conv2D层中对每个5×5输入补丁执行L1归一化等变换?

在tf.keras中对Conv2D的输入补丁提前做归一化处理

当然可以实现这个需求,核心是先对输入特征图的每个5×5感受野补丁完成L1归一化(或其他自定义变换),再将处理后的特征图送入Conv2D层。下面提供两种实用的实现方案:

方案1:Lambda层实现局部L1归一化(简单直接)

这种方法通过计算每个位置对应5×5补丁的L1范数,将输入特征图除以该范数(加小epsilon避免除零),得到归一化后的特征图,完美适配后续Conv2D的输入要求。

import tensorflow as tf
from tensorflow.keras import layers, Model

def local_l1_norm(inputs, patch_size=5):
    # 计算每个5×5补丁的L1总和
    l1_sum = tf.nn.avg_pool2d(
        tf.abs(inputs),
        ksize=patch_size,
        strides=1,
        padding='SAME'
    ) * (patch_size * patch_size)
    # 归一化操作,防止除零
    return inputs / (l1_sum + 1e-8)

# 构建模型
input_shape = (256, 256, 3)
inputs = layers.Input(shape=input_shape)

# 先对每个5×5补丁做L1归一化
normalized_input = layers.Lambda(local_l1_norm)(inputs)

# 接入原5×5 Conv2D层
x = layers.Conv2D(64, kernel_size=5, padding='same', activation='relu')(normalized_input)

model = Model(inputs=inputs, outputs=x)
model.summary()

如果需要替换成其他变换(比如L2归一化、局部标准化),只需要修改local_l1_norm函数内的计算逻辑即可。

方案2:自定义层实现复杂补丁变换(灵活扩展)

如果需要对补丁做更复杂的自定义操作(比如非线性变换、特征重组),可以自定义Keras层,手动提取补丁、执行变换后重构特征图。

import tensorflow as tf
from tensorflow.keras import layers, Model

class PatchTransformLayer(layers.Layer):
    def __init__(self, patch_size=5, transform_fn=None, **kwargs):
        super().__init__(**kwargs)
        self.patch_size = patch_size
        # 默认使用L1归一化,可传入任意自定义变换函数
        self.transform_fn = transform_fn or self.default_l1_norm

    def default_l1_norm(self, patches):
        # 对每个补丁做L1归一化
        return tf.math.l1_normalize(patches, axis=-1)

    def call(self, inputs):
        batch_size, h, w, channels = tf.shape(inputs)
        # 提取所有5×5补丁
        patches = tf.image.extract_patches(
            images=inputs,
            sizes=[1, self.patch_size, self.patch_size, 1],
            strides=[1, 1, 1, 1],
            rates=[1, 1, 1, 1],
            padding='SAME'
        )
        # 应用自定义变换
        transformed_patches = self.transform_fn(patches)
        # 将变换后的补丁重构为特征图(这里用深度卷积还原通道维度)
        transformed = tf.nn.conv2d_transpose(
            transformed_patches,
            filters=tf.eye(self.patch_size*self.patch_size*channels, channels, dtype=tf.float32)
                .reshape(self.patch_size, self.patch_size, channels, channels),
            output_shape=[batch_size, h, w, channels],
            strides=[1, 1, 1, 1],
            padding='SAME'
        )
        return transformed / (self.patch_size * self.patch_size)  # 还原权重

# 构建模型
input_shape = (256, 256, 3)
inputs = layers.Input(shape=input_shape)

# 自定义补丁变换层(这里用默认的L1归一化)
transformed_input = PatchTransformLayer(patch_size=5)(inputs)

# 接入Conv2D层
x = layers.Conv2D(64, kernel_size=5, padding='same', activation='relu')(transformed_input)

model = Model(inputs=inputs, outputs=x)
model.summary()

这种方式支持任意自定义补丁变换,只需要传入自定义的transform_fn函数即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:33:09