Skip to content

pytorch Issue: SequentialImpl and AnyModule do not support custom user-defined Modules inherited from Module (JVM crash / compilation failure) and ModuleDict need mapping Insert method #1779

Description

@mullerhai

Library: javacpp-presets/pytorch
Version: (Please fill in your used version)
Related C++ Library: LibTorch (fully supports this feature)
Related Python Library: PyTorch (fully supports this feature)
Problem Description
There are two critical functional defects in SequentialImpl and AnyModule when using custom user-defined layers that inherit from Module in Java, which are fully supported in both C++ LibTorch and Python PyTorch, but broken in JavaCPP PyTorch:

  1. SequentialImpl lacks native support for inserting custom Module subclasses
    The C++ LibTorch SequentialImpl provides a variadic template constructor and push_back method that directly accepts any module derived from torch::nn::Module (including custom layers):
运行
// C++ LibTorch (fully supported)
template <typename... Modules>
explicit SequentialImpl(Modules&&... modules) {
    modules_.reserve(sizeof...(Modules));
    push_back(std::forward<Modules>(modules)...);
}
void push_back(Module module);
#include <torch/torch.h>
#include <iostream>

// 1. 自定义层:必须继承 torch::nn::Module
struct MyCustomLayerImpl : torch::nn::Module {
    // 核心:实现 forward 函数
    torch::Tensor forward(torch::Tensor x) {
        x = torch::relu(x);            // ReLU 激活
        x = x / (torch::max(x) + 1e-8f); // 归一化
        return x;
    }
};

// LibTorch 固定用法:创建模块智能指针
TORCH_MODULE(MyCustomLayer);

int main() {
    // 2. 直接把自定义层插入 Sequential!
    auto model = torch::nn::Sequential(
        torch::nn::Linear(10, 20),
        MyCustomLayer(),  // 自定义层
        torch::nn::Linear(20, 5)
    );

    // 测试
    torch::Tensor x = torch::randn({2, 10});
    torch::Tensor out = model->forward(x);
    std::cout << "输出形状: " << out.sizes() << std::endl;
    return 0;
}
# 自定义 Layer:必须继承 nn.Module
class MyCustomLayer(nn.Module):
    def __init__(self):
        super().__init__()  # 必须调用父类初始化

    # 必须实现 forward
    def forward(self, x):
        x = torch.relu(x)
        x = x / (torch.max(x) + 1e-8)  # 归一化
        return x

# 直接插入 Sequential!
model = nn.Sequential(
    nn.Linear(10, 20),
    MyCustomLayer(),  # 自定义层
    nn.Linear(20, 5)
)

# 测试
x = torch.randn(2, 10)
out = model(x)
print(out.shape)  # torch.Size([2, 5])

The Python PyTorch nn.Sequential also directly accepts custom nn.Module subclasses.
JavaCPP PyTorch:
SequentialImpl does not have a push_back(Module module) native method that directly accepts base Module type.
Cannot compile when directly adding a custom Module (e.g., seq.push_back(new Dice()) → compilation error).

  1. AnyModule wrapper causes JVM crash at runtime for custom ModulesAs a workaround, users wrap custom modules with AnyModule (compiles successfully), but this causes an immediate JVM crash at runtime:java运行// Compiles, but JVM CRASH at runtimeseq.push_back(new AnyModule(new Dice()));This works perfectly for built-in modules (e.g., LinearImpl, ReLUImpl), but fails catastrophically for user-defined Module subclasses.
    Reproducible Code Example
  2. Custom Module (inherits from Module)
运行
import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.pytorch.Module;
import org.bytedeco.pytorch.Tensor;
import static org.bytedeco.pytorch.global.torch.*;

// Custom layer inheriting from base Module (identical pattern to C++/Python)
public class Dice extends Module {
    private double epsilon;
    private Tensor alpha;

    public Dice(double epsilon) {
        super("Dice");
        this.epsilon = epsilon;
        this.alpha = register_parameter("alpha", randn(new long[]{1}));
    }

    public Dice() {
        this(1e-3);
    }

    public Tensor forward(Tensor x) {
        Tensor avg = x.mean(1).unsqueeze(1);
        Tensor diff = x.sub(avg);
        Tensor sq = diff.mul(diff);
        Tensor var = sq.sum(1).unsqueeze(1);
        var = var.add(tensor(new DoublePointer(epsilon)));
        Tensor ps = x.sub(avg).div(sqrt(var));
        ps = sigmoid(ps);
        Tensor part1 = ps.mul(x);
        Tensor part2 = ones_like(ps).mul(alpha).mul(ones_like(ps).sub(ps)).mul(x);
        return part1.add(part2);
    }
}
  1. Test Code with Sequential
运行
import org.bytedeco.pytorch.AnyModule;
import org.bytedeco.pytorch.LinearImpl;
import org.bytedeco.pytorch.ReLUImpl;
import org.bytedeco.pytorch.SequentialImpl;

public class SequentialTest {
    public static void main(String[] args) {
        SequentialImpl seq = new SequentialImpl();

        // Built-in modules work fine
        seq.push_back(new AnyModule(new LinearImpl(128, 64)));
        ReLUImpl actModule = ActivationFactory.relu();
        seq.push_back(new AnyModule(actModule));

        // 1. DIRECT INSERT: Compilation FAILED
        // seq.push_back(new Dice());

        // 2. AnyModule WRAPPER: Compiles OK, but JVM CRASHES at runtime
        seq.push_back(new AnyModule(new Dice()));
    }
}

Expected Behavior
Consistent with C++ LibTorch and Python PyTorch:
SequentialImpl should expose a native method:

运行
public native void push_back(@ByVal Module module);

Allowing direct insertion of any custom subclass of Module without wrappers.
AnyModule should safely wrap and hold custom Module subclasses without JVM crashes.
Custom Module implementations should work identically to built-in modules inside Sequential.
Current Status
Direct insertion → Compilation error
AnyModule wrapper → Runtime JVM crash
C++/Python counterparts → Fully functional
This is a core functionality gap that blocks using custom neural network layers in JavaCPP PyTorch.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions