LinearCombination: higher-dimension capable LLVM implementation#3533
LinearCombination: higher-dimension capable LLVM implementation#3533kmantel wants to merge 1 commit into
Conversation
|
This PR causes the following changes to the html docs (ubuntu-latest-3.11): See CI logs for the full diff. |
|
This PR causes the following changes to the html docs (ubuntu-latest-3.11): See CI logs for the full diff. |
| if len(param_type) == 1 and not isinstance(param_type.element, pnlvm.ir.ArrayType): | ||
| index = [ctx.int32_ty(0)] | ||
|
|
||
| if not isinstance(index, list): |
There was a problem hiding this comment.
It might be better to guarantee that index/indices is always a list.
There was a problem hiding this comment.
I did that trying to deal with using lists as index in LinearCombination (ex L1568 exponent = self._gen_llvm_load_param(ctx, b, params, EXPONENTS, in_idx, 1.0) without changing other TransformFunctions or overriding _gen_llvm_load_param and couldn't think of something better. I'm fine changing it if it's better to do one of those or something else I haven't thought of.
|
|
||
| if isinstance(ptro.type.pointee, pnlvm.ir.ArrayType): | ||
| with pnlvm.helpers.array_ptr_loop(builder, ptro, f"combine_axis{len(indices)}") as (b, idx): | ||
| self._llvm_combine_body(b, ctx, vi, vo, val_f, pow_f, comb_op, params, [*indices, idx]) |
There was a problem hiding this comment.
Rather that recursing here, it might be clearer to use recursive_iterate_arrays over the output array.
There was a problem hiding this comment.
Can this be used when exponents/weights are either scalar or matching the input shape? Not sure about it, but it seems that since recursive_iterate_arrays yields gep results, it would need to conditionally include or exclude those parameter vals in the recursive_iterate_arrays calls, and need to be repeated per combination.
There was a problem hiding this comment.
@jvesely sorry, would you say this part is just unclear, or incorrect/costly/risky that it shouldn't wait to be reworked? I was a bit stumped on it considering my comment above. The overall support for >2d depends on these/similar changes
There was a problem hiding this comment.
Hi, sorry for the delay. I'll take another look at the updated changes today or tomorrow.
| # random 1/-1 | ||
| weights = 2 * (np.round(RANDh_V['weights'][variable.shape]) - .5) | ||
| if exponents == 'A': | ||
| exponents = RANDh_V['exponents'][variable.shape] |
There was a problem hiding this comment.
Why can't the above be passed as parametrized arguments?
There was a problem hiding this comment.
They could be generated in the test too.
Otherwise, I think the issue is that they need to match [parts of] the variable shape, but AFAIK there isn't a way to couple parametrization vars (as in, only do (var1,exp1), (var2,exp2)... and not also (var1,exp2), (var2,exp1)), so I'd still need to pass some function or dict to get the correctly shape value out.
But yeah I can also pre-calculate these a bit better.
|
This PR causes the following changes to the html docs (ubuntu-latest-3.11): See CI logs for the full diff. |
5148084 to
bd387a7
Compare
|
This PR causes the following changes to the html docs (ubuntu-latest-3.11): See CI logs for the full diff. |
|
This PR causes the following changes to the html docs (ubuntu-latest-3.11): See CI logs for the full diff. |
| self._gen_llvm_combine(builder, ctx=ctx, vi=arg_in, vo=arg_out, params=params) | ||
| return builder | ||
|
|
||
| def _gen_llvm_combine_body(self, builder, ctx, vi, vo, val_f, pow_f, comb_op, params, indices): |
There was a problem hiding this comment.
What is val_f ? if it's not a function, it probably shouldn't have the _f suffix.
There was a problem hiding this comment.
Changed; it's not a function, I just misunderstood the naming convention I think
| tmp = (variable ** exponent) * weights | ||
| if operation == pnl.SUM: | ||
| expected = np.sum(tmp, axis=0) * scale + offset | ||
| if operation == pnl.PRODUCT: |
There was a problem hiding this comment.
might need to use elif, including
elif
assert False, "Unknown operation"
at the end.
There was a problem hiding this comment.
Done here, though I copied this chunk from the other tests in test_combination.py and didn't touch those
| expected = np.prod(tmp, axis=0) * scale + offset | ||
|
|
||
| # wider tolerances needed for fp32 | ||
| np.testing.assert_allclose(res, expected, rtol=3e-5, atol=2e-7) |
There was a problem hiding this comment.
If the more lenient tolerance is only needed for fp32, please apply it only for fp32.
| # higher dimension arrays | ||
| test_varh1 = np.random.rand(1, 1, SIZE) | ||
| test_varh2 = np.random.rand(2, 3, SIZE, SIZE) | ||
| test_varh3 = np.random.rand(5, 4, SIZE, SIZE, SIZE) |
There was a problem hiding this comment.
Does using float32 dtype for the randomly generated values work to avoid having to relax tolerances when checking results?
There was a problem hiding this comment.
Ah, yeah it does. I do have to do this for all of the random vars though, or some other variants of other tests here will go out of tolerance (at least test_reduce_function but I haven't run enough to see if it's always the same)
|
This PR causes the following changes to the html docs (ubuntu-latest-3.11): See CI logs for the full diff. |
supports parameter specifications as scalar, len-1 vector, or N-dim array matching shape of input (weights, exponents) or output (scale, offset) (len-M vector elementwise for (M, ...) shape arrays is intended to work, but does not work in non-compiled PNL)
|
This PR causes the following changes to the html docs (ubuntu-latest-3.11): See CI logs for the full diff. |
|
|
||
| assert isinstance(vi.type.pointee, pnlvm.ir.ArrayType) | ||
| with pnlvm.helpers.array_ptr_loop(builder, vi, "combine") as (b, idx): | ||
| in_idx = [idx, *indices] |
There was a problem hiding this comment.
how come "idx" is prepended to the list of indices? I'd expect the innermost loop to change the last index.
| if pytest.helpers.llvm_current_fp_precision() == 'fp32': | ||
| try: | ||
| res = res.astype(np.float32) | ||
| except AttributeError: |
There was a problem hiding this comment.
does np.random.default_rng().random(size=(*args), dype=np.float32) work without the extra scalar handling logic?
supports parameter specifications as scalar, len-1 vector, or N-dim array matching shape of input (weights, exponents) or output (scale, offset)
(len-M vector elementwise for (M, ...) shape arrays is intended to work, but does not work in non-compiled PNL)