A naive approach would indeed be to construct m using nn.ModuleList() and a for loop.
But I think we parallelise the whole lot. The following idea should work, but I haven’t checked all the details.
The input x is shared by all subnetworks, so a single Linear layer of size m*100 followed by separating the result into m parts will work identically to m separate Linear layers of size 100.
self.x_to_z1 = nn.Sequential(
    nn.Linear(x_size, 100*m),
    nn.ReLU(),
)

In forward() we could follow this by .view(batch_size, m, 100) to separate the z^(1,i). Or we could use .view(batch_size, 100, 1) to add a spatial dimension of size 1, and follow up with a grouped convolution.
self.z1_to_z2 = nn.Sequential(
    nn.Conv1d(100*m, 10*m, kernel_size=1, groups=m),
    # the input is grouped into groups of 100 channels, 
    # and each group is used to produce 10 channels of output
    nn.ReLU(),
)

And then another grouped convolution to produce the required number of outputs, i.e. 2 per y^i, if I have understood correctly.
self.z2_to_y = nn.Conv1d(10*m, 2*m, kernel_size=1, groups=m)

And finally you could use .view(batch_size, m, 2) followed by .split(1, dim=1) to split the output into a list of m tensors of size 2. But I suspect you could parallelise the loss function too.