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

如何将Casadi MX变量用于PyTorch nn.Conv1d卷积操作?

解决方案:Casadi集成含Conv1d的神经网络做MPC

方案1:手动在Casadi中实现Conv1d逻辑

卷积操作的本质是滑动窗口内的加权求和加偏置,可以直接用Casadi的原生操作复现,步骤如下:

  • 从PyTorch的Conv1d层中提取训练好的权重和偏置:
    import torch
    import casadi as cs
    
    # 假设你的Conv1d层是conv_layer
    conv_layer = torch.nn.Conv1d(in_channels=3, out_channels=2, kernel_size=2, stride=1, padding=0)
    # 提取权重(形状:out_channels × in_channels × kernel_size)
    weight_np = conv_layer.weight.detach().numpy()
    # 提取偏置(形状:out_channels)
    bias_np = conv_layer.bias.detach().numpy()
    
  • 将参数转为Casadi的MX常量:
    weight_cs = cs.MX(weight_np)
    bias_cs = cs.MX(bias_np)
    
  • 实现卷积计算逻辑(以输入为x_cs,形状为(in_channels, seq_len)为例):
    def casadi_conv1d(x, weight, bias, stride=1):
        in_channels, seq_len = x.shape
        out_channels, _, kernel_size = weight.shape
        out_seq_len = (seq_len - kernel_size) // stride + 1
        output = []
        for out_idx in range(out_channels):
            channel_output = []
            for pos in range(0, seq_len - kernel_size + 1, stride):
                # 取当前窗口的输入
                window = x[:, pos:pos+kernel_size]
                # 加权求和
                val = cs.sum1(weight[out_idx, :, :] * window) + bias[out_idx]
                channel_output.append(val)
            output.append(cs.vertcat(*channel_output))
        return cs.horzcat(*output)
    
  • 替换原Sequential中的Conv1d层为上述Casadi实现即可,确保整个模型的计算都基于Casadi MX变量。

方案2:将Conv1d等价转换为全连接层(输入序列长度固定时适用)

如果MPC中输入的状态序列长度是固定值,可以把卷积层展开成等价的全连接层,直接用l4casadi处理:

  • 假设输入序列长度为L,Conv1d的kernel_size=K,stride=1,padding=0,每个输出神经元对应输入中连续的K个元素。
  • 把Conv1d的权重矩阵(out_channels, in_channels, K)重排为全连接层的权重(out_channels*(L-K+1), in_channels*L),对应每个输出位置的窗口权重。
  • 代码示例:
    import torch.nn as nn
    import numpy as np
    
    def conv_to_linear(conv_layer, input_seq_len):
        out_channels, in_channels, kernel_size = conv_layer.weight.shape
        out_seq_len = input_seq_len - kernel_size + 1
        # 初始化全连接层
        linear_layer = nn.Linear(in_channels * input_seq_len, out_channels * out_seq_len)
        # 重排权重
        weight_np = conv_layer.weight.detach().numpy()
        new_weight = np.zeros((out_channels * out_seq_len, in_channels * input_seq_len))
        for out_c in range(out_channels):
            for seq_pos in range(out_seq_len):
                row_idx = out_c * out_seq_len + seq_pos
                for in_c in range(in_channels):
                    col_start = in_c * input_seq_len + seq_pos
                    new_weight[row_idx, col_start:col_start+kernel_size] = weight_np[out_c, in_c, :]
        # 赋值权重和偏置
        linear_layer.weight.data = torch.tensor(new_weight, dtype=torch.float32)
        linear_layer.bias.data = conv_layer.bias.repeat(out_seq_len)
        return linear_layer
    
  • 转换后,用l4casadi将全连接层转为Casadi兼容的函数,注意输入要先展平为一维向量。

方案3:Casadi自定义操作封装(仅前向预测场景适用)

如果MPC只需要神经网络的前向预测,不需要对网络参数求导,可以用Casadi的自定义操作封装PyTorch的前向传播:

def torch_forward(x_np):
    x_tensor = torch.tensor(x_np, dtype=torch.float32).unsqueeze(0)  # 增加batch维度
    with torch.no_grad():
        return your_sequential_model(x_tensor).squeeze(0).numpy()

# 封装为Casadi函数
casadi_nn = cs.Function('nn', [cs.MX.sym('x', in_channels*seq_len)], [cs.MX(torch_forward(cs.MX.sym('x', in_channels*seq_len)))])
  • 注意:该方法无法自动计算关于输入的梯度,若MPC需要对神经网络的输入(状态/控制量)求导,此方法不适用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 19:23:10