def concatenate_lists(*layers, **kwargs):  
if not layers:<EOL><INDENT>return noop()<EOL><DEDENT>drop_factor = kwargs.get("<STR_LIT>", <NUM_LIT:1.0>)<EOL>ops = layers[<NUM_LIT:0>].ops<EOL>layers = [chain(layer, flatten) for layer in layers]<EOL>concat = concatenate(*layers)<EOL>def concatenate_lists_fwd(Xs, drop=<NUM_LIT:0.0>):<EOL><INDENT>drop *= drop_factor<EOL>lengths = ops.asarray([len(X) for X in Xs], dtype="<STR_LIT:i>")<EOL>flat_y, bp_flat_y = concat.begin_update(Xs, drop=drop)<EOL>ys = ops.unflatten(flat_y, lengths)<EOL>def concatenate_lists_bwd(d_ys, sgd=None):<EOL><INDENT>return bp_flat_y(ops.flatten(d_ys), sgd=sgd)<EOL><DEDENT>return ys, concatenate_lists_bwd<EOL><DEDENT>model = wrap(concatenate_lists_fwd, concat)<EOL>return model<EOL>
Compose two or more models `f`, `g`, etc, such that their outputs are
    concatenated, i.e. `concatenate(f, g)(x)` computes `hstack(f(x), g(x))`