You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在自定义神经网络层中将形状为(None,1)的输出重塑为滑动窗口式时间序列形状

嘿,这个需求其实就是经典的滑动窗口序列重塑问题,完全不用手动写循环折腾,直接用深度学习框架的原生操作就能搞定!我分TensorFlow/Keras和PyTorch两种主流框架给你写好自定义层的实现:

TensorFlow/Keras 自定义层实现

TensorFlow自带tf.signal.frame函数,专门用来生成滑动窗口,非常适合这个场景。自定义层的实现逻辑很清晰:

import tensorflow as tf
from tensorflow.keras.layers import Layer

class SlidingWindowLayer(Layer):
    def __init__(self, window_size=3, step_size=1, **kwargs):
        super().__init__(**kwargs)
        self.window_size = window_size  # 窗口大小,这里是3
        self.step_size = step_size      # 滑动步长,这里是1

    def call(self, inputs):
        # 输入形状是 (序列长度, 1) 或 (批量大小, 序列长度, 1),先去掉最后一维的冗余维度
        inputs_squeezed = tf.squeeze(inputs, axis=-1)
        # 生成滑动窗口,结果形状为 (批量大小, 窗口数量, 窗口大小)(如果是单样本则是(窗口数量, 窗口大小))
        windows = tf.signal.frame(
            inputs_squeezed,
            frame_length=self.window_size,
            frame_step=self.step_size
        )
        return windows

# 测试一下效果
test_input = tf.constant([[1],[2],[3],[4],[5],[6],[7]], dtype=tf.float32)
layer = SlidingWindowLayer()
output = layer(test_input)
print(output.numpy())

代码说明:

  • tf.squeeze把输入从(N,1)转成(N,)的一维序列,方便后续窗口生成
  • tf.signal.frame会自动计算生成的窗口数量:窗口数量 = 序列长度 - 窗口大小 + 步长,这里7-3+1=5,刚好对应你要的5个窗口
  • 支持批量输入,如果你的输入是(batch_size, seq_len, 1),这个层也能直接处理,输出会是(batch_size, num_windows, 3)
PyTorch 自定义层实现

PyTorch里可以用两种方式实现:一种是用unfold(更直观),另一种是用as_strided(更高效,直接创建视图不复制数据)。

方式1:用unfold实现

import torch
import torch.nn as nn

class SlidingWindowLayer(nn.Module):
    def __init__(self, window_size=3, step_size=1):
        super().__init__()
        self.window_size = window_size
        self.step_size = step_size

    def forward(self, inputs):
        # 输入形状是 (序列长度, 1),先调整为unfold需要的三维格式:(1, 1, 序列长度)
        inputs_reshaped = inputs.permute(1, 0).unsqueeze(0)
        # 在最后一维上滑动生成窗口
        windows = inputs_reshaped.unfold(
            dimension=2,
            size=self.window_size,
            step=self.step_size
        )
        # 去掉冗余维度,得到最终形状 (窗口数量, 窗口大小)
        windows = windows.squeeze(0).squeeze(0)
        return windows

# 测试
test_input = torch.tensor([[1],[2],[3],[4],[5],[6],[7]], dtype=torch.float32)
layer = SlidingWindowLayer()
output = layer(test_input)
print(output.numpy())

方式2:用as_strided实现(高效版)

import torch
import torch.nn as nn

class SlidingWindowLayer(nn.Module):
    def __init__(self, window_size=3, step_size=1):
        super().__init__()
        self.window_size = window_size
        self.step_size = step_size

    def forward(self, inputs):
        # 输入形状 (序列长度,1),转成一维序列
        inputs_squeezed = inputs.squeeze(-1)
        seq_len = inputs_squeezed.size(0)
        num_windows = seq_len - self.window_size + self.step_size
        
        # 边界判断:如果序列长度小于窗口大小,返回空张量或抛出提示
        if num_windows <= 0:
            return torch.empty(0, self.window_size, dtype=inputs.dtype)
        
        # 直接创建滑动窗口视图,不复制数据,效率极高
        windows = inputs_squeezed.as_strided(
            size=(num_windows, self.window_size),
            stride=(inputs_squeezed.stride(0), inputs_squeezed.stride(0))
        )
        return windows

代码说明:

  • unfold是PyTorch专门用于滑动窗口采样的API,原本针对图像,但调整维度后也能处理一维序列
  • as_strided直接操作张量的内存布局,生成视图而非复制数据,适合对性能要求高的场景,但要注意边界判断,避免越界

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

火山引擎 最新活动