|
1 | 1 | #include <cstdint> |
2 | 2 | #include <functional> |
3 | 3 | #include <map> |
| 4 | +#include <string> |
4 | 5 | #include <vector> |
5 | 6 |
|
6 | 7 | #include "gtest/gtest.h" // from @googletest |
@@ -737,6 +738,74 @@ TEST_P(KernelImplementationTest, TestConv1dCwFcwStride2) { |
737 | 738 | EXPECT_EQ(actualUnpacked, expected); |
738 | 739 | } |
739 | 740 |
|
| 741 | +// End-to-end Halevi-Shoup matvec for a padded strided 1-D multichannel conv, in |
| 742 | +// the packing production uses when LayoutPropagation folds a zero tensor.pad on |
| 743 | +// the width dim into the conv's own `padding` parameter: the data ciphertext is |
| 744 | +// packed row-major at the *unpadded* width, and the Toeplitz matrix is built |
| 745 | +// with padding = p so that a window reaching into the padding contributes no |
| 746 | +// column. `expected` is the convolution of the zero-padded data. |
| 747 | +void checkPaddedConv1dCwFcw(int64_t padding, const tensor3d& expected, |
| 748 | + bool unroll, bool interchangeRows) { |
| 749 | + SCOPED_TRACE("padding = " + std::to_string(padding)); |
| 750 | + MLIRContext context; |
| 751 | + // 1x2x6 input data, 2x2x3 filter, stride 2. |
| 752 | + tensor3d data = {{{0, 1, 2, 3, 4, 5}, {6, 7, 8, 9, 10, 11}}}; |
| 753 | + tensor3d filter = {{{3, 4, 1}, {1, 5, 2}}, {{1, 2, 3}, {2, 2, 2}}}; |
| 754 | + int64_t stride = 2; |
| 755 | + int numSlots = 16; |
| 756 | + |
| 757 | + RankedTensorType dataType = |
| 758 | + RankedTensorType::get({1, 2, 6}, mlir::IndexType::get(&context)); |
| 759 | + RankedTensorType filterType = |
| 760 | + RankedTensorType::get({2, 2, 3}, mlir::IndexType::get(&context)); |
| 761 | + |
| 762 | + auto dataLayout = getRowMajorLayoutRelation(dataType, numSlots); |
| 763 | + std::vector<std::vector<int>> packedData = |
| 764 | + evaluateLayout(dataLayout, getDataValueFn3D(data)); |
| 765 | + |
| 766 | + auto filterLayout = get1dConvCwFcwFilterDiagonalizedRelation( |
| 767 | + filterType, dataType, stride, padding, numSlots, interchangeRows); |
| 768 | + ASSERT_TRUE(succeeded(filterLayout)); |
| 769 | + std::function<int(const std::vector<int64_t>&)> getFilterValueFn = |
| 770 | + [&](const std::vector<int64_t>& domainPoint) -> int { |
| 771 | + return filter[domainPoint[0]][domainPoint[1]][domainPoint[2]]; |
| 772 | + }; |
| 773 | + std::vector<std::vector<int>> packedFilter = |
| 774 | + evaluateLayout(filterLayout.value(), getFilterValueFn); |
| 775 | + // The matrix shape must be derived the same way the filter was diagonalized, |
| 776 | + // i.e. against the unpadded data type with padding = p: implementHaleviShoup |
| 777 | + // sizes the squat-diagonal collapse from nextPowerOfTwo of these dims. |
| 778 | + auto expandedFilterShape = |
| 779 | + get1dConvCwFcwFilterExpandedType(filterType, dataType, stride, padding); |
| 780 | + |
| 781 | + auto dag = implementHaleviShoup( |
| 782 | + LiteralValue(packedData[0]), LiteralValue(packedFilter), |
| 783 | + expandedFilterShape.getShape(), DagType::intTensor(32, {numSlots}), |
| 784 | + /*zeroDiagonals=*/{}, unroll); |
| 785 | + auto actual = std::get<std::vector<int>>(evalKernel(dag)[0].get()); |
| 786 | + |
| 787 | + int64_t outputWidth = expected[0][0].size(); |
| 788 | + RankedTensorType outputType = RankedTensorType::get( |
| 789 | + {1, 2, outputWidth}, mlir::IndexType::get(&context)); |
| 790 | + auto resultLayout = get1dConvResultRelation(outputType, stride, /*padding=*/0, |
| 791 | + numSlots, interchangeRows); |
| 792 | + |
| 793 | + EXPECT_EQ( |
| 794 | + unpackLayoutTo3DTensor<int>(resultLayout, {actual}, {1, 2, outputWidth}), |
| 795 | + expected); |
| 796 | +} |
| 797 | + |
| 798 | +TEST_P(KernelImplementationTest, TestConv1dCwFcwStride2WithPadding) { |
| 799 | + // Same shape family as TestConv1dCwFcwStride2, but with padding != 0 |
| 800 | + // padding 1 keeps the unpadded and padded column counts in the same |
| 801 | + // power-of-two bucket (2*6=12 and 2*8=16 both round to 16); padding 2 does |
| 802 | + // not (2*6=12 rounds to 16, 2*10=20 rounds to 32). |
| 803 | + checkPaddedConv1dCwFcw(/*padding=*/1, {{{45, 79, 111}, {29, 62, 86}}}, |
| 804 | + std::get<0>(GetParam()), std::get<1>(GetParam())); |
| 805 | + checkPaddedConv1dCwFcw(/*padding=*/2, {{{12, 63, 95, 97}, {12, 50, 74, 56}}}, |
| 806 | + std::get<0>(GetParam()), std::get<1>(GetParam())); |
| 807 | +} |
| 808 | + |
740 | 809 | TEST_P(KernelImplementationTest, |
741 | 810 | TestConv2dNchwFchwStride2InterchangedLargeSlots) { |
742 | 811 | MLIRContext context; |
|
0 commit comments