From 6615010cd016125f6abbf7a50793e70e569b3703 Mon Sep 17 00:00:00 2001 From: Manish Gupta Date: Thu, 19 Nov 2020 21:25:25 -0800 Subject: [PATCH] CUTLASS 2.4 (Implicit GEMM convolution) (#147) CUTLASS 2.4 (Implicit GEMM Convolution) Co-authored-by: Manish Gupta , Haicheng Wu , Dustyn Blasig , Andrew Kerr --- CHANGELOG.md | 11 + CMakeLists.txt | 202 ++- README.md | 113 +- cmake/CTestTestfile.config.cmake | 19 + cuBLAS.cmake | 21 + cuDNN.cmake | 107 ++ examples/03_visualize_layout/CMakeLists.txt | 6 + .../03_visualize_layout/visualize_layout.cpp | 4 + .../turing_tensorop_gemm.cu | 52 +- .../CMakeLists.txt | 28 + .../turing_tensorop_conv2dfprop.cu | 758 ++++++++ examples/12_gemm_bias_relu/gemm_bias_relu.cu | 40 +- examples/13_fused_two_gemms/fused_gemm.cu | 43 +- examples/13_fused_two_gemms/kernel/b2b_gemm.h | 2 +- .../ampere_tf32_tensorop_gemm.cu | 52 +- .../ampere_sparse_tensorop_gemm.cu | 55 +- .../CMakeLists.txt | 28 + .../ampere_tensorop_conv2dfprop.cu | 763 ++++++++ examples/CMakeLists.txt | 33 +- include/cutlass/arch/memory_sm80.h | 17 +- include/cutlass/arch/mma.h | 2 +- include/cutlass/arch/mma_sm75.h | 4 +- .../arch/{sp_mma_sm80.h => mma_sparse_sm80.h} | 10 +- include/cutlass/arch/wmma.h | 16 +- include/cutlass/conv/conv2d_problem_size.h | 450 +++++ include/cutlass/conv/conv3d_problem_size.h | 453 +++++ include/cutlass/conv/convolution.h | 118 ++ .../conv/device/implicit_gemm_convolution.h | 263 +++ include/cutlass/conv/kernel/default_conv2d.h | 104 ++ .../conv/kernel/default_conv2d_dgrad.h | 1154 +++++++++++++ .../conv/kernel/default_conv2d_fprop.h | 1379 +++++++++++++++ .../conv/kernel/default_conv2d_wgrad.h | 928 ++++++++++ .../conv/kernel/default_conv3d_dgrad.h | 184 ++ .../conv/kernel/default_conv3d_fprop.h | 181 ++ .../conv/kernel/default_conv3d_wgrad.h | 504 ++++++ .../conv/kernel/implicit_gemm_convolution.h | 424 +++++ ...rad_filter_tile_access_iterator_analytic.h | 240 +++ ...ad_filter_tile_access_iterator_optimized.h | 283 +++ ...t_gradient_tile_access_iterator_analytic.h | 525 ++++++ ..._gradient_tile_access_iterator_optimized.h | 437 +++++ ...activation_tile_access_iterator_analytic.h | 274 +++ ...ctivation_tile_access_iterator_optimized.h | 438 +++++ ...rop_filter_tile_access_iterator_analytic.h | 252 +++ ...op_filter_tile_access_iterator_optimized.h | 282 +++ .../cutlass/conv/threadblock/conv2d_params.h | 609 +++++++ .../conv/threadblock/conv2d_tile_iterator.h | 170 ++ ...activation_tile_access_iterator_analytic.h | 254 +++ ...ctivation_tile_access_iterator_optimized.h | 273 +++ ...t_gradient_tile_access_iterator_analytic.h | 234 +++ ..._gradient_tile_access_iterator_optimized.h | 300 ++++ ...rad_filter_tile_access_iterator_analytic.h | 263 +++ ...t_gradient_tile_access_iterator_analytic.h | 331 ++++ ...activation_tile_access_iterator_analytic.h | 296 ++++ ...rop_filter_tile_access_iterator_analytic.h | 262 +++ ...activation_tile_access_iterator_analytic.h | 281 +++ ...ctivation_tile_access_iterator_optimized.h | 346 ++++ ...t_gradient_tile_access_iterator_analytic.h | 256 +++ ..._gradient_tile_access_iterator_optimized.h | 330 ++++ .../threadblock/implicit_gemm_multistage.h | 480 ++++++ .../threadblock/implicit_gemm_pipelined.h | 313 ++++ include/cutlass/core_io.h | 54 +- .../epilogue/thread/linear_combination.h | 2 +- .../thread/linear_combination_clamp.h | 10 +- .../linear_combination_planar_complex.h | 2 +- .../epilogue/thread/linear_combination_relu.h | 121 +- .../thread/linear_combination_sigmoid.h | 2 +- .../threadblock/default_epilogue_tensor_op.h | 46 + .../default_thread_map_tensor_op.h | 49 + .../threadblock/output_iterator_parameter.h | 92 + .../threadblock/output_tile_thread_map.h | 62 + .../threadblock/predicated_tile_iterator.h | 379 +++- .../predicated_tile_iterator_params.h | 227 +++ .../warp/fragment_iterator_wmma_tensor_op.h | 4 +- .../warp/tile_iterator_wmma_tensor_op.h | 2 +- include/cutlass/fast_math.h | 4 +- include/cutlass/functional.h | 150 ++ include/cutlass/gemm/device/gemm_sparse.h | 40 +- .../gemm/device/gemm_universal_adapter.h | 13 +- .../cutlass/gemm/device/gemm_universal_base.h | 52 +- .../gemm/kernel/default_gemm_complex.h | 160 ++ include/cutlass/gemm/kernel/gemm.h | 18 +- .../cutlass/gemm/kernel/gemm_planar_complex.h | 2 +- include/cutlass/gemm/kernel/gemm_universal.h | 18 +- include/cutlass/gemm/kernel/sparse_gemm.h | 2 +- include/cutlass/gemm/thread/mma_sm60.h | 29 + .../gemm/threadblock/default_mma_core_simt.h | 2 +- .../default_multistage_mma_complex.h | 1 + ...default_multistage_mma_complex_core_sm80.h | 670 +++++++ .../cutlass/gemm/threadblock/mma_multistage.h | 9 +- .../gemm/threadblock/mma_singlestage.h | 8 + .../cutlass/gemm/warp/mma_complex_tensor_op.h | 85 +- .../warp/mma_gaussian_complex_tensor_op.h | 42 +- include/cutlass/gemm/warp/mma_simt.h | 22 +- .../cutlass/gemm/warp/mma_sparse_tensor_op.h | 63 +- include/cutlass/gemm/warp/mma_tensor_op.h | 2 - .../gemm/warp/mma_tensor_op_tile_iterator.h | 427 ++++- .../warp/mma_tensor_op_tile_iterator_sm70.h | 841 +++++++++ include/cutlass/layout/tensor.h | 16 +- .../transform/pitch_linear_thread_map.h | 128 ++ .../predicated_tile_access_iterator.h | 12 +- .../regular_tile_access_iterator_tensor_op.h | 262 --- media/docs/functionality.md | 22 + media/docs/implicit_gemm_convolution.md | 779 +++++++++ media/docs/profiler.md | 173 +- media/docs/quickstart.md | 64 +- media/images/conv2d-fprop-int4.png | Bin 0 -> 391882 bytes media/images/ldmatrix-8x128bx4.png | Bin 0 -> 560084 bytes media/images/ldmatrix-tensorop-32x32x32.png | Bin 0 -> 1219789 bytes media/images/mma-8x8x32.png | Bin 0 -> 215559 bytes .../tensor-op-permuted-smem-layout-TN-k0.png | Bin 0 -> 181688 bytes .../tensor-op-permuted-smem-layout-TN-k1.png | Bin 0 -> 186274 bytes .../tensor-op-permuted-smem-layout-TN.png | Bin 0 -> 265401 bytes test/CMakeLists.txt | 1 + test/unit/CMakeLists.txt | 30 +- test/unit/conv/CMakeLists.txt | 42 + test/unit/conv/device/CMakeLists.txt | 148 ++ ...f32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu | 130 ++ ...f32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu | 314 ++++ ...nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu | 123 ++ ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu | 118 ++ ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu | 159 ++ ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu | 286 +++ ...m_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu | 323 ++++ ...hwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu | 124 ++ ...f32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu | 222 +++ ...f32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu | 397 +++++ ...nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu | 121 ++ ...nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.cu | 124 ++ ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu | 81 + ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu | 121 ++ ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu | 124 ++ ...m_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm50.cu | 82 + ...m_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu | 321 ++++ ...wx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm75.cu | 520 ++++++ ...wx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm80.cu | 521 ++++++ ...4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm75.cu | 119 ++ ...4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm80.cu | 121 ++ ...wx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm75.cu | 679 ++++++++ ...wx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm80.cu | 680 ++++++++ ...8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm75.cu | 119 ++ ...8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm80.cu | 120 ++ ...hwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu | 81 + test/unit/conv/device/conv2d_problems.h | 520 ++++++ test/unit/conv/device/conv2d_testbed.h | 558 ++++++ .../conv/device/conv2d_testbed_interleaved.h | 534 ++++++ ...f32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu | 172 ++ ...f32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu | 311 ++++ ...nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu | 122 ++ ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu | 78 + ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu | 78 + ...nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu | 161 ++ ...m_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu | 321 ++++ ...hwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu | 81 + ...c_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu | 80 + ...c_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu | 80 + test/unit/conv/device/conv3d_problems.h | 248 +++ test/unit/conv/device/conv3d_testbed.h | 537 ++++++ ...wc_f16ndhwc_f32ndhwc_tensor_op_f32_sm75.cu | 78 + ...wc_f16ndhwc_f32ndhwc_tensor_op_f32_sm80.cu | 159 ++ ...c_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu | 120 ++ .../threadblock/epilogue_simt_sm61.cu | 10 +- test/unit/gemm/device/CMakeLists.txt | 327 ++-- test/unit/gemm/device/multistage_testbed.h | 41 +- test/unit/gemm/device/simt_sgemm_nt_sm80.cu | 9 +- test/unit/gemm/device/simt_sgemm_tn_sm80.cu | 10 +- test/unit/gemm/device/testbed.h | 40 +- test/unit/gemm/device/testbed_complex.h | 39 + test/unit/gemm/device/testbed_interleaved.h | 33 + test/unit/gemm/device/testbed_sparse.h | 38 +- test/unit/gemm/device/testbed_universal.h | 33 + .../mma_multistage_sparse_testbed.h | 14 +- .../gemm/threadblock/mma_multistage_testbed.h | 14 +- test/unit/gemm/warp/gemm_sm70.cu | 85 + test/unit/gemm/warp/testbed.h | 6 +- test/unit/reduction/CMakeLists.txt | 1 - .../regular_tile_iterator_tensor_op.cu | 2 +- tools/CMakeLists.txt | 8 +- tools/library/CMakeLists.txt | 11 +- .../library/include/cutlass/library/handle.h | 4 + .../library/include/cutlass/library/library.h | 293 ++++ .../include/cutlass/library/manifest.h | 3 + .../include/cutlass/library/operation_table.h | 268 +++ tools/library/include/cutlass/library/util.h | 21 + tools/library/scripts/conv2d_operation.py | 344 ++++ tools/library/scripts/conv3d_operation.py | 321 ++++ tools/library/scripts/generator.py | 486 ++++-- tools/library/scripts/library.py | 87 +- tools/library/scripts/manifest.py | 12 +- tools/library/src/conv2d_operation.h | 380 ++++ tools/library/src/conv3d_operation.h | 378 ++++ tools/library/src/handle.cu | 64 +- tools/library/src/library_internal.h | 54 + tools/library/src/manifest.cpp | 11 + tools/library/src/operation_table.cu | 49 + .../reduction/init_reduction_operations.cu | 57 + .../library/src/reduction/reduction_device.cu | 145 ++ .../src/reduction/reduction_operation.h | 282 +++ tools/library/src/reference/conv2d.cu | 223 +++ tools/library/src/reference/conv3d.cu | 203 +++ .../src/reference/conv_reference_operation.h | 607 +++++++ .../initialize_reference_operations.cu | 4 + tools/library/src/util.cu | 176 +- tools/profiler/CMakeLists.txt | 19 +- .../profiler/src/conv2d_operation_profiler.cu | 1468 ++++++++++++++++ .../profiler/src/conv2d_operation_profiler.h | 431 +++++ .../profiler/src/conv3d_operation_profiler.cu | 1345 +++++++++++++++ .../profiler/src/conv3d_operation_profiler.h | 441 +++++ tools/profiler/src/cudnn_helpers.cpp | 485 ++++++ tools/profiler/src/cudnn_helpers.h | 584 +++++++ tools/profiler/src/cutlass_profiler.cu | 8 + tools/profiler/src/device_allocation.cu | 37 +- tools/profiler/src/operation_profiler.cu | 19 +- tools/profiler/src/options.cu | 12 +- tools/profiler/src/options.h | 3 + tools/profiler/src/performance_report.cpp | 172 +- tools/profiler/src/performance_report.h | 22 +- tools/profiler/src/problem_space.cpp | 166 +- tools/profiler/src/problem_space.h | 57 +- .../src/reduction_operation_profiler.h | 167 ++ .../src/sparse_gemm_operation_profiler.cu | 3 + .../util/include/cutlass/util/host_reorder.h | 12 + .../util/reference/device/convolution.h | 1536 +++++++++++++++++ .../cutlass/util/reference/host/convolution.h | 767 ++++++++ .../cutlass/util/reference/host/gemm.h | 39 + 224 files changed, 43939 insertions(+), 1061 deletions(-) create mode 100644 cmake/CTestTestfile.config.cmake create mode 100644 cuDNN.cmake create mode 100644 examples/09_turing_tensorop_conv2dfprop/CMakeLists.txt create mode 100644 examples/09_turing_tensorop_conv2dfprop/turing_tensorop_conv2dfprop.cu create mode 100644 examples/22_ampere_tensorop_conv2dfprop/CMakeLists.txt create mode 100644 examples/22_ampere_tensorop_conv2dfprop/ampere_tensorop_conv2dfprop.cu rename include/cutlass/arch/{sp_mma_sm80.h => mma_sparse_sm80.h} (99%) create mode 100644 include/cutlass/conv/conv2d_problem_size.h create mode 100644 include/cutlass/conv/conv3d_problem_size.h create mode 100644 include/cutlass/conv/convolution.h create mode 100644 include/cutlass/conv/device/implicit_gemm_convolution.h create mode 100644 include/cutlass/conv/kernel/default_conv2d.h create mode 100644 include/cutlass/conv/kernel/default_conv2d_dgrad.h create mode 100644 include/cutlass/conv/kernel/default_conv2d_fprop.h create mode 100644 include/cutlass/conv/kernel/default_conv2d_wgrad.h create mode 100644 include/cutlass/conv/kernel/default_conv3d_dgrad.h create mode 100644 include/cutlass/conv/kernel/default_conv3d_fprop.h create mode 100644 include/cutlass/conv/kernel/default_conv3d_wgrad.h create mode 100644 include/cutlass/conv/kernel/implicit_gemm_convolution.h create mode 100644 include/cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_optimized.h create mode 100644 include/cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_optimized.h create mode 100644 include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_optimized.h create mode 100644 include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_optimized.h create mode 100644 include/cutlass/conv/threadblock/conv2d_params.h create mode 100644 include/cutlass/conv/threadblock/conv2d_tile_iterator.h create mode 100644 include/cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_optimized.h create mode 100644 include/cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_optimized.h create mode 100644 include/cutlass/conv/threadblock/conv3d_dgrad_filter_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv3d_dgrad_output_gradient_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv3d_fprop_activation_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv3d_fprop_filter_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_optimized.h create mode 100644 include/cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_analytic.h create mode 100644 include/cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_optimized.h create mode 100644 include/cutlass/conv/threadblock/implicit_gemm_multistage.h create mode 100644 include/cutlass/conv/threadblock/implicit_gemm_pipelined.h create mode 100644 include/cutlass/epilogue/threadblock/output_iterator_parameter.h create mode 100644 include/cutlass/epilogue/threadblock/predicated_tile_iterator_params.h create mode 100644 media/docs/implicit_gemm_convolution.md create mode 100644 media/images/conv2d-fprop-int4.png create mode 100644 media/images/ldmatrix-8x128bx4.png create mode 100644 media/images/ldmatrix-tensorop-32x32x32.png create mode 100644 media/images/mma-8x8x32.png create mode 100644 media/images/tensor-op-permuted-smem-layout-TN-k0.png create mode 100644 media/images/tensor-op-permuted-smem-layout-TN-k1.png create mode 100644 media/images/tensor-op-permuted-smem-layout-TN.png create mode 100644 test/unit/conv/CMakeLists.txt create mode 100644 test/unit/conv/device/CMakeLists.txt create mode 100644 test/unit/conv/device/conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu create mode 100644 test/unit/conv/device/conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu create mode 100644 test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu create mode 100644 test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu create mode 100644 test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_dgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_dgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm50.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm75.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm75.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm75.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm75.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_fprop_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_problems.h create mode 100644 test/unit/conv/device/conv2d_testbed.h create mode 100644 test/unit/conv/device/conv2d_testbed_interleaved.h create mode 100644 test/unit/conv/device/conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu create mode 100644 test/unit/conv/device/conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu create mode 100644 test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu create mode 100644 test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu create mode 100644 test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_wgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu create mode 100644 test/unit/conv/device/conv2d_wgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv3d_dgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv3d_fprop_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv3d_problems.h create mode 100644 test/unit/conv/device/conv3d_testbed.h create mode 100644 test/unit/conv/device/conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm75.cu create mode 100644 test/unit/conv/device/conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm80.cu create mode 100644 test/unit/conv/device/conv3d_wgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu create mode 100644 tools/library/scripts/conv2d_operation.py create mode 100644 tools/library/scripts/conv3d_operation.py create mode 100644 tools/library/src/conv2d_operation.h create mode 100644 tools/library/src/conv3d_operation.h create mode 100644 tools/library/src/reduction/init_reduction_operations.cu create mode 100644 tools/library/src/reduction/reduction_device.cu create mode 100644 tools/library/src/reduction/reduction_operation.h create mode 100644 tools/library/src/reference/conv2d.cu create mode 100644 tools/library/src/reference/conv3d.cu create mode 100644 tools/library/src/reference/conv_reference_operation.h create mode 100644 tools/profiler/src/conv2d_operation_profiler.cu create mode 100644 tools/profiler/src/conv2d_operation_profiler.h create mode 100644 tools/profiler/src/conv3d_operation_profiler.cu create mode 100644 tools/profiler/src/conv3d_operation_profiler.h create mode 100644 tools/profiler/src/cudnn_helpers.cpp create mode 100644 tools/profiler/src/cudnn_helpers.h create mode 100644 tools/profiler/src/reduction_operation_profiler.h create mode 100644 tools/util/include/cutlass/util/reference/device/convolution.h create mode 100644 tools/util/include/cutlass/util/reference/host/convolution.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 96053eefb..eded0a4ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ # NVIDIA CUTLASS Changelog # CUTLASS 2.x +## [2.4.0](https://github.com/NVIDIA/cutlass/releases/tag/v2.4.0) (2020-11-19) + * Implicit GEMM convolution kernels supporting CUDA and Tensor Cores on NVIDIA GPUs + * Operators: forward (Fprop), backward data gradient (Dgrad), and backward weight gradient (Wgrad) convolution + * Data type: FP32, complex, Tensor Float 32 (TF32), BFloat16 (BF16), Float16, Int4, Int8, Int32 + * Spatial dimensions: 1-D, 2-D, and 3-D + * Layout: NHWC, NCxHWx + * Implicit GEMM convolution components: + * Global memory iterators supporting fprop, dgrad, and wgrad + * `MmaMultistage` for implicit GEMM convolution for NVIDIA Ampere architecture + * `MmaPipeline` for implicit GEMM convolution for NVIDIA Volta and Turing architectures + * [Documentation](/media/docs/implicit_gemm_convolution.md) describing Implicit GEMM Convolution algorithm and implementation ## [2.3.0](https://github.com/NVIDIA/cutlass/releases/tag/v2.3.0) (2020-09-23) * [NVIDIA Ampere Architecture features](https://devblogs.nvidia.com/nvidia-ampere-architecture-in-depth/) diff --git a/CMakeLists.txt b/CMakeLists.txt index d853a9dd3..a0ece82c6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ endif() message(STATUS "CMake Version: ${CMAKE_VERSION}") -project(CUTLASS VERSION 2.3.0 LANGUAGES CXX) +project(CUTLASS VERSION 2.4.0 LANGUAGES CXX) include(${CMAKE_CURRENT_SOURCE_DIR}/CUDA.cmake) find_package(Doxygen QUIET) @@ -137,7 +137,12 @@ if (NOT (CMAKE_BUILD_TYPE OR CONFIGURATION_TYPES)) endif() set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CUTLASS_LIBRARY_DEBUG_POSTFIX ".debug" CACHE STRING "Default postfix value for debug libraries") +if (DEFINED CMAKE_DEBUG_POSTFIX) + set(CUTLASS_LIBRARY_DEBUG_POSTFIX_INIT ${CMAKE_DEBUG_POSTFIX}) +else() + set(CUTLASS_LIBRARY_DEBUG_POSTFIX_INIT .debug) +endif() +set(CUTLASS_LIBRARY_DEBUG_POSTFIX ${CUTLASS_LIBRARY_DEBUG_POSTFIX_INIT} CACHE STRING "Default postfix value for debug libraries") if(WIN32) # On Windows we link against the shared (DLL) runtime. Change gtest settings to match this. @@ -192,7 +197,6 @@ endif() set(CUTLASS_DEBUG_TRACE_LEVEL "0" CACHE STRING "Level of debug tracing to perform.") list(APPEND CUTLASS_CUDA_NVCC_FLAGS -DCUTLASS_DEBUG_TRACE_LEVEL=${CUTLASS_DEBUG_TRACE_LEVEL}) - set(CUTLASS_ENABLE_TENSOR_CORE_MMA ${CUTLASS_ENABLE_TENSOR_CORE_MMA_DEFAULT} CACHE BOOL "Enable PTX mma instruction for collective matrix multiply operations.") @@ -466,20 +470,194 @@ if (CUTLASS_ENABLE_CUBLAS) target_compile_definitions(CUTLASS INTERFACE CUTLASS_ENABLE_CUBLAS=1) endif() +include(${CMAKE_CURRENT_SOURCE_DIR}/cuDNN.cmake) + +if (CUTLASS_ENABLE_CUDNN) + target_compile_definitions(CUTLASS INTERFACE CUTLASS_ENABLE_CUDNN=1) +endif() + ################################################################################ -if(CUTLASS_ENABLE_TOOLS) - add_subdirectory(tools) -endif() -if(CUTLASS_ENABLE_EXAMPLES) - add_subdirectory(examples) +include(CTest) +enable_testing() +if (NOT TARGET test_all) + add_custom_target(test_all) endif() -if(CUTLASS_ENABLE_TESTS) - include(CTest) - enable_testing() - add_subdirectory(test) +set(CUTLASS_INSTALL_TESTS ON CACHE BOOL "Install test executables") +set(CUTLASS_TEST_EXECUTION_ENVIRONMENT "" CACHE BOOL "Environment in which to invoke unit test executables") + +set(CMAKE_TEST_INSTALL_PREFIX test CACHE STRING "Test root install location, relative to CMAKE_INSTALL_PREFIX.") +set(CUTLASS_TEST_INSTALL_PREFIX ${CMAKE_TEST_INSTALL_PREFIX}/cutlass CACHE STRING "Test root install location, relative to CMAKE_INSTALL_PREFIX.") +set(CUTLASS_TEST_INSTALL_BINDIR ${CUTLASS_TEST_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR} CACHE STRING "Test root install location, relative to CMAKE_INSTALL_PREFIX.") +set(CUTLASS_TEST_INSTALL_LIBDIR ${CUTLASS_TEST_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} CACHE STRING "Test root install location, relative to CMAKE_INSTALL_PREFIX.") + +install(DIRECTORY DESTINATION ${CUTLASS_TEST_INSTALL_PREFIX}) +install(DIRECTORY DESTINATION ${CUTLASS_TEST_INSTALL_BINDIR}) +install(DIRECTORY DESTINATION ${CUTLASS_TEST_INSTALL_LIBDIR}) +install(DIRECTORY DESTINATION ${CUTLASS_TEST_INSTALL_PREFIX}/ctest) + +set(CUTLASS_CTEST_TEMPLATE_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/CTestTestfile.config.cmake) +set(CUTLASS_CTEST_GENERATED_FILES "" CACHE INTERNAL "") + +function(cutlass_add_executable_tests NAME TARGET) +# +# Generates test rules for `make test`, `make test_all`, and `ctest` invoked from either the +# or the / after installation. +# +# NAME: The base name for the test. Can be run with `make ` or `ctest -R 'c'`. +# TARGET: The target corresponding to the executable under test. +# DISABLE_EXECUTABLE_INSTALL_RULE: An option, if given, that disables creating an install rule for TARGET. +# DEPENDS: A list of targets or files on which this test is dependent. +# DEPENDEES: A list of targets which should depend on this test. +# TEST_COMMAND_OPTIONS: A list of variables (i.e. by reference params) which contain command line arguments +# to pass to the test executable. A unique test with suffix _0, _1, ... is generated for each set of +# options given. If this option is not used, a single test with no arguments is generated. +# + + set(options DISABLE_EXECUTABLE_INSTALL_RULE) + set(oneValueArgs) + set(multiValueArgs DEPENDS DEPENDEES TEST_COMMAND_OPTIONS) + cmake_parse_arguments(_ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT __DISABLE_EXECUTABLE_INSTALL_RULE AND CUTLASS_INSTALL_TESTS) + + # file(RELATIVE_PATH CMAKE_CURRENT_BINARY_RELATIVE_DIR ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + + install( + TARGETS ${TARGET} + RUNTIME DESTINATION ${CUTLASS_TEST_INSTALL_BINDIR} + ) + + endif() + + if (NOT __TEST_COMMAND_OPTIONS) + set(__TEST_COMMAND_OPTIONS " ") + endif() + + list(LENGTH __TEST_COMMAND_OPTIONS CMD_COUNT) + set(CMD_IDX 0) + + if (CMD_COUNT GREATER 1) + add_custom_target(${NAME} DEPENDS ${TARGET} ${__DEPENDS}) + foreach(DEPENDEE ${__DEPENDEES}) + add_dependencies(${DEPENDEE} ${NAME}) + endforeach() + endif() + + foreach(CMD_OPTIONS ${__TEST_COMMAND_OPTIONS}) + + if (CMD_COUNT GREATER 1) + set(TEST_NAME ${NAME}_${CMD_IDX}) + else() + set(TEST_NAME ${NAME}) + endif() + + # The following rigmarole is needed to deal with spaces and possible quotes in + # command line arguments. The options are passed "by reference" as the actual + # variable names holding the real options. We then expand these in a way that + # preserves any quotes. Note, they have to be in this order for it to work for + # all the use cases below. + + set(CMD_OPTIONS ${${CMD_OPTIONS}}) + list(JOIN CMD_OPTIONS " " TEST_COMMAND_OPTIONS) + separate_arguments(CMD_OPTIONS) + + add_custom_target( + ${TEST_NAME} + COMMAND + ${CUTLASS_TEST_EXECUTION_ENVIRONMENT} $ ${CMD_OPTIONS} + DEPENDS + ${TARGET} + ) + + if (CMD_COUNT GREATER 1) + add_dependencies(${NAME} ${TEST_NAME}) + endif() + + foreach(DEPENDEE ${__DEPENDEES}) + add_dependencies(${DEPENDEE} ${TEST_NAME}) + endforeach() + + add_test( + NAME c${TEST_NAME} + COMMAND ${CUTLASS_TEST_EXECUTION_ENVIRONMENT} $ ${CMD_OPTIONS} + ) + + if (CUTLASS_INSTALL_TESTS) + + # To run the tests from an install package with tests enabled, we need to generate test files + # that don't rely on the current directory structure in build. + + set(TEST_NAME c${TEST_NAME}) + set(TEST_EXE $) + set(TEST_EXE_WORKING_DIRECTORY ./${CMAKE_INSTALL_BINDIR}) + configure_file("${CUTLASS_CTEST_TEMPLATE_FILE}" "${CMAKE_PROJECT_DIR}${CMAKE_CURRENT_BINARY_DIR}/CTestTestfile.${TEST_NAME}.config.cmake" @ONLY) + + file(GENERATE + OUTPUT "${CMAKE_PROJECT_DIR}${CMAKE_CURRENT_BINARY_DIR}/CTestTestfile.${TEST_NAME}.cmake" + INPUT "${CMAKE_PROJECT_DIR}${CMAKE_CURRENT_BINARY_DIR}/CTestTestfile.${TEST_NAME}.config.cmake" + ) + + install( + FILES "${CMAKE_PROJECT_DIR}${CMAKE_CURRENT_BINARY_DIR}/CTestTestfile.${TEST_NAME}.cmake" + DESTINATION ${CUTLASS_TEST_INSTALL_PREFIX}/ctest/ + ) + + set(CUTLASS_CTEST_GENERATED_FILES ${CUTLASS_CTEST_GENERATED_FILES};ctest/CTestTestfile.${TEST_NAME}.cmake CACHE INTERNAL "") + + endif() + + math(EXPR CMD_IDX "${CMD_IDX} + 1") + + endforeach() + +endfunction() + +if (CUTLASS_ENABLE_TOOLS) + add_subdirectory(tools) + if (CUTLASS_ENABLE_PROFILER) + add_dependencies(test_all test_profiler) + endif() endif() +if (CUTLASS_ENABLE_EXAMPLES) + add_subdirectory(examples) + add_dependencies(test_all test_examples) +endif() + +if (CUTLASS_ENABLE_TESTS) + add_subdirectory(test) + add_dependencies(test_all test_unit) +endif() + +if (CUTLASS_INSTALL_TESTS) + + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/cmake") + + file(WRITE "${CMAKE_BINARY_DIR}/cmake/CTestTestfile.cmake" "# Generated File\n") + foreach(GENERATED_FILE ${CUTLASS_CTEST_GENERATED_FILES}) + file(APPEND "${CMAKE_BINARY_DIR}/cmake/CTestTestfile.cmake" "include(${GENERATED_FILE})\n") + endforeach() + + install( + FILES "${CMAKE_BINARY_DIR}/cmake/CTestTestfile.cmake" + DESTINATION ${CUTLASS_TEST_INSTALL_PREFIX}/ + ) + +endif() + +#? install( +#? FILES ${CMAKE_BINARY_DIR}/CTestTestfile.cmake +#? DESTINATION ${CUTLASS_TEST_INSTALL_PREFIX}/ +#? ) +#? +#? install( +#? DIRECTORY +#? ${CMAKE_BINARY_DIR}/tools +#? ${CMAKE_BINARY_DIR}/test +#? DESTINATION ${CUTLASS_TEST_INSTALL_PREFIX}/ +#? FILES_MATCHING PATTERN "CTestTestfile.cmake" +#? ) ################################################################################ diff --git a/README.md b/README.md index 88a1b4070..d7a1d7d47 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ ![ALT](/media/images/gemm-hierarchy-with-epilogue-no-labels.png "Complete CUDA GEMM decomposition") -# CUTLASS 2.3 +# CUTLASS 2.4 -_CUTLASS 2.3 - September 2020_ +_CUTLASS 2.4 - November 2020_ CUTLASS is a collection of CUDA C++ template abstractions for implementing high-performance matrix-multiplication (GEMM) at all levels and scales within CUDA. @@ -25,11 +25,22 @@ Furthermore, CUTLASS demonstrates warp-synchronous matrix multiply operations targeting the programmable, high-throughput _Tensor Cores_ implemented by NVIDIA's Volta, Turing, and Ampere architectures. +Additionaly, CUTLASS implements high-performance convolution (implicit GEMM). +Implicit GEMM is the formulation of a convolution operation as a GEMM. This allows CUTLASS +to build convolutions by reusing highly optimized warp-wide GEMM components and below. + See the [Quick Start Guide](/media/docs/quickstart.md) to get started quickly. -See the [functionality listing](media/docs/functionality.md) for the list of operations +See the [functionality listing](/media/docs/functionality.md) for the list of operations supported at each level of the execution model hierarchy. +# What's New in CUTLASS 2.4 +CUTLASS 2.4 is a significant update to CUTLASS adding: +- 1-D, 2-D, and 3-D convolution targeting Tensor and CUDA cores for NVIDIA Ampere, Turing, and Volta GPU architectures +- CUTLASS profiler support for convolution +- [Documentation](/media/docs/implicit_gemm_convolution.md) describing Implicit GEMM Convolution algorithm and implementation +- See the [CHANGELOG](CHANGELOG.md) for more details. + # What's New in CUTLASS 2.3 CUTLASS 2.3 is a minor update to CUTLASS adding: @@ -118,6 +129,7 @@ CUTLASS is described in the following documents and the accompanying - [Functionality](/media/docs/functionality.md) - summarizes functionality available in CUTLASS - [Efficient GEMM in CUDA](media/docs/efficient_gemm.md) - describes how GEMM kernels may be implemented efficiently in CUDA - [GEMM API](media/docs/gemm_api.md) - describes the CUTLASS GEMM model and C++ template concepts +- [Implicit GEMM Convolution](media/docs/implicit_gemm_convolution.md) - describes 2-D and 3-D convolution in CUTLASS - [Code Organization](media/docs/code_organization.md) - describes the organization and contents of the CUTLASS project - [Terminology](media/docs/terminology.md) - describes terms used in the code - [Programming Guidelines](media/docs/programming_guidelines.md) - guidelines for writing efficient modern CUDA C++ @@ -140,7 +152,7 @@ CUTLASS unit tests, examples, and utilities can be build with CMake starting ver Make sure the `CUDACXX` environment variable points to NVCC in the CUDA Toolkit installed on your system. -``` +```bash $ export CUDACXX=${CUDA_INSTALL_PATH}/bin/nvcc ``` @@ -149,7 +161,7 @@ for CUDA architecture versions 5.0, 6.0, 6.1, 7.0, 7.5, 8.0, and 8.6. To reduce the architectures to build CUTLASS for by changing the CMake configuration setting `CUTLASS_NVCC_ARCHS`. -``` +```bash $ mkdir build && cd build $ cmake .. -DCUTLASS_NVCC_ARCHS=80 # compiles for NVIDIA's Ampere Architecture @@ -160,7 +172,7 @@ From the `build/` directory, compile and run the CUTLASS unit tests by building The unit tests are organized as several binaries mirroring the top-level namespaces of CUTLASS, and they may be executed in parallel via make's `-j` command line argument. -``` +```bash $ make test_unit -j ... ... @@ -191,6 +203,8 @@ include/ # client applications should target this directory arch/ # direct exposure of architecture features (including instruction-level GEMMs) + conv/ # code specialized for convolution + gemm/ # code specialized for general matrix product computations layout/ # layout definitions for matrices, tensors, and other mathematical objects in memory @@ -210,34 +224,39 @@ include/ # client applications should target this directory ``` examples/ - 00_basic_gemm/ # launches a basic GEMM with single precision inputs and outputs + 00_basic_gemm/ # launches a basic GEMM with single precision inputs and outputs - 01_cutlass_utilities/ # demonstrates CUTLASS Utilities for allocating and initializing tensors + 01_cutlass_utilities/ # demonstrates CUTLASS Utilities for allocating and initializing tensors - 02_dump_reg_smem/ # debugging utilities for printing register and shared memory contents + 02_dump_reg_smem/ # debugging utilities for printing register and shared memory contents - 03_visualize_layout/ # utility for visualizing all layout functions in CUTLASS + 03_visualize_layout/ # utility for visualizing all layout functions in CUTLASS - 04_tile_iterator/ # example demonstrating an iterator over tiles in memory + 04_tile_iterator/ # example demonstrating an iterator over tiles in memory - 05_batched_gemm/ # example demonstrating CUTLASS's batched strided GEMM operation + 05_batched_gemm/ # example demonstrating CUTLASS's batched strided GEMM operation - 06_splitK_gemm/ # exmaple demonstrating CUTLASS's Split-K parallel reduction kernel + 06_splitK_gemm/ # exmaple demonstrating CUTLASS's Split-K parallel reduction kernel - 07_volta_tensorop_gemm/ # example demonstrating mixed precision GEMM using Volta Tensor Cores + 07_volta_tensorop_gemm/ # example demonstrating mixed precision GEMM using Volta Tensor Cores - 08_turing_tensorop_gemm/ # example demonstrating integer GEMM using Turing Tensor Cores + 08_turing_tensorop_gemm/ # example demonstrating integer GEMM using Turing Tensor Cores - 10_planar_complex/ # example demonstrating planar complex GEMM kernels + 09_turing_tensorop_conv2dfprop/ # example demonstrating integer implicit GEMM convolution (forward propagation) using Turing Tensor Cores - 11_planar_complex_array/ # example demonstrating planar complex kernels with batch-specific problem sizes + 10_planar_complex/ # example demonstrating planar complex GEMM kernels - 12_gemm_bias_relu/ # example demonstrating GEMM fused with bias and relu + 11_planar_complex_array/ # example demonstrating planar complex kernels with batch-specific problem sizes - 13_fused_two_gemms/ # example demonstrating two GEMms fused in one kernel + 12_gemm_bias_relu/ # example demonstrating GEMM fused with bias and relu + + 13_fused_two_gemms/ # example demonstrating two GEMms fused in one kernel + + 22_ampere_tensorop_conv2dfprop/ # example demonstrating integer implicit GEMM convolution (forward propagation) using Ampere Tensor Cores ``` ### Tools + ``` tools/ library/ # CUTLASS Instance Library - contains instantiations of all supported CUTLASS templates @@ -266,14 +285,14 @@ Instructions for building and running the Unit tests are described in the [Quick The `tools/profiler/` directory contains a command-line utility for launching each of the GEMM kernels. It can be built as follows: -``` +```bash $ make cutlass_profiler -j16 ``` By default, only one tile size is instantiated for each data type, math instruction, and layout. To instantiate all, set the following environment variable when running CMake from an empty `build/` directory. Beware, this results in *thousands* of kernels and long build times. -``` +```bash $ cmake .. -DCUTLASS_NVCC_ARCHS=75 -DCUTLASS_LIBRARY_KERNELS=all ... $ make cutlass_profiler -j16 @@ -282,7 +301,7 @@ $ make cutlass_profiler -j16 To compile strictly one kernel or a small set of kernels, a comma-delimited list of kernel names with wildcard characters may be reduce the set of kernels. The following builds exactly one kernel: -``` +```bash $ cmake .. -DCUTLASS_NVCC_ARCHS=75 -DCUTLASS_LIBRARY_KERNELS=cutlass_simt_sgemm_128x128_8x2_nn_align1 ... $ make cutlass_profiler -j16 @@ -318,6 +337,56 @@ $ ./tools/profiler/cutlass_profiler --kernels=sgemm --m=3456 --n=4096 --k=4096 Math: 17218.4 GFLOP/s ``` +To compile strictly 2-D or 3-D convolution kernels, filter by operation +```bash +$ cmake .. -DCUTLASS_NVCC_ARCHS=75 -DCUTLASS_LIBRARY_OPERATIONS=conv2d,conv3d +... +$ make cutlass_profiler -j16 +``` + +or by name + +```bash +$ cmake .. -DCUTLASS_NVCC_ARCHS=80 -DCUTLASS_LIBRARY_KERNELS=sfprop,s16816fprop,s16816dgrad,s16816wgrad +... +$ make cutlass_profiler -j16 +``` + +Example command line for profiling 2-D convolution kernels is as follows: + +```bash +$ ./tools/profiler/cutlass_profiler --kernels=cutlass_simt_sfprop_optimized_128x128_8x2_nhwc --n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 + + +============================= + Problem ID: 1 + + Provider: CUTLASS + OperationKind: conv2d + Operation: cutlass_simt_sfprop_optimized_128x128_8x2_nhwc + + Status: Success + Verification: ON + Disposition: Passed + +reference_device: Passed + + Arguments: --conv_kind=fprop --n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 --p=224 --q=224 --pad_h=1 --pad_w=1 \ + --stride_h=1 --stride_w=1 --dilation_h=1 --dilation_w=1 --Activation=f32:nhwc --Filter=f32:nhwc --Output=f32:nhwc \ + --conv_mode=cross --iterator_algorithm=optimized --alpha=1 --beta=0 --split_k_mode=serial --split_k_slices=1 \ + --eq_gemm_provider=none --op_class=simt --accum=f32 --cta_m=128 --cta_n=128 --cta_k=8 --stages=2 --warps_m=4 \ + --warps_n=2 --warps_k=1 --inst_m=1 --inst_n=1 --inst_k=1 --min_cc=50 --max_cc=1024 + + Bytes: 2055798784 bytes + FLOPs: 118482796544 flops + + Runtime: 8.13237 ms + Memory: 235.431 GiB/s + + Math: 14569.3 GFLOP/s + +``` + [Further details about the CUTLASS Profiler are described here.](media/docs/profiler.md) diff --git a/cmake/CTestTestfile.config.cmake b/cmake/CTestTestfile.config.cmake new file mode 100644 index 000000000..65fda51a7 --- /dev/null +++ b/cmake/CTestTestfile.config.cmake @@ -0,0 +1,19 @@ +# Generated file + +if (DEFINED ENV{CUTLASS_TEST_EXECUTION_ENVIRONMENT}) + set(_CUTLASS_TEST_EXECUTION_ENVIRONMENT $ENV{CUTLASS_TEST_EXECUTION_ENVIRONMENT}) +else() + set(_CUTLASS_TEST_EXECUTION_ENVIRONMENT @CUTLASS_TEST_EXECUTION_ENVIRONMENT@) +endif() + +if (NOT "@TEST_EXE_DIR@" STREQUAL "") + set(TEST_EXE_PATH @TEST_EXE_DIR@/@TEST_EXE@) +else() + set(TEST_EXE_PATH @TEST_EXE@) +endif() + +add_test("@TEST_NAME@" ${_CUTLASS_TEST_EXECUTION_ENVIRONMENT} "${TEST_EXE_PATH}" @TEST_COMMAND_OPTIONS@) + +if (NOT "@TEST_EXE_WORKING_DIRECTORY@" STREQUAL "") + set_tests_properties("@TEST_NAME@" PROPERTIES WORKING_DIRECTORY "@TEST_EXE_WORKING_DIRECTORY@") +endif() diff --git a/cuBLAS.cmake b/cuBLAS.cmake index 4c73a1db4..0ad6db237 100644 --- a/cuBLAS.cmake +++ b/cuBLAS.cmake @@ -1,3 +1,24 @@ +# Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. message(STATUS "Configuring cublas ...") diff --git a/cuDNN.cmake b/cuDNN.cmake new file mode 100644 index 000000000..da5e45313 --- /dev/null +++ b/cuDNN.cmake @@ -0,0 +1,107 @@ + +# Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if(DEFINED CUDNN_ENABLED) + set(CUTLASS_ENABLE_CUDNN ${CUDNN_ENABLED} CACHE BOOL "Enable CUTLASS to build with cuDNN library.") +endif() + +if(DEFINED CUTLASS_ENABLE_CUDNN AND NOT CUTLASS_ENABLE_CUDNN) + return() +endif() + +message(STATUS "Configuring cuDNN ...") + +find_path( + _CUDNN_INCLUDE_DIR cudnn.h + PATHS + ${CUDA_TOOLKIT_ROOT_DIR}/include + $ENV{CUDNN_PATH}/include + $ENV{CUDA_PATH}/include + ${CUDNN_PATH}/include + /usr/include) + +find_library( + _CUDNN_LIBRARY cudnn + HINTS + ${CUDA_TOOLKIT_ROOT_DIR}/lib64 + ${CUDA_TOOLKIT_ROOT_DIR}/lib/x64 + ${CUDA_TOOLKIT_ROOT_DIR}/lib + $ENV{CUDNN_PATH}/lib64 + $ENV{CUDNN_PATH}/lib/x64 + $ENV{CUDNN_PATH}/lib + $ENV{CUDA_PATH}/lib64 + $ENV{CUDA_PATH}/lib/x64 + $ENV{CUDA_PATH}/lib + ${CUDNN_PATH}/lib64 + ${CUDNN_PATH}/lib/x64 + ${CUDNN_PATH}/lib + /usr/lib/x86_64-linux-gnu + /usr/lib) + +if(_CUDNN_INCLUDE_DIR AND _CUDNN_LIBRARY) + + message(STATUS "cuDNN: ${_CUDNN_LIBRARY}") + message(STATUS "cuDNN: ${_CUDNN_INCLUDE_DIR}") + + set(CUDNN_FOUND ON CACHE INTERNAL "cuDNN Library Found") + +else() + + message(STATUS "cuDNN not found.") + set(CUDNN_FOUND OFF CACHE INTERNAL "cuDNN Library Found") + +endif() + +set(CUTLASS_ENABLE_CUDNN ${CUDNN_FOUND} CACHE BOOL "Enable CUTLASS to build with cuDNN library.") + +if (CUTLASS_ENABLE_CUDNN AND NOT TARGET cudnn) + + set(CUDNN_INCLUDE_DIR ${_CUDNN_INCLUDE_DIR}) + set(CUDNN_LIBRARY ${_CUDNN_LIBRARY}) + + if(WIN32) + add_library(cudnn STATIC IMPORTED GLOBAL) + else() + add_library(cudnn SHARED IMPORTED GLOBAL) + endif() + + add_library(nvidia::cudnn ALIAS cudnn) + + set_property( + TARGET cudnn + PROPERTY IMPORTED_LOCATION + ${CUDNN_LIBRARY}) + + target_include_directories( + cudnn + INTERFACE + $ + $) + +endif() + +if(CUTLASS_ENABLE_CUDNN AND NOT CUDNN_FOUND) + message(FATAL_ERROR "CUTLASS_ENABLE_CUDNN enabled but cuDNN library could not be found.") +endif() + +message(STATUS "Configuring cuDNN ... done.") diff --git a/examples/03_visualize_layout/CMakeLists.txt b/examples/03_visualize_layout/CMakeLists.txt index e2bb28348..27a87c929 100644 --- a/examples/03_visualize_layout/CMakeLists.txt +++ b/examples/03_visualize_layout/CMakeLists.txt @@ -20,9 +20,15 @@ # STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +set(TEST_COMMAND_00 RowMajor --extent=16,16) +set(TEST_COMMAND_01 "ColumnMajorInterleaved<4>" --extent=32,8 --output-shape=16 --vectorize=4) + cutlass_example_add_executable( 03_visualize_layout visualize_layout.cpp register_layout.cu + TEST_COMMAND_OPTIONS + TEST_COMMAND_00 + TEST_COMMAND_01 ) diff --git a/examples/03_visualize_layout/visualize_layout.cpp b/examples/03_visualize_layout/visualize_layout.cpp index a0f271812..3c4b783ca 100644 --- a/examples/03_visualize_layout/visualize_layout.cpp +++ b/examples/03_visualize_layout/visualize_layout.cpp @@ -32,6 +32,8 @@ #include #include +#include + #include "options.h" #include "register_layout.h" @@ -133,6 +135,8 @@ int main(int argc, char const *arg[]) { layout_it->second->print_csv(std::cout); + cudaFree(0); // Ensure CUDA is available. + return 0; } diff --git a/examples/08_turing_tensorop_gemm/turing_tensorop_gemm.cu b/examples/08_turing_tensorop_gemm/turing_tensorop_gemm.cu index d18a4e6ab..36f794d92 100644 --- a/examples/08_turing_tensorop_gemm/turing_tensorop_gemm.cu +++ b/examples/08_turing_tensorop_gemm/turing_tensorop_gemm.cu @@ -188,31 +188,6 @@ using Gemm = cutlass::gemm::device::Gemm 10 || (__CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 2))) { - std::cerr << "Turing Tensor Core operations must be compiled with CUDA 10.2 Toolkit or later." << std::endl; - return -1; - } - - cudaDeviceProp props; - - cudaError_t error = cudaGetDeviceProperties(&props, 0); - if (error != cudaSuccess) { - std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; - return -1; - } - - if (!((props.major * 10 + props.minor) >= 75)) { - std::cerr << "Turing Tensor Core operations must be run on a machine with compute capability at least 75." - << std::endl; - - // Return 0 so tests are considered passing if run on unsupported platforms. - return 0; - } - const int length_m = 5120; const int length_n = 4096; const int length_k = 4096; @@ -337,18 +312,37 @@ int run() { } int main() { + bool notSupported = false; + // Turing Tensor Core operations exposed with mma.sync and ldmatrix are first available // in CUDA 10.2. // // CUTLASS must be compiled with CUDA 10.2 Toolkit to run these examples. if (!(__CUDACC_VER_MAJOR__ > 10 || (__CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 2))) { std::cerr << "Turing Tensor Core operations must be compiled with CUDA 10.2 Toolkit or later." << std::endl; + notSupported = true; + } - // Returning zero so this test passes when built on older Toolkits. + cudaDeviceProp props; + + cudaError_t error = cudaGetDeviceProperties(&props, 0); + if (error != cudaSuccess) { + std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; + return -1; + } + + if (!((props.major * 10 + props.minor) >= 75)) { + std::cerr << "Turing Tensor Core operations must be run on a machine with compute capability at least 75." + << std::endl; + + notSupported = true; + } + + if (notSupported) { + // Returning zero so this test passes on older Toolkits. Its actions are no-op. return 0; } - else { - return run(); - } + + return run(); } diff --git a/examples/09_turing_tensorop_conv2dfprop/CMakeLists.txt b/examples/09_turing_tensorop_conv2dfprop/CMakeLists.txt new file mode 100644 index 000000000..b1b5c8df1 --- /dev/null +++ b/examples/09_turing_tensorop_conv2dfprop/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +cutlass_example_add_executable( + 09_turing_tensorop_conv2dfprop + turing_tensorop_conv2dfprop.cu + ) + diff --git a/examples/09_turing_tensorop_conv2dfprop/turing_tensorop_conv2dfprop.cu b/examples/09_turing_tensorop_conv2dfprop/turing_tensorop_conv2dfprop.cu new file mode 100644 index 000000000..cf07efdcb --- /dev/null +++ b/examples/09_turing_tensorop_conv2dfprop/turing_tensorop_conv2dfprop.cu @@ -0,0 +1,758 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/** + + +This example shows how to run convolution kernels using functions and data structures +provided by CUTLASS using tensor cores; which we run on a NVIDIA Turing GPU. + +Writing a single high performance convolution kernel is hard but do-able. Whereas writing +high performance kernels at scale which works for multiple problem sizes with good abstractions is +really hard. CUTLASS solves this problem by providing simplified abstractions to compose +multiple sections of implicit gemm kernel. When used properly, the kernels can hit peak performance +of GPU easily. + +CUTLASS divides a kernel into hierarchical composable sections. Which means, at each thread, warp +and thread-block level, they compute on their own tile-size with higher level of tile sizes being +composed from lower level ones. Multiple thread-tiles (tile size each thread computes) can be used +to form warp-tiles (tile size each warp computes) and multiple warp tiles can be used to compute +threadblock-tile (tile size computed by a threadblock). + +In thie example, we split variable initialization into +1. Setting up data properties : describes how tensors are laid out in the memory and how the kernel +can view them (logical to physical mapping) +2. Setting up computation properties : describes how the above set tensors will be used to compute +output of convolution. + +First, we setup the data types of the input tensor A, weights' tensor B and output tensor C along +with alpha, beta as the equation for convolution is C = alpha * Conv(A, B) + beta * C. In CUTLASS, +the kernels first compute Conv(A, B) and leave the rest of the computation to end of the kernel as +alpha * X + beta * C is a simple element-wise operation on X (Conv(A, B)) and C. We call this as +epilogue of kernel. Hence, we setup data types for alpha and beta to be equal to +ElementComputeEpilogue = float. We want to use MMA instructions on Turing and they support 4-bit +signed integer. But int4b_t is not fully supported by Nvidia software stack, so CUTLASS introduces +cutlass::int4b_t. We use the data type for elements in input tensor A and B as cutlass::int4b_t. We +convey this to CUTLASS kernel by initializing template variables ElementAccumulator (int32_t), +ElementComputeEpilogue (float), ElementInputA (cutlass::int4b_t), ElementInputB (cutlass::int4b_t), +ElementOutput (int32_t). Communicating just the data type is not enough. As the data is laid out +linearly in memory, we have to convey the layout of tensors. We do that by initializing template +variables LayoutInputA, LayoutInputB and LayoutOutput to TensorNHWC cutlass variable. Next, we setup +rules to comptue alpha * X + beta * C which is called epilogue of the kernel. We initialize template +variable EpilogueOp, which takes the data type of output ElementOutput (int32_t), the number of +elements per vector memory access (32), data type of accumulator (int32_t) and data type of +computation of linear combination (alpha * X + beta * C). + +Now that we setup the properties of data, we have to setup properties of computation. + +Second, we create template variables of tile sizes for thread-block, warp and mma-op to 128x128x128, +64x64x128, 8x8x32 (MxNxK) respectively. When passed to instantiate CUTLASS Implicit GEMM kernel, it +internally deduces the amount of threads needed per thread-block, amount of shared memory, storing +data in bank-conflict free manner, and ton of other variables required to compose, intialize and +launch a high performance Implicit GEMM kernel. This is the beauty of CUTLASS, it relieves developer +from understanding and coding complicated hardware optimizations which can easily go wrong. + +CUTLASS also supports multiple MMA pipelines in a threadblock. What are MMA pipelines? MMA pipelines +constitute the whole process of loading input data from global memory to shared memory, loading data +from shared memory to registers, doing matrix multiplication, store to global memory. The below flow +sequence shows a typical mma pipeline. + +tensor in global memory -> registers -> tile in shared memory -> registers -> mma -> registers -> +output to global memory + +The problem with single pipeline is, each stage is synchronous which means, each stage has to wait +until the previous finished executing. There are stages in the pipeline which do not have fixed +latency, for example, the loads from global memory and shared memory. Therefore, we can add one more +pipeline with a phase shift in mma kernel to hide latency from global and shared memory loads. +Finally, the pipeline in a kernel looks like + +(1) tensor in global memory -> (2) registers -> (3) tile in shared memory -> (4) registers -> (5) +mma -> (6) registers -> (7) output to global memory (1) -> (2) -> (3) tensor in global +memory -> (4) registers -> (5) tile in shared memory -> (6) registers -> (7) mma -> (8) registers -> +(9) output to global memory + +This way, you can hide the second global memory load latency by doing computation on already loaded +input data. + +There are few more template variables initialized such as, which threadblock tile of output matrix +is done which threadblock launched on an SM, CUDA SM architecture of GPU you want to run on. + +These are all put together to create a template variable which describes CUTLASS Implicit GEMM +kernel using cutlass::conv::device::ImplicitGemm template. + +The next step is to intialize physical data, instantiate and initialize CUTLASS kernel and run it. +We use CUTLASS utilities to initialize, fill, compare tensors as they are simple and doesn't come +in the way of learning CUTLASS. + +Once all the tensors are initialized and filled with data, create arguments tuple to launch CUTLASS +kernel which takes problem size (N = 1, H = 64, W = 64, C = 128), filter size (K = 64, +R = 3, S = 3, C = 128 ), padding, strides, dilation, tensors, alpha, beta and the +important one, split k-dimension factor. Along with that, we query CUTLASS if any scratch-space +memory required by the kernel we instantiated. If yes, we create it and pass it along with other +arguments created to intialize CUTLASS kernel then, the kernel is launched. + +In this example, we later on launch a reference convolution kernel (from CUTLASS utilities) to +compare if the output from CUTLASS kernel is same as the reference implicit GEMM kernel. +*/ + +#include +#include + +#include "cutlass/cutlass.h" +#include "cutlass/gemm/device/gemm.h" +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "cutlass/util/command_line.h" +#include "cutlass/util/host_tensor.h" +#include "cutlass/util/tensor_view_io.h" +#include "cutlass/util/reference/device/gemm.h" +#include "cutlass/util/reference/host/tensor_compare.h" +#include "cutlass/util/reference/host/tensor_copy.h" +#include "cutlass/util/reference/host/tensor_fill.h" +#include "cutlass/util/reference/host/convolution.h" +#include "cutlass/util/tensor_view_io.h" + +#include "helper.h" + +// The code section below describes datatype for input, output tensors and computation between +// elements +using ElementAccumulator = int32_t; // Data type of accumulator +using ElementComputeEpilogue = float; // Data type of epilogue computation (alpha, beta) +using ElementInputA = cutlass::int4b_t; // Data type of elements in input tensor +using ElementInputB = cutlass::int4b_t; // Data type of elements in input tensor +using ElementOutput = cutlass::int4b_t; // Data type of elements in output tensor + +using LayoutInputA = cutlass::layout::TensorNHWC; +using LayoutInputB = cutlass::layout::TensorNHWC; +using LayoutOutput = cutlass::layout::TensorNHWC; + +// This code section describes whether you want to use tensor cores or regular SIMT cores on GPU SM +using MMAOp = cutlass::arch::OpClassTensorOp; + +// This code section describes CUDA SM architecture number +using SmArch = cutlass::arch::Sm75; + +// This code section describes the tile size a thread block will compute +using ThreadblockShape = cutlass::gemm::GemmShape<128, 128, 128>; // Threadblock tile shape + +// This code section describes tile size a warp will compute +using WarpShape = cutlass::gemm::GemmShape<64, 64, 128>; // Warp tile shape + +// This code section describes the size of MMA op +using InstructionShape = cutlass::gemm::GemmShape<8, 8, 32>; // TensorCore instruction shape + +// This code section describes how threadblocks are scheduled on GPU +using SwizzleThreadBlock = cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>; + +// Number of pipelines you want to use +constexpr int NumStages = 2; + +// This code section describes the epilogue part of the kernel, we use default value +using EpilogueOp = cutlass::epilogue::thread::LinearCombinationClamp< + ElementOutput, // Data type of output matrix. + 8, // The number of elements per vectorized. + // memory access. This becomes the vector width of + // math instructions in the epilogue too. + ElementAccumulator, // Data type of accumulator + ElementComputeEpilogue>; // Data type for alpha/beta in linear combination + + +using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementInputA, LayoutInputA, + ElementInputB, LayoutInputB, + ElementOutput, LayoutOutput, + ElementAccumulator, + MMAOp, + SmArch, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOp, + SwizzleThreadBlock, + NumStages, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic +>::Kernel; + +using ImplicitGemm = cutlass::conv::device::ImplicitGemmConvolution; + + +///////////////////////////////////////////////////////////////////////////////////////////////// + +// Command line options parsing +struct Options { + + bool help; + cutlass::Tensor4DCoord input_size; + cutlass::Tensor4DCoord filter_size; + cutlass::Tensor4DCoord padding; + cutlass::MatrixCoord conv_stride; + cutlass::MatrixCoord dilation; + bool reference_check; + bool measure_performance; + int iterations; + bool save_workspace; + ElementComputeEpilogue alpha; + ElementComputeEpilogue beta; + bool benchmark; + std::string tag; + + Options(): + help(false), + input_size(1, 32, 32, 32), + filter_size(32, 3, 3, 32), + padding(1, 1, 1, 1), + conv_stride(1, 1), + dilation(1, 1), + reference_check(false), + measure_performance(true), + iterations(20), + save_workspace(false), + alpha(1), + beta(0), + benchmark(false) { } + + // Verify the problem size is compatible with the CUTLASS Convolution implementation. + bool valid() { + + // + // CUTLASS attempts to load 128b vectors of int4b_t elements. Consequently, + // all pointers, strides, and tensor extents must be divisible by 32 elements. + // + int const kAlignment = 32; + + if ((input_size.c() % kAlignment) || + (filter_size.n() % kAlignment)) { + + // misaligned tensors + return false; + } + + // Invalid padding + if ((padding.h() != filter_size.h() / 2) || + (padding.w() != filter_size.w() / 2)) { + + return false; + } + + return true; + } + + /// Updates input and filter sizes + void update( + cutlass::Tensor4DCoord input_size, + cutlass::Tensor4DCoord filter_size) { + + this->input_size = input_size; + this->filter_size = filter_size; + + padding.n() = filter_size.h() / 2; + padding.h() = filter_size.h() / 2; + padding.w() = filter_size.w() / 2; + padding.c() = filter_size.w() / 2; + } + + // Parses the command line + void parse(int argc, char const **args) { + cutlass::CommandLine cmd(argc, args); + + if (cmd.check_cmd_line_flag("help")) { + help = true; + } + + if (cmd.check_cmd_line_flag("ref-check")) { + reference_check = true; + } + + if (cmd.check_cmd_line_flag("perf-check")) { + measure_performance = true; + } + + if (cmd.check_cmd_line_flag("save-workspace")) { + save_workspace = true; + } + + if (cmd.check_cmd_line_flag("benchmark")) { + benchmark = true; + } + + cmd.get_cmd_line_argument("n", input_size.n()); + cmd.get_cmd_line_argument("h", input_size.h()); + cmd.get_cmd_line_argument("w", input_size.w()); + cmd.get_cmd_line_argument("c", input_size.c()); + + cmd.get_cmd_line_argument("k", filter_size.n()); + cmd.get_cmd_line_argument("r", filter_size.h()); + cmd.get_cmd_line_argument("s", filter_size.w()); + filter_size.c() = input_size.c(); + + cmd.get_cmd_line_argument("alpha", alpha); + cmd.get_cmd_line_argument("beta", beta); + + cmd.get_cmd_line_argument("iterations", iterations); + cmd.get_cmd_line_argument("tag", tag); + + if (filter_size.h() == 3 && filter_size.w() == 3) { + padding = {1, 1, 1, 1}; + } + else { + filter_size.h() = 1; + filter_size.w() = 1; + padding = {0, 0, 0, 0}; + } + } + + /// Prints the usage statement. + std::ostream & print_usage(std::ostream &out) const { + + out << "09_turing_tensorop_conv2dfprop example\n\n" + << " This example uses Turing's Tensor Core operators on int4 data types to compute\n" + << " forward convolution on tensors of layout NHWC.\n\n" + << "Options:\n\n" + << " --help If specified, displays this usage statement.\n\n" + << " --n Input tensor extent N\n" + << " --h Input tensor extent H\n" + << " --w Input tensor extent W\n" + << " --c Input tensor extent C\n" + << " --k Filter extent K\n" + << " --r Filter extent R\n" + << " --s Filter extent S\n\n" + << " --alpha Epilogue scalar alpha\n" + << " --beta Epilogue scalar beta\n\n" + << " --ref-check If set (true), reference check on the host is computed\n" + << " --perf-check If set (true), performance is measured.\n" + << " --benchmark If set (true), performance benchmarking on several layers and batch-size.\n" + << " --iterations Number of profiling iterations to perform.\n" + << " --save-workspace If set, workspace is written to a text file.\n" + << " --tag String to replicate across the first column in the results table\n"; + + out << "\n\nExamples:\n\n" + << "$ ./examples/09_turing_tensorop_conv2dfprop/09_turing_tensorop_conv2dfprop --n=32 --h=224 --w=224 --c=128 --k=256 --r=1 --s=1\n\n" + << "$ ./examples/09_turing_tensorop_conv2dfprop/09_turing_tensorop_conv2dfprop --n=1 --h=224 --w=224 --c=32 --k=32 --r=3 --s=3 --ref-check\n\n"; + + return out; + } + + /// Computes the output tensor size (NPQK) + cutlass::Tensor4DCoord output_size() const { + return cutlass::Tensor4DCoord( + input_size.n(), + (input_size.h() + padding.n() + padding.h() - filter_size.h()) / conv_stride.row() + 1, + (input_size.w() + padding.w() + padding.c() - filter_size.w()) / conv_stride.column() + 1, + filter_size.n()); + } + + /// Compute performance in GFLOP/s + double gflops(double runtime_s) const { + + // Number of multiply-adds = NPQK * CRS + int64_t fmas = output_size().product() * int64_t(filter_size.h() * filter_size.w() * filter_size.c()); + + // Two flops per multiply-add + return 2.0 * double(fmas) / double(1.0e9) / runtime_s; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +struct Result { + double runtime_ms; + double gflops; + cutlass::Status status; + cutlass::Status reference_check; + cudaError_t error; + + Result(): + runtime_ms(0), + gflops(0), + status(cutlass::Status::kSuccess), + reference_check(cutlass::Status::kInvalid), + error(cudaSuccess) { } + + static std::ostream & print_header(std::ostream &out, Options const &options) { + + if (!options.tag.empty()) { + out << "Name,"; + } + + out << "Layer,N,H,W,C,K,R,S,Runtime,GFLOPs"; + + return out; + } + + std::ostream & print(std::ostream &out, int idx, Options const &options) { + + if (!options.tag.empty()) { + out << options.tag << ","; + } + + out + << "conv_" << idx << "," + << options.input_size.n() << "," + << options.input_size.h() << "," + << options.input_size.w() << "," + << options.input_size.c() << "," + << options.filter_size.n() << "," + << options.filter_size.h() << "," + << options.filter_size.w() << "," + << runtime_ms << "," + << gflops; + + return out; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Runs one benchmark +Result profile_convolution(Options const &options) { + + Result result; + + // + // Allocate host-device tensors using the CUTLASS Utilities. + // + + cutlass::HostTensor tensor_a(options.input_size); + cutlass::HostTensor tensor_b(options.filter_size); + cutlass::HostTensor tensor_c(options.output_size()); + cutlass::HostTensor tensor_ref_c(options.output_size()); + + // + // Initialize tensors + // + + // Fill tensor A on host with uniform-distribution random data + cutlass::reference::host::TensorFillRandomUniform( + tensor_a.host_view(), + 1, + ElementInputA(7), + ElementInputA(-8), + 0); + + // Fill tensor B on host with uniform-distribution random data + cutlass::reference::host::TensorFillRandomUniform( + tensor_b.host_view(), + 1, + ElementInputB(7), + ElementInputB(-8), + 0); + + // Fill tensor C on host with zeros + cutlass::reference::host::TensorFill( + tensor_c.host_view()); + + // Fill tensor C for reference on host with zeros + cutlass::reference::host::TensorFill( + tensor_ref_c.host_view()); + + // Copy data from host to GPU + tensor_a.sync_device(); + tensor_b.sync_device(); + tensor_c.sync_device(); + tensor_ref_c.sync_device(); + + // + // Define arguments for CUTLASS Convolution + // + + // mode (kCrossCorrelation or kConvolution) + cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation; + + // Split K dimension into 1 partitions + int split_k_slices = 1; + + cutlass::conv::Conv2dProblemSize problem_size( + options.input_size, + options.filter_size, + options.padding, + options.conv_stride, + options.dilation, + options.output_size(), + mode, + split_k_slices); + + typename ImplicitGemm::Arguments arguments{ + problem_size, + tensor_a.device_ref(), + tensor_b.device_ref(), + tensor_c.device_ref(), + tensor_c.device_ref(), + {options.alpha, options.beta}, + }; + + // + // Initialize CUTLASS Convolution + // + + ImplicitGemm implicit_gemm_op; + + size_t workspace_size = implicit_gemm_op.get_workspace_size(arguments); + + // Allocate workspace memory + cutlass::device_memory::allocation workspace(workspace_size); + + result.status = implicit_gemm_op.initialize(arguments, workspace.get()); + CUTLASS_CHECK(result.status); + + // + // Launch initialized CUTLASS kernel + // + result.status = implicit_gemm_op(); + + CUTLASS_CHECK(result.status); + + // + // Optional reference check + // + + if (options.reference_check) { + std::cout << "Verification on host...\n"; + + // Compute with reference implementation + cutlass::reference::host::Conv2dFprop< + ElementInputA, + LayoutInputA, + ElementInputB, + LayoutInputB, + ElementOutput, + LayoutOutput, + ElementComputeEpilogue, + ElementAccumulator, + cutlass::NumericConverterClamp + >( + problem_size, + tensor_a.host_ref(), + tensor_b.host_ref(), + tensor_c.host_ref(), + tensor_ref_c.host_ref(), + options.alpha, + options.beta + ); + + // Check if output from CUTLASS kernel and reference kernel are equal or not + tensor_c.sync_host(); + + bool passed = cutlass::reference::host::TensorEquals( + tensor_c.host_view(), + tensor_ref_c.host_view()); + + if (!passed) { + result.reference_check = cutlass::Status::kErrorInternal; + std::cout << "ERROR - results miscompared.\n"; + } + else { + result.reference_check = cutlass::Status::kSuccess; + std::cout << "Passed.\n"; + } + } + else { + result.reference_check = cutlass::Status::kInvalid; + } + + if (options.save_workspace) { + + std::stringstream ss; + + ss << "09_tensor_conv_workspace_conv2dfprop_" + << options.input_size.n() << "x" << options.input_size.h() << "x" << options.input_size.w() << "x" << options.input_size.c() + << "_" + << options.filter_size.n() << "x" << options.filter_size.h() << "x" << options.filter_size.w() << "x" << options.filter_size.c() + << ".dat"; + + std::ofstream output_workspace(ss.str()); + + output_workspace + << "Input = \n" << tensor_a.host_view() << "\n\n" + << "Filters = \n" << tensor_b.host_view() << "\n\n"; + + if (options.reference_check) { + output_workspace << "Reference = \n" << tensor_ref_c.host_view() << "\n\n"; + } + + output_workspace << "Computed = \n" << tensor_c.host_view() << std::endl; + + std::cout << "Results written to '" << ss.str() << "'." << std::endl; + } + + // + // Performance measurement + // + + if (options.measure_performance) { + + cudaEvent_t events[2]; + + for (auto & event : events) { + result.error = cudaEventCreate(&event); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventCreate() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + } + + // Record an event at the start of a series of convolution operations. + result.error = cudaEventRecord(events[0]); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventRecord() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + + // Launch a sequence of implicit GEMM operations on the device + for (int iteration = 0; iteration < options.iterations; ++iteration) { + result.status = implicit_gemm_op(); + CUTLASS_CHECK(result.status); + } + + // Record an event when the convolutions have been launched. + result.error = cudaEventRecord(events[1]); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventRecord() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + + // Wait for work on the device to complete. + result.error = cudaEventSynchronize(events[1]); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventSynchronize() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + + // Measure elapsed runtime + float runtime_ms = 0; + result.error = cudaEventElapsedTime(&runtime_ms, events[0], events[1]); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventElapsed() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + + // Print average runtime and GFLOPs. + result.runtime_ms = double(runtime_ms) / double(options.iterations); + result.gflops = options.gflops(result.runtime_ms / 1000.0); + + // Cleanup + for (auto event : events) { + (void)cudaEventDestroy(event); + } + } + + return result; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char const **args) { + + // Turing Tensor Core operations exposed with mma.sync are first available in CUDA 10.2. + // + // CUTLASS must be compiled with CUDA 10.2 Toolkit to run these examples. + if (!(__CUDACC_VER_MAJOR__ > 10 || (__CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 2))) { + std::cerr << "Turing Tensor Core operations must be compiled with CUDA 10.2 Toolkit or later." << std::endl; + return 0; + } + + cudaDeviceProp props; + CUDA_CHECK(cudaGetDeviceProperties(&props, 0)); + + if (!(props.major > 7 || (props.major == 7 && props.minor >= 5))) { + std::cerr << "Turing Tensor Ops must be run on a machine with compute capability at least 75." + << std::endl; + return 0; + } + + Options options; + + options.parse(argc, args); + + if (options.help) { + options.print_usage(std::cout) << std::endl; + return 0; + } + + if (options.benchmark) { + // Benchmark several layers + + int batch_sizes[] = {1, 32, 64, 128, 256, 512}; + + struct Benchmark { + int h, w, c, k, r, s; + } layers[] = { + {56, 56, 64, 256, 1, 1}, + {56, 56, 64, 64, 1, 1}, + {56, 56, 64, 64, 3, 3}, + {56, 56, 256, 64, 1, 1}, + {56, 56, 256, 512, 1, 1}, + {56, 56, 256, 128, 1, 1}, + {28, 28, 128, 128, 3, 3}, + {28, 28, 128, 512, 1, 1}, + {28, 28, 512, 128, 1, 1}, + {28, 28, 512, 1024, 1, 1}, + {28, 28, 512, 256, 1, 1}, + {14, 14, 256, 256, 3, 3}, + {14, 14, 256, 1024, 1, 1}, + {14, 14, 1024, 256, 1, 1}, + {14, 14, 1024, 2048, 1, 1}, + {14, 14, 1024, 512, 1, 1}, + {7, 7, 512, 512, 3, 3}, + }; + + Result::print_header(std::cout, options) << std::endl; + + int idx = 1; + + for (auto const &layer : layers) { + for (auto N : batch_sizes) { + + options.update({N, layer.h, layer.w, layer.c}, {layer.k, layer.r, layer.s, layer.c}); + + Result result = profile_convolution(options); + result.print(std::cout, idx, options) << std::endl; + } + + ++idx; + } + } + else { + + // Execute one problem size + if (!options.valid()) { + std::cerr << "Invalid problem." << std::endl; + return -1; + } + + Result result = profile_convolution(options); + + Result::print_header(std::cout, options) << std::endl; + result.print(std::cout, 1, options) << std::endl; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + + + diff --git a/examples/12_gemm_bias_relu/gemm_bias_relu.cu b/examples/12_gemm_bias_relu/gemm_bias_relu.cu index 1f83a61af..2b5c779bc 100644 --- a/examples/12_gemm_bias_relu/gemm_bias_relu.cu +++ b/examples/12_gemm_bias_relu/gemm_bias_relu.cu @@ -106,21 +106,6 @@ using Gemm = cutlass::gemm::device::Gemm= 75)) { - std::cerr << "Turing Tensor Ops must be run on a machine with compute capability at least 75." - << std::endl; - // Returning zero so this test passes on older Toolkits. Its actions are no-op. - return 0; - } - const int length_m = 5120; const int length_n = 4096; const int length_k = 4096; @@ -265,17 +250,36 @@ int run() { } int main() { + + bool notSupported = false; + // Turing Tensor Core operations exposed with mma.sync are first available in CUDA 10.2. // // CUTLASS must be compiled with CUDA 10.1 Toolkit to run these examples. if (!(__CUDACC_VER_MAJOR__ > 10 || (__CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 2))) { std::cerr << "Turing Tensor Core operations must be compiled with CUDA 10.2 Toolkit or later." << std::endl; + notSupported = true; + } + cudaDeviceProp props; + + cudaError_t error = cudaGetDeviceProperties(&props, 0); + if (error != cudaSuccess) { + std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; + return -1; + } + + if (!(props.major * 10 + props.minor >= 75)) { + std::cerr << "Turing Tensor Ops must be run on a machine with compute capability at least 75." + << std::endl; + notSupported = true; + } + + if (notSupported) { // Returning zero so this test passes on older Toolkits. Its actions are no-op. return 0; } - else { - return run(); - } + + return run(); } diff --git a/examples/13_fused_two_gemms/fused_gemm.cu b/examples/13_fused_two_gemms/fused_gemm.cu index edc08d318..b96a0ef09 100644 --- a/examples/13_fused_two_gemms/fused_gemm.cu +++ b/examples/13_fused_two_gemms/fused_gemm.cu @@ -55,22 +55,6 @@ Performance: int run() { - cudaDeviceProp props; - - cudaError_t error = cudaGetDeviceProperties(&props, 0); - if (error != cudaSuccess) { - std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; - return -1; - } - - if (!(props.major * 10 + props.minor >= 75)) { - std::cerr << "Turing Tensor Ops must be run on a machine with compute capability at least 75." - << std::endl; - - // Returning zero so this test passes on older Toolkits. Its actions are no-op. - return 0; - } - #if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) run_nonfused_gemm_s8_sm80(); run_fused_gemm_s8_sm80(); @@ -85,17 +69,38 @@ int run() { } int main() { + + bool notSupported = false; + // Turing Tensor Core operations exposed with mma.sync are first available in CUDA 10.2. // // CUTLASS must be compiled with CUDA 10.1 Toolkit to run these examples. if (!(__CUDACC_VER_MAJOR__ > 10 || (__CUDACC_VER_MAJOR__ == 10 && __CUDACC_VER_MINOR__ >= 2))) { std::cerr << "Turing Tensor Core operations must be compiled with CUDA 10.2 Toolkit or later." << std::endl; + notSupported = true; + } + + cudaDeviceProp props; + + cudaError_t error = cudaGetDeviceProperties(&props, 0); + if (error != cudaSuccess) { + std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; + return -1; + } + + if (!(props.major * 10 + props.minor >= 75)) { + std::cerr << "Turing Tensor Ops must be run on a machine with compute capability at least 75." + << std::endl; + + notSupported = true; + } + + if (notSupported) { // Returning zero so this test passes on older Toolkits. Its actions are no-op. return 0; } - else { - return run(); - } + + return run(); } diff --git a/examples/13_fused_two_gemms/kernel/b2b_gemm.h b/examples/13_fused_two_gemms/kernel/b2b_gemm.h index 5df5e4e38..a67b1e877 100644 --- a/examples/13_fused_two_gemms/kernel/b2b_gemm.h +++ b/examples/13_fused_two_gemms/kernel/b2b_gemm.h @@ -335,7 +335,7 @@ struct B2bGemm { semaphore.fetch(); // Indicate which position in a serial reduction the output operator is currently updating - output_op_1.set_k_partition(threadblock_tile_offset.k()); + output_op_1.set_k_partition(threadblock_tile_offset.k(), params.grid_tiled_shape.k()); } // Tile iterator loading from source tensor. diff --git a/examples/14_ampere_tf32_tensorop_gemm/ampere_tf32_tensorop_gemm.cu b/examples/14_ampere_tf32_tensorop_gemm/ampere_tf32_tensorop_gemm.cu index 253355713..84eadc5ea 100644 --- a/examples/14_ampere_tf32_tensorop_gemm/ampere_tf32_tensorop_gemm.cu +++ b/examples/14_ampere_tf32_tensorop_gemm/ampere_tf32_tensorop_gemm.cu @@ -113,31 +113,6 @@ using Gemm = cutlass::gemm::device::Gemm= 11)) { - std::cerr << "Ampere Tensor Core operations must be compiled with CUDA 11.0 Toolkit or later." << std::endl; - return -1; - } - - cudaDeviceProp props; - - cudaError_t error = cudaGetDeviceProperties(&props, 0); - if (error != cudaSuccess) { - std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; - return -1; - } - - if (!((props.major * 10 + props.minor) >= 80)) { - std::cerr << "Turing Tensor Core operations must be run on a machine with compute capability at least 80." - << std::endl; - - // Return 0 so tests are considered passing if run on unsupported platforms. - return 0; - } - const int length_m = 5120; const int length_n = 4096; const int length_k = 4096; @@ -262,17 +237,36 @@ int run() { } int main() { + + bool notSupported = false; + // Ampere Tensor Core operations exposed with mma.sync and ldmatrix are first available // in CUDA 11.0. // // CUTLASS must be compiled with CUDA 11.0 Toolkit to run these examples. if (!(__CUDACC_VER_MAJOR__ >= 11)) { std::cerr << "Ampere Tensor Core operations must be compiled with CUDA 11.0 Toolkit or later." << std::endl; + notSupported = true; + } - // Returning zero so this test passes when built on older Toolkits. + cudaDeviceProp props; + + cudaError_t error = cudaGetDeviceProperties(&props, 0); + if (error != cudaSuccess) { + std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; + return -1; + } + + if (!((props.major * 10 + props.minor) >= 80)) { + std::cerr << "Turing Tensor Core operations must be run on a machine with compute capability at least 80." + << std::endl; + notSupported = true; + } + + if (notSupported) { + // Returning zero so this test passes on older Toolkits. Its actions are no-op. return 0; } - else { - return run(); - } + + return run(); } diff --git a/examples/15_ampere_sparse_tensorop_gemm/ampere_sparse_tensorop_gemm.cu b/examples/15_ampere_sparse_tensorop_gemm/ampere_sparse_tensorop_gemm.cu index 02f65b199..1b233c488 100644 --- a/examples/15_ampere_sparse_tensorop_gemm/ampere_sparse_tensorop_gemm.cu +++ b/examples/15_ampere_sparse_tensorop_gemm/ampere_sparse_tensorop_gemm.cu @@ -71,7 +71,7 @@ using SmArch = cutlass::arch::Sm80; // This code section describes the tile size a thread block will compute using ShapeMMAThreadBlock = - cutlass::gemm::GemmShape<256, 128, 256>; // <- threadblock tile M = 128, N = 128, K = 256 + cutlass::gemm::GemmShape<128, 128, 256>; // <- threadblock tile M = 128, N = 128, K = 256 // This code section describes tile size a warp will compute using ShapeMMAWarp = cutlass::gemm::GemmShape<64, 64, 256>; // <- warp tile M = 64, N = 64, K = 256 // This code section describes the size of MMA op @@ -123,31 +123,6 @@ constexpr int kMetaSizeInBits = Gemm::kMetaSizeInBits; int run() { - // Ampere Sparse Tensor Core operations exposed with mma.sync and ldmatrix are first available - // in CUDA 11.1. - // - // CUTLASS must be compiled with CUDA 11.1 Toolkit to run these examples. - if (!(__CUDACC_VER_MAJOR__ > 11 || (__CUDACC_VER_MAJOR__ == 11 && __CUDACC_VER_MINOR__ >= 1))) { - std::cerr << "Ampere Tensor Core operations must be compiled with CUDA 11.1 Toolkit or later." << std::endl; - return -1; - } - - cudaDeviceProp props; - - cudaError_t error = cudaGetDeviceProperties(&props, 0); - if (error != cudaSuccess) { - std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; - return -1; - } - - if (!((props.major * 10 + props.minor) >= 80)) { - std::cerr << "Turing Tensor Core operations must be run on a machine with compute capability at least 80." - << std::endl; - - // Return 0 so tests are considered passing if run on unsupported platforms. - return 0; - } - const int length_m = 512; const int length_n = 512; const int length_k = 1024; @@ -295,17 +270,37 @@ int run() { } int main() { + + bool notSupported = false; + // Ampere Sparse Tensor Core operations exposed with mma.sync and ldmatrix are first available // in CUDA 11.1. // // CUTLASS must be compiled with CUDA 11.1 Toolkit to run these examples. + if (!(__CUDACC_VER_MAJOR__ > 11 || (__CUDACC_VER_MAJOR__ == 11 && __CUDACC_VER_MINOR__ >= 1))) { std::cerr << "Ampere Tensor Core operations must be compiled with CUDA 11.1 Toolkit or later." << std::endl; + notSupported = true; + } - // Returning zero so this test passes when built on older Toolkits. + cudaDeviceProp props; + + cudaError_t error = cudaGetDeviceProperties(&props, 0); + if (error != cudaSuccess) { + std::cerr << "cudaGetDeviceProperties() returned an error: " << cudaGetErrorString(error) << std::endl; + return -1; + } + + if (!((props.major * 10 + props.minor) >= 80)) { + std::cerr << "Ampere Tensor Core operations must be run on a machine with compute capability at least 80." + << std::endl; + notSupported = true; + } + + if (notSupported) { + // Returning zero so this test passes on older Toolkits. Its actions are no-op. return 0; } - else { - return run(); - } + + return run(); } diff --git a/examples/22_ampere_tensorop_conv2dfprop/CMakeLists.txt b/examples/22_ampere_tensorop_conv2dfprop/CMakeLists.txt new file mode 100644 index 000000000..1b7daac3d --- /dev/null +++ b/examples/22_ampere_tensorop_conv2dfprop/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +cutlass_example_add_executable( + 22_ampere_tensorop_conv2dfprop + ampere_tensorop_conv2dfprop.cu + ) + diff --git a/examples/22_ampere_tensorop_conv2dfprop/ampere_tensorop_conv2dfprop.cu b/examples/22_ampere_tensorop_conv2dfprop/ampere_tensorop_conv2dfprop.cu new file mode 100644 index 000000000..cb7c39866 --- /dev/null +++ b/examples/22_ampere_tensorop_conv2dfprop/ampere_tensorop_conv2dfprop.cu @@ -0,0 +1,763 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/** + +This example shows how to run convolution kernels using functions and data structures +provided by CUTLASS using tensor cores; which we run on a NVIDIA Ampere GPU. + +Writing a single high performance convolution kernel is hard but do-able. Whereas writing +high performance kernels at scale which works for multiple problem sizes with good abstractions is +really hard. CUTLASS solves this problem by providing simplified abstractions to compose +multiple sections of implicit gemm kernel. When used properly, the kernels can hit peak performance +of GPU easily. + +CUTLASS divides a kernel into hierarchical composable sections. Which means, at each thread, warp +and thread-block level, they compute on their own tile-size with higher level of tile sizes being +composed from lower level ones. Multiple thread-tiles (tile size each thread computes) can be used +to form warp-tiles (tile size each warp computes) and multiple warp tiles can be used to compute +threadblock-tile (tile size computed by a threadblock). + +In thie example, we split variable initialization into +1. Setting up data properties : describes how tensors are laid out in the memory and how the kernel +can view them (logical to physical mapping) +2. Setting up computation properties : describes how the above set tensors will be used to compute +output of convolution. + +First, we setup the data types of the input tensor A, weights' tensor B and output tensor C along +with alpha, beta as the equation for convolution is C = alpha * Conv2dFprop(A, B) + beta * C. In CUTLASS, +the kernels first compute Conv2dFprop(A, B) and leave the rest of the computation to end of the kernel as +alpha * X + beta * C is a simple element-wise operation on X (Conv2dFprop(A, B)) and C. We call this as +epilogue of kernel. Hence, we setup data types for alpha and beta to be equal to +ElementComputeEpilogue = float. We use the data type for elements in input tensor A and B as +cutlass::half_t. We convey this to CUTLASS kernel by initializing template variables ElementAccumulator (float), +ElementComputeEpilogue (float), ElementInputA (cutlass::half_t), ElementInputB (cutlass::half_t), +ElementOutput (float). Communicating just the data type is not enough. As the data is laid out +linearly in memory, we have to convey the layout of tensors. We do that by initializing template +variables LayoutInputA, LayoutInputB and LayoutOutput to TensorNHWC cutlass variable. Next, we setup +rules to comptue alpha * X + beta * C which is called epilogue of the kernel. We initialize template +variable EpilogueOp, which takes the data type of output ElementOutput (float), the number of +elements per vector memory access (8), data type of accumulator (float) and data type of +computation of linear combination (alpha * X + beta * C). + +Now that we setup the properties of data, we have to setup properties of computation. + +Second, we create template variables of tile sizes for thread-block, warp and mma-op to 128x128x64, +64x64x64, 16x8x16 (MxNxK) respectively. When passed to instantiate CUTLASS Implicit GEMM kernel, it +internally deduces the amount of threads needed per thread-block, amount of shared memory, storing +data in bank-conflict free manner, and ton of other variables required to compose, intialize and +launch a high performance Implicit GEMM kernel. This is the beauty of CUTLASS, it relieves developer +from understanding and coding complicated hardware optimizations which can easily go wrong. + +CUTLASS also supports multiple MMA pipelines in a threadblock. What are MMA pipelines? MMA pipelines +constitute the whole process of loading input data from global memory to shared memory, loading data +from shared memory to registers, doing matrix multiplication, store to global memory. The below flow +sequence shows a typical mma multistage pipeline. +(see include/cutlass/conv/threadblock/implicit_gemm_multistage.h) + +tensor in global memory --cp_async--> tile in shared memory --smem loads--> registers +--mma--> registers --global stores--> output to global memory + +NVIDIA Ampere uses `cp_async` to build multistage software pipeline to better hide latencies. + + +There are few more template variables initialized such as, which threadblock tile of output matrix +is done which threadblock launched on an SM, CUDA SM architecture of GPU you want to run on. + +These are all put together to create a template variable which describes CUTLASS Implicit GEMM +kernel using cutlass::conv::device::ImplicitGemm template. + +The next step is to intialize physical data, instantiate and initialize CUTLASS kernel and run it. +We use CUTLASS utilities to initialize, fill, compare tensors as they are simple and doesn't come +in the way of learning CUTLASS. + +Once all the tensors are initialized and filled with data, create arguments tuple to launch CUTLASS +kernel which takes problem size (N = 1, H = 64, W = 64, C = 128), filter size (K = 64, +R = 3, S = 3, C = 128 ), padding, strides, dilation, tensors, alpha, beta and the +important one, split k-dimension factor. Along with that, we query CUTLASS if any scratch-space +memory required by the kernel we instantiated. If yes, we create it and pass it along with other +arguments created to intialize CUTLASS kernel then, the kernel is launched. + +In this example, we later on launch a reference convolution kernel (from CUTLASS utilities) to +compare if the output from CUTLASS kernel is same as the reference implicit GEMM kernel. +*/ + +#include +#include + +#include "cutlass/cutlass.h" +#include "cutlass/gemm/device/gemm.h" +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "cutlass/util/command_line.h" +#include "cutlass/util/host_tensor.h" +#include "cutlass/util/tensor_view_io.h" +#include "cutlass/util/reference/device/gemm.h" +#include "cutlass/util/reference/host/tensor_compare.h" +#include "cutlass/util/reference/host/tensor_copy.h" +#include "cutlass/util/reference/host/tensor_fill.h" +#include "cutlass/util/reference/host/convolution.h" +#include "cutlass/util/tensor_view_io.h" + +#include "helper.h" + +// The code section below describes datatype for input, output tensors and computation between +// elements +using ElementAccumulator = float; // Data type of accumulator +using ElementComputeEpilogue = float; // Data type of epilogue computation (alpha, beta) +using ElementInputA = cutlass::half_t; // Data type of elements in input tensor +using ElementInputB = cutlass::half_t; // Data type of elements in input tensor +using ElementOutput = float; // Data type of elements in output tensor + +using LayoutInputA = cutlass::layout::TensorNHWC; +using LayoutInputB = cutlass::layout::TensorNHWC; +using LayoutOutput = cutlass::layout::TensorNHWC; + +// This code section describes whether you want to use tensor cores or regular SIMT cores on GPU SM +using MMAOp = cutlass::arch::OpClassTensorOp; + +// This code section describes CUDA SM architecture number +using SmArch = cutlass::arch::Sm80; + +// This code section describes the tile size a thread block will compute +using ThreadblockShape = cutlass::gemm::GemmShape<128, 128, 64>; // Threadblock tile shape + +// This code section describes tile size a warp will compute +using WarpShape = cutlass::gemm::GemmShape<64, 64, 64>; // Warp tile shape + +// This code section describes the size of MMA op +using InstructionShape = cutlass::gemm::GemmShape<16, 8, 16>; // TensorCore instruction shape + +// This code section describes how threadblocks are scheduled on GPU +using SwizzleThreadBlock = cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>; + +// Number of pipelines you want to use +constexpr int NumStages = 3; + +// This code section describe iterator algorithm selected is Analytic or Optimized +static cutlass::conv::IteratorAlgorithm const IteratorAlgorithm = cutlass::conv::IteratorAlgorithm::kAnalytic; + +// This code section describes the epilogue part of the kernel, we use default value +using EpilogueOp = cutlass::epilogue::thread::LinearCombination< + ElementOutput, // Data type of output matrix. + 128 / cutlass::sizeof_bits::value, // The number of elements per vectorized. + // memory access. This becomes the vector width of + // math instructions in the epilogue too. + ElementAccumulator, // Data type of accumulator + ElementComputeEpilogue>; // Data type for alpha/beta in linear combination + + +using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementInputA, LayoutInputA, + ElementInputB, LayoutInputB, + ElementOutput, LayoutOutput, + ElementAccumulator, + MMAOp, + SmArch, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOp, + SwizzleThreadBlock, + NumStages, + cutlass::arch::OpMultiplyAdd, + IteratorAlgorithm +>::Kernel; + +using ImplicitGemm = cutlass::conv::device::ImplicitGemmConvolution; + + +///////////////////////////////////////////////////////////////////////////////////////////////// + +// Command line options parsing +struct Options { + + bool help; + cutlass::Tensor4DCoord input_size; + cutlass::Tensor4DCoord filter_size; + cutlass::Tensor4DCoord padding; + cutlass::MatrixCoord conv_stride; + cutlass::MatrixCoord dilation; + bool reference_check; + bool measure_performance; + int iterations; + bool save_workspace; + ElementComputeEpilogue alpha; + ElementComputeEpilogue beta; + bool benchmark; + std::string tag; + + Options(): + help(false), + input_size(1, 32, 32, 32), + filter_size(32, 3, 3, 32), + padding(1, 1, 1, 1), + conv_stride(1, 1), + dilation(1, 1), + reference_check(false), + measure_performance(true), + iterations(20), + save_workspace(false), + alpha(1), + beta(0), + benchmark(false) { } + + // Verify the problem size is compatible with the CUTLASS Convolution implementation. + bool valid() { + + // + // CUTLASS attempts to load 128b vectors of cutlass::half_t (F16) elements. Consequently, + // all pointers, strides, and tensor extents must be divisible by 8 elements. + // + int const kAlignment = 8; + + if ((input_size.c() % kAlignment) || + (filter_size.n() % kAlignment)) { + + // misaligned tensors + return false; + } + + // Invalid padding + if ((padding.h() != filter_size.h() / 2) || + (padding.w() != filter_size.w() / 2)) { + + return false; + } + + return true; + } + + /// Updates input and filter sizes + void update( + cutlass::Tensor4DCoord input_size, + cutlass::Tensor4DCoord filter_size) { + + this->input_size = input_size; + this->filter_size = filter_size; + + padding.n() = filter_size.h() / 2; + padding.h() = filter_size.h() / 2; + padding.w() = filter_size.w() / 2; + padding.c() = filter_size.w() / 2; + } + + // Parses the command line + void parse(int argc, char const **args) { + cutlass::CommandLine cmd(argc, args); + + if (cmd.check_cmd_line_flag("help")) { + help = true; + } + + if (cmd.check_cmd_line_flag("ref-check")) { + reference_check = true; + } + + if (cmd.check_cmd_line_flag("perf-check")) { + measure_performance = true; + } + + if (cmd.check_cmd_line_flag("save-workspace")) { + save_workspace = true; + } + + if (cmd.check_cmd_line_flag("benchmark")) { + benchmark = true; + } + + cmd.get_cmd_line_argument("n", input_size.n()); + cmd.get_cmd_line_argument("h", input_size.h()); + cmd.get_cmd_line_argument("w", input_size.w()); + cmd.get_cmd_line_argument("c", input_size.c()); + + cmd.get_cmd_line_argument("k", filter_size.n()); + cmd.get_cmd_line_argument("r", filter_size.h()); + cmd.get_cmd_line_argument("s", filter_size.w()); + filter_size.c() = input_size.c(); + + cmd.get_cmd_line_argument("alpha", alpha); + cmd.get_cmd_line_argument("beta", beta); + + cmd.get_cmd_line_argument("iterations", iterations); + cmd.get_cmd_line_argument("tag", tag); + + if (filter_size.h() == 3 && filter_size.w() == 3) { + padding = {1, 1, 1, 1}; + } + else { + filter_size.h() = 1; + filter_size.w() = 1; + padding = {0, 0, 0, 0}; + } + } + + /// Prints the usage statement. + std::ostream & print_usage(std::ostream &out) const { + + out << "22_ampere_tensorop_conv2dfprop example\n\n" + << " This example uses Ampere's Tensor Core operators on F16 data types to compute\n" + << " forward convolution on tensors of layout NHWC.\n\n" + << "Options:\n\n" + << " --help If specified, displays this usage statement.\n\n" + << " --n Input tensor extent N\n" + << " --h Input tensor extent H\n" + << " --w Input tensor extent W\n" + << " --c Input tensor extent C\n" + << " --k Filter extent K\n" + << " --r Filter extent R\n" + << " --s Filter extent S\n\n" + << " --alpha Epilogue scalar alpha\n" + << " --beta Epilogue scalar beta\n\n" + << " --ref-check If set (true), reference check on the host is computed\n" + << " --perf-check If set (true), performance is measured.\n" + << " --benchmark If set (true), performance benchmarking on several layers and batch-size.\n" + << " --iterations Number of profiling iterations to perform.\n" + << " --save-workspace If set, workspace is written to a text file.\n" + << " --tag String to replicate across the first column in the results table\n"; + + out << "\n\nExamples:\n\n" + << "$ ./examples/22_ampere_tensorop_conv2dfprop/22_ampere_tensorop_conv2dfprop --n=32 --h=224 --w=224 --c=128 --k=256 --r=1 --s=1\n\n" + << "$ ./examples/22_ampere_tensorop_conv2dfprop/22_ampere_tensorop_conv2dfprop --n=1 --h=224 --w=224 --c=32 --k=32 --r=3 --s=3 --ref-check\n\n"; + + return out; + } + + /// Computes the output tensor size (NPQK) + cutlass::Tensor4DCoord output_size() const { + return cutlass::Tensor4DCoord( + input_size.n(), + (input_size.h() + padding.n() + padding.h() - filter_size.h()) / conv_stride.row() + 1, + (input_size.w() + padding.w() + padding.c() - filter_size.w()) / conv_stride.column() + 1, + filter_size.n()); + } + + /// Compute performance in GFLOP/s + double gflops(double runtime_s) const { + + // Number of multiply-adds = NPQK * CRS + int64_t fmas = output_size().product() * int64_t(filter_size.h() * filter_size.w() * filter_size.c()); + + // Two flops per multiply-add + return 2.0 * double(fmas) / double(1.0e9) / runtime_s; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +struct Result { + double runtime_ms; + double gflops; + cutlass::Status status; + cutlass::Status reference_check; + cudaError_t error; + + Result(): + runtime_ms(0), + gflops(0), + status(cutlass::Status::kSuccess), + reference_check(cutlass::Status::kInvalid), + error(cudaSuccess) { } + + static std::ostream & print_header(std::ostream &out, Options const &options) { + + if (!options.tag.empty()) { + out << "Name,"; + } + + out << "Layer,N,H,W,C,K,R,S,Runtime,GFLOPs"; + + return out; + } + + std::ostream & print(std::ostream &out, int idx, Options const &options) { + + if (!options.tag.empty()) { + out << options.tag << ","; + } + + out + << "conv_" << idx << "," + << options.input_size.n() << "," + << options.input_size.h() << "," + << options.input_size.w() << "," + << options.input_size.c() << "," + << options.filter_size.n() << "," + << options.filter_size.h() << "," + << options.filter_size.w() << "," + << runtime_ms << "," + << gflops; + + return out; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Runs one benchmark +Result profile_convolution(Options const &options) { + + Result result; + + // + // Allocate host-device tensors using the CUTLASS Utilities. + // + + cutlass::HostTensor tensor_a(options.input_size); + cutlass::HostTensor tensor_b(options.filter_size); + cutlass::HostTensor tensor_c(options.output_size()); + cutlass::HostTensor tensor_ref_c(options.output_size()); + + // + // Initialize tensors + // + + // Fill tensor A on host with uniform-distribution random data + cutlass::reference::host::TensorFillRandomUniform( + tensor_a.host_view(), + 1, + ElementInputA(7), + ElementInputA(-8), + 0); + + // Fill tensor B on host with uniform-distribution random data + cutlass::reference::host::TensorFillRandomUniform( + tensor_b.host_view(), + 1, + ElementInputB(7), + ElementInputB(-8), + 0); + + // Fill tensor C on host with zeros + cutlass::reference::host::TensorFill( + tensor_c.host_view()); + + // Fill tensor C for reference on host with zeros + cutlass::reference::host::TensorFill( + tensor_ref_c.host_view()); + + // Copy data from host to GPU + tensor_a.sync_device(); + tensor_b.sync_device(); + tensor_c.sync_device(); + tensor_ref_c.sync_device(); + + // + // Define arguments for CUTLASS Convolution + // + + cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation; + + // Split K dimension into 1 partitions + int split_k_slices = 1; + + typename ImplicitGemm::Arguments arguments{ + { + options.input_size, + options.filter_size, + options.padding, + options.conv_stride, + options.dilation, + options.output_size(), + mode, + split_k_slices + }, + tensor_a.device_ref(), + tensor_b.device_ref(), + tensor_c.device_ref(), + tensor_c.device_ref(), + {options.alpha, options.beta}, + + + }; + + // + // Initialize CUTLASS Convolution + // + + ImplicitGemm implicit_gemm_op; + + size_t workspace_size = implicit_gemm_op.get_workspace_size(arguments); + + // Allocate workspace memory + cutlass::device_memory::allocation workspace(workspace_size); + + result.status = implicit_gemm_op.initialize(arguments, workspace.get()); + CUTLASS_CHECK(result.status); + + // + // Launch initialized CUTLASS kernel + // + result.status = implicit_gemm_op(); + + CUTLASS_CHECK(result.status); + + // + // Optional reference check + // + + if (options.reference_check) { + std::cout << "Verification on host...\n"; + + cutlass::conv::Conv2dProblemSize problem_size( + options.input_size, + options.filter_size, + options.padding, + options.conv_stride, + options.dilation, + mode + ); + + // Compute with reference implementation + cutlass::reference::host::Conv2dFprop< + ElementInputA, + LayoutInputA, + ElementInputB, + LayoutInputB, + ElementOutput, + LayoutOutput, + ElementComputeEpilogue, + ElementAccumulator, + cutlass::NumericConverter + >( + problem_size, + tensor_a.host_ref(), + tensor_b.host_ref(), + tensor_c.host_ref(), + tensor_ref_c.host_ref(), + options.alpha, + options.beta + ); + + // Check if output from CUTLASS kernel and reference kernel are equal or not + tensor_c.sync_host(); + + bool passed = cutlass::reference::host::TensorEquals( + tensor_c.host_view(), + tensor_ref_c.host_view()); + + if (!passed) { + result.reference_check = cutlass::Status::kErrorInternal; + std::cout << "ERROR - results miscompared.\n"; + } + else { + result.reference_check = cutlass::Status::kSuccess; + std::cout << "Passed.\n"; + } + } + else { + result.reference_check = cutlass::Status::kInvalid; + } + + if (options.save_workspace) { + + std::stringstream ss; + + ss << "22_ampere_workspace_conv2dfprop_" + << options.input_size.n() << "x" << options.input_size.h() << "x" << options.input_size.w() << "x" << options.input_size.c() + << "_" + << options.filter_size.n() << "x" << options.filter_size.h() << "x" << options.filter_size.w() << "x" << options.filter_size.c() + << ".dat"; + + std::ofstream output_workspace(ss.str()); + + output_workspace + << "Input = \n" << tensor_a.host_view() << "\n\n" + << "Filters = \n" << tensor_b.host_view() << "\n\n"; + + if (options.reference_check) { + output_workspace << "Reference = \n" << tensor_ref_c.host_view() << "\n\n"; + } + + output_workspace << "Computed = \n" << tensor_c.host_view() << std::endl; + + std::cout << "Results written to '" << ss.str() << "'." << std::endl; + } + + // + // Performance measurement + // + + if (options.measure_performance) { + + cudaEvent_t events[2]; + + for (auto & event : events) { + result.error = cudaEventCreate(&event); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventCreate() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + } + + // Record an event at the start of a series of convolution operations. + result.error = cudaEventRecord(events[0]); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventRecord() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + + // Launch a sequence of implicit GEMM operations on the device + for (int iteration = 0; iteration < options.iterations; ++iteration) { + result.status = implicit_gemm_op(); + CUTLASS_CHECK(result.status); + } + + // Record an event when the convolutions have been launched. + result.error = cudaEventRecord(events[1]); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventRecord() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + + // Wait for work on the device to complete. + result.error = cudaEventSynchronize(events[1]); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventSynchronize() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + + // Measure elapsed runtime + float runtime_ms = 0; + result.error = cudaEventElapsedTime(&runtime_ms, events[0], events[1]); + if (result.error != cudaSuccess) { + std::cerr << "cudaEventElapsed() failed: " << cudaGetErrorString(result.error) << std::endl; + return result; + } + + // Print average runtime and GFLOPs. + result.runtime_ms = double(runtime_ms) / double(options.iterations); + result.gflops = options.gflops(result.runtime_ms / 1000.0); + + // Cleanup + for (auto event : events) { + (void)cudaEventDestroy(event); + } + } + + return result; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char const **args) { + + bool notSupported = false; + + // Ampere Tensor Core operations exposed with mma.sync are first available in CUDA 10.2. + // + // CUTLASS must be compiled with CUDA 11 Toolkit to run Conv2dFprop examples. + if (!(__CUDACC_VER_MAJOR__ > 11 || (__CUDACC_VER_MAJOR__ == 11 && __CUDACC_VER_MINOR__ >= 0))) { + std::cerr << "Ampere Tensor Core operations must be compiled with CUDA 11.0 Toolkit or later." << std::endl; + notSupported = true; + } + + cudaDeviceProp props; + CUDA_CHECK(cudaGetDeviceProperties(&props, 0)); + + if (!(props.major > 8 || (props.major == 8 && props.minor >= 0))) { + std::cerr << "Ampere Tensor Ops must be run on a machine with compute capability at least 80." + << std::endl; + notSupported = true; + } + + if (notSupported) { + return 0; + } + + Options options; + + options.parse(argc, args); + + if (options.help) { + options.print_usage(std::cout) << std::endl; + return 0; + } + + if (options.benchmark) { + // Benchmark several layers + + int batch_sizes[] = {1, 32, 64, 128, 256, 512}; + + struct Benchmark { + int h, w, c, k, r, s; + } layers[] = { + {56, 56, 64, 256, 1, 1}, + {56, 56, 64, 64, 1, 1}, + {56, 56, 64, 64, 3, 3}, + {56, 56, 256, 64, 1, 1}, + {56, 56, 256, 512, 1, 1}, + {56, 56, 256, 128, 1, 1}, + {28, 28, 128, 128, 3, 3}, + {28, 28, 128, 512, 1, 1}, + {28, 28, 512, 128, 1, 1}, + {28, 28, 512, 1024, 1, 1}, + {28, 28, 512, 256, 1, 1}, + {14, 14, 256, 256, 3, 3}, + {14, 14, 256, 1024, 1, 1}, + {14, 14, 1024, 256, 1, 1}, + {14, 14, 1024, 2048, 1, 1}, + {14, 14, 1024, 512, 1, 1}, + {7, 7, 512, 512, 3, 3}, + }; + + Result::print_header(std::cout, options) << std::endl; + + int idx = 1; + + for (auto const &layer : layers) { + for (auto N : batch_sizes) { + + options.update({N, layer.h, layer.w, layer.c}, {layer.k, layer.r, layer.s, layer.c}); + + Result result = profile_convolution(options); + result.print(std::cout, idx, options) << std::endl; + } + + ++idx; + } + } + else { + + // Execute one problem size + if (!options.valid()) { + std::cerr << "Invalid problem." << std::endl; + return -1; + } + + Result result = profile_convolution(options); + + Result::print_header(std::cout, options) << std::endl; + result.print(std::cout, 1, options) << std::endl; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + + + diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index aabfa53c6..d51df92c7 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -22,15 +22,20 @@ set(CUTLASS_EXAMPLES_COMMON_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/common) +add_custom_target(cutlass_examples) +add_custom_target(test_examples) + function(cutlass_example_add_executable NAME) set(options) set(oneValueArgs) - set(multiValueArgs) + set(multiValueArgs DEPENDS DEPENDEES TEST_COMMAND_OPTIONS) cmake_parse_arguments(_ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cutlass_add_executable(${NAME} ${__UNPARSED_ARGUMENTS}) + add_dependencies(cutlass_examples ${NAME}) + target_link_libraries( ${NAME} PRIVATE @@ -44,19 +49,21 @@ function(cutlass_example_add_executable NAME) ${CUTLASS_EXAMPLES_COMMON_SOURCE_DIR} ) - add_custom_target( - test_${NAME} - COMMAND - ${CUTLASS_TEST_EXECUTION_ENVIRONMENT} $ - DEPENDS - ${NAME} + install( + TARGETS ${NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + + cutlass_add_executable_tests( + test_examples_${NAME} ${NAME} + DEPENDS ${__DEPENDS} + DEPENDEES test_examples ${__DEPENDEES} + TEST_COMMAND_OPTIONS ${__TEST_COMMAND_OPTIONS} + DISABLE_EXECUTABLE_INSTALL_RULE ) endfunction() -add_custom_target(cutlass_examples) -add_custom_target(test_examples) - foreach(EXAMPLE 00_basic_gemm 01_cutlass_utilities @@ -67,16 +74,16 @@ foreach(EXAMPLE 06_splitK_gemm 07_volta_tensorop_gemm 08_turing_tensorop_gemm + 09_turing_tensorop_conv2dfprop 10_planar_complex 11_planar_complex_array 12_gemm_bias_relu 13_fused_two_gemms 14_ampere_tf32_tensorop_gemm 15_ampere_sparse_tensorop_gemm -) + 22_ampere_tensorop_conv2dfprop + ) add_subdirectory(${EXAMPLE}) - add_dependencies(cutlass_examples ${EXAMPLE}) - add_dependencies(test_examples test_${EXAMPLE}) endforeach() diff --git a/include/cutlass/arch/memory_sm80.h b/include/cutlass/arch/memory_sm80.h index 04c568760..045196cb8 100644 --- a/include/cutlass/arch/memory_sm80.h +++ b/include/cutlass/arch/memory_sm80.h @@ -74,6 +74,10 @@ template < /// Size of the access in bytes int SizeInBytes> struct cp_async { + // Make sure the size is supported. + static_assert((SizeInBytes == 4 || SizeInBytes == 8 || SizeInBytes == 16), + "Size is not supported"); + /// Copy CUTLASS_DEVICE cp_async(void *smem_ptr, void const *global_ptr, bool pred_guard = true) { @@ -104,6 +108,10 @@ template < /// Size of the access in bytes int SizeInBytes> struct cp_async_zfill { + // Make sure the size is supported. + static_assert((SizeInBytes == 4 || SizeInBytes == 8 || SizeInBytes == 16), + "Size is not supported"); + /// Copy with zero fill CUTLASS_DEVICE cp_async_zfill(void *smem_ptr, void const *global_ptr, bool pred_guard) { @@ -138,6 +146,10 @@ template < /// Size of the access in bytes int SizeInBytes> struct cp_async { + // Make sure the size is supported. + static_assert((SizeInBytes == 4 || SizeInBytes == 8 || SizeInBytes == 16), + "Size is not supported"); + /// Copy CUTLASS_DEVICE cp_async(void *smem_ptr, void const *global_ptr, bool pred_guard = true) { @@ -171,6 +183,10 @@ template < /// Size of the access in bytes int SizeInBytes> struct cp_async_zfill { + // Make sure the size is supported. + static_assert((SizeInBytes == 4 || SizeInBytes == 8 || SizeInBytes == 16), + "Size is not supported"); + /// Copy with zero fill CUTLASS_DEVICE cp_async_zfill(void *smem_ptr, void const *global_ptr, bool pred_guard = true) { @@ -235,4 +251,3 @@ CUTLASS_DEVICE void cp_async_wait<0>() { } // namespace cutlass ///////////////////////////////////////////////////////////////////////////////////////////////// - diff --git a/include/cutlass/arch/mma.h b/include/cutlass/arch/mma.h index 49f3979ca..729cd1791 100644 --- a/include/cutlass/arch/mma.h +++ b/include/cutlass/arch/mma.h @@ -201,5 +201,5 @@ struct SparseMma; #include "cutlass/arch/mma_sm70.h" #include "cutlass/arch/mma_sm75.h" #include "cutlass/arch/mma_sm80.h" -#include "cutlass/arch/sp_mma_sm80.h" +#include "cutlass/arch/mma_sparse_sm80.h" ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/arch/mma_sm75.h b/include/cutlass/arch/mma_sm75.h index a862e65df..c5e0db972 100644 --- a/include/cutlass/arch/mma_sm75.h +++ b/include/cutlass/arch/mma_sm75.h @@ -365,7 +365,7 @@ struct Mma< } }; -/// Matrix multiply-add operation: S32 = S8 * U8 + S32 +/// Matrix multiply-add operation: S32 = U8 * U8 + S32 template <> struct Mma< gemm::GemmShape<8, 8, 16>, @@ -599,7 +599,7 @@ struct Mma< } }; -/// Matrix multiply-add operation: S32 = S8 * U8 + S32 +/// Matrix multiply-add operation: S32 = U8 * U8 + S32 template <> struct Mma< gemm::GemmShape<8,8,16>, diff --git a/include/cutlass/arch/sp_mma_sm80.h b/include/cutlass/arch/mma_sparse_sm80.h similarity index 99% rename from include/cutlass/arch/sp_mma_sm80.h rename to include/cutlass/arch/mma_sparse_sm80.h index 0c8989b86..a93fd2924 100644 --- a/include/cutlass/arch/sp_mma_sm80.h +++ b/include/cutlass/arch/mma_sparse_sm80.h @@ -29,7 +29,15 @@ #pragma once -#include "mma_sm80.h" +#if defined(__CUDACC_RTC__) +#include +#else +#include +#endif + +#include "mma.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/numeric_types.h" ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/arch/wmma.h b/include/cutlass/arch/wmma.h index 88968abdc..0a556aee3 100644 --- a/include/cutlass/arch/wmma.h +++ b/include/cutlass/arch/wmma.h @@ -52,7 +52,7 @@ #endif #endif -#endif //__clang__ +#endif //!defined(__clang__) #if defined(CUTLASS_ARCH_WMMA_ENABLED) @@ -82,6 +82,12 @@ struct CutlassToWmmaDataType { using Type = __half; }; +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800) && (__CUDACC_VER_MAJOR__ >= 11) +template<> +struct CutlassToWmmaDataType { + using Type = __nv_bfloat16; +}; +#endif /// Statically maps int8_t => char template<> @@ -158,6 +164,14 @@ template<> struct WmmaToCutlassDataType<__half> { using Type = cutlass::half_t; }; + +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800) && (__CUDACC_VER_MAJOR__ >= 11) +template<> +struct WmmaToCutlassDataType<__nv_bfloat16> { + using Type = cutlass::bfloat16_t; +}; +#endif + //////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/conv2d_problem_size.h b/include/cutlass/conv/conv2d_problem_size.h new file mode 100644 index 000000000..735103722 --- /dev/null +++ b/include/cutlass/conv/conv2d_problem_size.h @@ -0,0 +1,450 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief This file contains definitions and utility functions for describing convolution problem sizes. + + Conv2dProblem desciption: + activation (NHWC), + filter (KRSC), + output (NPQK), + pading (pad_h, pad_w), + stride (stride_h, stride_w), + dilation (dilation_h, dilation_w). + + Free functions to map: + Map tensor extents (Conv2d -> ImplicitGemm) : implicit_gemm_tensor_[a|b|c]_extent(ConvolutionOperator) + Map tensor sizes (Conv2d -> ImplicitGemm) : implicit_gemm_tensor_[a|b|c]_size(ConvolutionOperator) + Map tensor problem sizes (Conv2d -> ImplicitGemm): implicit_gemm_problem_size(ConvolutionOperator) +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/tensor_coord.h" +#include "cutlass/fast_math.h" +#include "cutlass/gemm/gemm.h" +#include "cutlass/matrix_coord.h" +#include "cutlass/conv/convolution.h" + +namespace cutlass { +namespace conv { + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Problem size structure +struct Conv2dProblemSize { + + // Conv2d strictly problem size parameters + int N, H, W, C, P, Q, K, R, S; + int pad_h, pad_w; + int stride_h, stride_w; + int dilation_h, dilation_w; + Mode mode; + + // Conv2d implementation-related parameters + int split_k_slices; + int groups; + + // + // Methods + // + +public: + CUTLASS_HOST_DEVICE + Conv2dProblemSize(): + N(0), H(0), W(0), C(0), P(0), Q(0), K(0), R(0), S(0), + pad_h(0), pad_w(0), stride_h(1), stride_w(1), dilation_h(1), dilation_w(1), + mode(Mode::kConvolution), split_k_slices(1), groups(1) { } + + /// Constructor for default padding, stride, dilation, and split-K + CUTLASS_HOST_DEVICE + Conv2dProblemSize( + int N, + int H, + int W, + int C, + int P, + int Q, + int K, + int R, + int S, + Mode mode + ): + N(N), H(H), W(W), C(C), P(P), Q(Q), K(K), R(R), S(S), + pad_h(R / 2), pad_w(S / 2), stride_h(1), stride_w(1), dilation_h(1), dilation_w(1), + mode(mode), split_k_slices(1), groups (1) { } + + /// Constructor + CUTLASS_HOST_DEVICE + Conv2dProblemSize( + int N, + int H, + int W, + int C, + int K, + int R, + int S, + int P, + int Q, + int pad_h, + int pad_w, + int stride_h, + int stride_w, + int dilation_h, + int dilation_w, + Mode mode, + int split_k_slices = 1, + int groups = 1 + ): + N(N), H(H), W(W), C(C), K(K), R(R), S(S), P(P), Q(Q), + pad_h(pad_h), pad_w(pad_w), stride_h(stride_h), stride_w(stride_w), + dilation_h(dilation_h), dilation_w(dilation_w), + mode(mode), split_k_slices(split_k_slices), groups (groups) { } + + /// Constructs convolution problem size from cutlass Tensor4DCoord and MatrixCoord + // set user-defined output size and sets P and Q (include all data members in ctor) + CUTLASS_HOST_DEVICE + Conv2dProblemSize( + cutlass::Tensor4DCoord input_size, // NHWC + cutlass::Tensor4DCoord filter_size, // KRSC + cutlass::Tensor4DCoord padding, // pad_h, _, pad_w, _ + cutlass::MatrixCoord stride, // stride_h, stride_w + cutlass::MatrixCoord dilation, // dilation_h, dilation_w + cutlass::Tensor4DCoord output_size, // NPQK + cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation, + int split_k_slices = 1, + int groups = 1 + ): + N(input_size.n()), H(input_size.h()), W(input_size.w()), C(input_size.c()), + K(filter_size.n()), R(filter_size.h()), S(filter_size.w()), + pad_h(padding[0]), pad_w(padding[2]), + stride_h(stride.row()), stride_w(stride.column()), + dilation_h(dilation.row()), dilation_w(dilation.column()), + P(output_size.h()), Q(output_size.w()), + mode(mode), split_k_slices(split_k_slices), groups(groups) {} + + /// Constructs convolution problem size from cutlass Tensor4DCoord and MatrixCoord + // computes output size and sets P and Q (skip output from ctor arguments) + CUTLASS_HOST_DEVICE + Conv2dProblemSize( + cutlass::Tensor4DCoord input_size, // NHWC + cutlass::Tensor4DCoord filter_size, // KRSC + cutlass::Tensor4DCoord padding, // pad_h, _, pad_w, _ + cutlass::MatrixCoord stride, // stride_h, stride_w + cutlass::MatrixCoord dilation, // dilation_h, dilation_w + cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation, + int split_k_slices = 1, + int groups = 1 + ): + N(input_size.n()), H(input_size.h()), W(input_size.w()), C(input_size.c()), + K(filter_size.n()), R(filter_size.h()), S(filter_size.w()), + pad_h(padding[0]), pad_w(padding[2]), + stride_h(stride.row()), stride_w(stride.column()), + dilation_h(dilation.row()), dilation_w(dilation.column()), + mode(mode), split_k_slices(split_k_slices), groups(groups) { + // set output P and Q + P = ((H + pad_h * 2 - R * dilation_h) / stride_h) + 1; + Q = ((W + pad_w * 2 - S * dilation_w) / stride_w) + 1; + } + + /// Constructs convolution problem size from cutlass Tensor4DCoord and MatrixCoord + // set user-defined output size and sets P and Q (skip padding, striding, and dilation) + CUTLASS_HOST_DEVICE + Conv2dProblemSize( + cutlass::Tensor4DCoord input_size, // NHWC + cutlass::Tensor4DCoord filter_size, // KRSC + cutlass::Tensor4DCoord output_size, // NPQK + cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation, + int split_k_slices = 1, + int groups = 1 + ): + N(input_size.n()), H(input_size.h()), W(input_size.w()), C(input_size.c()), + K(filter_size.n()), R(filter_size.h()), S(filter_size.w()), + P(output_size.h()), Q(output_size.w()), + pad_h(R / 2), pad_w(S / 2), stride_h(1), stride_w(1), + dilation_h(1), dilation_w(1), + mode(mode), split_k_slices(split_k_slices), groups(groups) {} + + // Reset covolution mode in the problem + CUTLASS_HOST_DEVICE + Conv2dProblemSize reset_mode(cutlass::conv::Mode mode_) { + Conv2dProblemSize tmp(*this); + tmp.mode = mode_; + return tmp; + } + + // Reset covolution mode in the problem + CUTLASS_HOST_DEVICE + Conv2dProblemSize reset_split_k_slices(int split_k_slices_) { + Conv2dProblemSize tmp(*this); + tmp.split_k_slices = split_k_slices_; + return tmp; + } + + /// Equality operator (ignores mode and split_k_slice) + CUTLASS_HOST_DEVICE + bool operator==(Conv2dProblemSize const &conv) const { + return ( + (N == conv.N) && (W == conv.H) && (W == conv.W) && (C == conv.C) && + (K == conv.K) && (R == conv.R) && (S == conv.S) && + (P == conv.P) && (Q == conv.Q) && + (pad_h == conv.pad_h) && (pad_w == conv.pad_w) && + (stride_h == conv.stride_h) && (stride_w == conv.stride_w) && + (dilation_h == conv.dilation_h) && (dilation_h == conv.dilation_h) + ); + } + + /// Inequality operator + CUTLASS_HOST_DEVICE + bool operator!=(Conv2dProblemSize const &rhs) const { + return !(*this == rhs); + } + + /// Returns activation extent as Tensor4DCoord + CUTLASS_HOST_DEVICE + cutlass::Tensor4DCoord activation_extent() const { + + return cutlass::Tensor4DCoord ({N, H, W, C}); + } + + /// Returns filter extent as Tensor4DCoord + CUTLASS_HOST_DEVICE + cutlass::Tensor4DCoord filter_extent() const { + + return cutlass::Tensor4DCoord ({K, R, S, C}); + } + + /// Returns output extent as Tensor4DCoord + CUTLASS_HOST_DEVICE + cutlass::Tensor4DCoord output_extent() const { + + return cutlass::Tensor4DCoord ({N, P, Q, K}); + } + + /// Returns activation size in number of elements + CUTLASS_HOST_DEVICE + int64_t activation_size() const { + + return (N * H * W * C); + } + + /// Returns filter size in number of elements + CUTLASS_HOST_DEVICE + int64_t filter_size() const { + + return (K * R * S * C); + } + + /// Returns output size in number of elements + CUTLASS_HOST_DEVICE + int64_t output_size() const { + + return (N * P * Q * K); + } + + /// Returns output extent as Tensor4DCoord + CUTLASS_HOST_DEVICE + cutlass::Tensor4DCoord padding() const { + + return cutlass::Tensor4DCoord ({pad_h, pad_h, pad_w, pad_w}); + } + + /// Returns stride as MatrixCoord + CUTLASS_HOST_DEVICE + cutlass::MatrixCoord stride() const { + + return cutlass::MatrixCoord ({stride_h, stride_w}); + } + + /// Returns dilation as MatrixCoord + CUTLASS_HOST_DEVICE + cutlass::MatrixCoord dilation() const { + + return cutlass::MatrixCoord ({dilation_h, dilation_w}); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// ImplicitGemm helper functions // +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Determine the problem size of the implicit GEMM operation +CUTLASS_HOST_DEVICE +cutlass::gemm::GemmCoord implicit_gemm_problem_size( + Operator conv_operator, + Conv2dProblemSize const &problem_size) { + // Compute problem size + switch (conv_operator) { + case Operator::kFprop: + return gemm::GemmCoord( + problem_size.N * problem_size.P * problem_size.Q, + problem_size.K, + problem_size.R * problem_size.S * problem_size.C + ); + case Operator::kDgrad: + return gemm::GemmCoord( + problem_size.N * problem_size.H * problem_size.W, + problem_size.C, + problem_size.R * problem_size.S * problem_size.K + ); + case Operator::kWgrad: + return gemm::GemmCoord( + problem_size.K, + problem_size.R * problem_size.S * problem_size.C, + problem_size.N * problem_size.P * problem_size.Q + ); + default: + break; + } + return gemm::GemmCoord(); +} + +// Determine the number of gemm_k iterations for conv2d problem using implicit gemm algorithm +CUTLASS_HOST_DEVICE +int implicit_gemm_k_iterations( + Operator conv_operator, + int threadblock_K, + Conv2dProblemSize const &problem_size) { + + int iterations = 0; + int elements_per_split_k_slice = 0; + + switch (conv_operator) { + case Operator::kFprop: + elements_per_split_k_slice = (problem_size.C + problem_size.split_k_slices - 1) / problem_size.split_k_slices; + iterations = problem_size.R * problem_size.S * ((elements_per_split_k_slice + threadblock_K - 1) / threadblock_K); + break; + + case Operator::kDgrad: + elements_per_split_k_slice = (problem_size.K + problem_size.split_k_slices - 1) / problem_size.split_k_slices; + iterations = problem_size.R * problem_size.S * ((elements_per_split_k_slice + threadblock_K - 1) / threadblock_K); + break; + + case Operator::kWgrad: + elements_per_split_k_slice = (problem_size.N * problem_size.P * problem_size.Q + problem_size.split_k_slices - 1) / problem_size.split_k_slices; + iterations = (elements_per_split_k_slice + threadblock_K - 1) / threadblock_K; + break; + + default: + break; + } + + return iterations; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Mapping function (ImplicitGemm A, B, C -> Conv Activation, Filter, Output) +//////////////////////////////////////////////////////////////////////////////// +/// Returns ImplicitGemm tensor A extent as Tensor4DCoord +CUTLASS_HOST_DEVICE +cutlass::Tensor4DCoord implicit_gemm_tensor_a_extent( + Operator conv_operator, + Conv2dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.activation_extent(); + case cutlass::conv::Operator::kDgrad: return problem_size.output_extent(); + case cutlass::conv::Operator::kWgrad: return problem_size.output_extent(); + default : break; + } + return cutlass::Tensor4DCoord(); +} + +/// Returns ImplicitGemm tensor B extent as Tensor4DCoord +CUTLASS_HOST_DEVICE +cutlass::Tensor4DCoord implicit_gemm_tensor_b_extent( + Operator conv_operator, + Conv2dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.filter_extent(); + case cutlass::conv::Operator::kDgrad: return problem_size.filter_extent(); + case cutlass::conv::Operator::kWgrad: return problem_size.activation_extent(); + default : break; + } + return cutlass::Tensor4DCoord(); +} + +/// Returns ImplicitGemm tensor C extent as Tensor4DCoord +CUTLASS_HOST_DEVICE +cutlass::Tensor4DCoord implicit_gemm_tensor_c_extent( + Operator conv_operator, + Conv2dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.output_extent(); + case cutlass::conv::Operator::kDgrad: return problem_size.activation_extent(); + case cutlass::conv::Operator::kWgrad: return problem_size.filter_extent(); + default : break; + } + return cutlass::Tensor4DCoord(); +} + +/// Returns ImplicitGemm tensor A size in number of elements +CUTLASS_HOST_DEVICE +int64_t implicit_gemm_tensor_a_size( + Operator conv_operator, + Conv2dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.activation_size(); + case cutlass::conv::Operator::kDgrad: return problem_size.output_size(); + case cutlass::conv::Operator::kWgrad: return problem_size.output_size(); + default : break; + } + return 0; +} + +/// Returns ImplicitGemm tensor B size in number of elements +CUTLASS_HOST_DEVICE +int64_t implicit_gemm_tensor_b_size( + Operator conv_operator, + Conv2dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.filter_size(); + case cutlass::conv::Operator::kDgrad: return problem_size.filter_size(); + case cutlass::conv::Operator::kWgrad: return problem_size.activation_size(); + default : break; + } + return 0; +} + +/// Returns ImplicitGemm tensor C size in number of elements +CUTLASS_HOST_DEVICE +int64_t implicit_gemm_tensor_c_size( + Operator conv_operator, + Conv2dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.output_size(); + case cutlass::conv::Operator::kDgrad: return problem_size.activation_size(); + case cutlass::conv::Operator::kWgrad: return problem_size.filter_size(); + default : break; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace conv +} // namespace cutlass + +//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/conv3d_problem_size.h b/include/cutlass/conv/conv3d_problem_size.h new file mode 100644 index 000000000..91827d272 --- /dev/null +++ b/include/cutlass/conv/conv3d_problem_size.h @@ -0,0 +1,453 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief This file contains definitions and utility functions for describing convolution problem sizes. + + Conv3dProblem desciption: + activation (NDHWC), + filter (KTRSC), + output (NZPQK), + pading (pad_d, pad_h, pad_w), + stride (stride_d, stride_h, stride_w), + dilation (dilation_d, dilation_h, dilation_w). + + Free functions to map: + Map tensor extents (Conv3d -> ImplicitGemm) : implicit_gemm_tensor_[a|b|c]_extent(ConvolutionOperator) + Map tensor sizes (Conv3d -> ImplicitGemm) : implicit_gemm_tensor_[a|b|c]_size(ConvolutionOperator) + Map tensor problem sizes (Conv3d -> ImplicitGemm): implicit_gemm_problem_size(ConvolutionOperator) +*/ + +#pragma once + +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" + +namespace cutlass { +namespace conv { + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Problem size structure +struct Conv3dProblemSize : public Conv2dProblemSize { + // + // Type definitions + // + + // 3D coordinate for padding, stride, and dilation in (d, h, w) dimensions + using Coord3D = Coord<3>; + + // + // Data members + // + + // Conv3d strictly problem size parameters + int D, T, Z; // input depth, filter depth, output depth + int pad_d; // padding in depth dimension + int stride_d; // stride in depth dimension + int dilation_d; // dilation in depth dimension + + // + // Methods + // +public: + CUTLASS_HOST_DEVICE + Conv3dProblemSize(): + D(0), T(0), Z(0), + pad_d(0), + stride_d(1), + dilation_d(1), + Conv2dProblemSize() { } + + /// Constructor for default padding, stride, dilation, and split-K + CUTLASS_HOST_DEVICE + Conv3dProblemSize( + int N, + int D, + int H, + int W, + int C, + int Z, + int P, + int Q, + int K, + int T, + int R, + int S, + Mode mode + ): + D(D), T(T), Z(Z), + pad_d(T / 2), stride_d(1), dilation_d(1), + Conv2dProblemSize(N, H, W, C, P, Q, K, R, S, mode) { } + + /// Constructor + CUTLASS_HOST_DEVICE + Conv3dProblemSize( + int N, + int D, + int H, + int W, + int C, + int K, + int T, + int R, + int S, + int Z, + int P, + int Q, + int pad_d, + int pad_h, + int pad_w, + int stride_d, + int stride_h, + int stride_w, + int dilation_d, + int dilation_h, + int dilation_w, + Mode mode, + int split_k_slices = 1, + int groups = 1 + ): + D(D), T(T), Z(Z), + pad_d(pad_d), stride_d(stride_d), dilation_d(dilation_d), + Conv2dProblemSize( + N, H, W, C, K, R, S, P, Q, + pad_h, pad_w, + stride_h, stride_w, + dilation_h, dilation_w, + mode, split_k_slices, groups) { } + + /// Constructs convolution problem size from cutlass Tensor5DCoord and Coord3D + // set *user-defined* output size and sets Z, P, and Q (include all data members in ctor) + CUTLASS_HOST_DEVICE + Conv3dProblemSize( + cutlass::Tensor5DCoord input_size, // NDHWC + cutlass::Tensor5DCoord filter_size, // KTRSC + Coord3D padding, // pad_d, pad_h, pad_w + Coord3D stride, // stride_d, stride_h, stride_w + Coord3D dilation, // dilation_d, dilation_h, dilation_w + cutlass::Tensor5DCoord output_size, // NZPQK + cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation, + int split_k_slices = 1, + int groups = 1 + ): + D(input_size.d()), T(filter_size.d()), Z(output_size.d()), + pad_d(padding[0]), stride_d(stride[0]), dilation_d(dilation[0]), + Conv2dProblemSize( + {input_size.n(), input_size.h(), input_size.w(), input_size.c()}, + {filter_size.n(), filter_size.h(), filter_size.w(), filter_size.c()}, + {padding[1], padding[1], padding[2], padding[2]}, + {stride[1], stride[2]}, + {dilation[1], dilation[2]}, + {output_size.n(), output_size.h(), output_size.w(), output_size.c()}, + mode, split_k_slices, groups + ) { } + + /// Constructs convolution problem size from cutlass Tensor5DCoord and Coord3D + // *computes* output size and sets Z, P and Q (include all data members in ctor) + CUTLASS_HOST_DEVICE + Conv3dProblemSize( + cutlass::Tensor5DCoord input_size, // NDHWC + cutlass::Tensor5DCoord filter_size, // KTRSC + Coord3D padding, // pad_d, pad_h, pad_w + Coord3D stride, // stride_d, stride_h, stride_w + Coord3D dilation, // dilation_d, dilation_h, dilation_w + cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation, + int split_k_slices = 1, + int groups = 1 + ): + D(input_size.d()), T(filter_size.d()), + pad_d(padding[0]), stride_d(stride[0]), dilation_d(dilation[0]), + Conv2dProblemSize( + {input_size.n(), input_size.h(), input_size.w(), input_size.c()}, + {filter_size.n(), filter_size.h(), filter_size.w(), filter_size.c()}, + {padding[1], padding[1], padding[2], padding[2]}, + {stride[1], stride[2]}, + {dilation[1], dilation[2]}, + mode, split_k_slices, groups + ) { + // set output Z + Z = ((D + pad_d - T * dilation_d) / stride_d) + 1; + } + + /// Equality operator (ignores mode and split_k_slice) + CUTLASS_HOST_DEVICE + bool operator==(Conv3dProblemSize const &conv) const { + return ( + (N == conv.N) && (D == conv.D) && (H == conv.H) && (W == conv.W) && (C == conv.C) && + (K == conv.K) && (T == conv.T) && (R == conv.R) && (S == conv.S) && + (Z == conv.Z) &&(P == conv.P) && (Q == conv.Q) && + (pad_d == conv.pad_d) && (pad_h == conv.pad_h) && (pad_w == conv.pad_w) && + (stride_d == conv.stride_d) && (stride_h == conv.stride_h) && (stride_w == conv.stride_h) && + (dilation_d == conv.dilation_d) && (dilation_h == conv.dilation_h) && (dilation_h == conv.dilation_h) + ); + } + + /// Inequality operator + CUTLASS_HOST_DEVICE + bool operator!=(Conv3dProblemSize const &rhs) const { + return !(*this == rhs); + } + + // Reset covolution mode in the problem + CUTLASS_HOST_DEVICE + Conv3dProblemSize reset_mode(cutlass::conv::Mode mode_) { + Conv3dProblemSize tmp(*this); + tmp.mode = mode_; + return tmp; + } + + // Reset covolution mode in the problem + CUTLASS_HOST_DEVICE + Conv3dProblemSize reset_split_k_slices(int split_k_slices_) { + Conv3dProblemSize tmp(*this); + tmp.split_k_slices = split_k_slices_; + return tmp; + } + + /// Returns activation extent as Tensor5DCoord + CUTLASS_HOST_DEVICE + cutlass::Tensor5DCoord activation_extent() const { + + return cutlass::Tensor5DCoord ({N, D, H, W, C}); + } + + /// Returns filter extent as Tensor5DCoord + CUTLASS_HOST_DEVICE + cutlass::Tensor5DCoord filter_extent() const { + + return cutlass::Tensor5DCoord ({K, T, R, S, C}); + } + + /// Returns output extent as Tensor5DCoord + CUTLASS_HOST_DEVICE + cutlass::Tensor5DCoord output_extent() const { + + return cutlass::Tensor5DCoord ({N, Z, P, Q, K}); + } + + /// Returns activation size in number of elements + CUTLASS_HOST_DEVICE + int64_t activation_size() const { + + return (N * D * H * W * C); + } + + /// Returns filter size in number of elements + CUTLASS_HOST_DEVICE + int64_t filter_size() const { + + return (K * T * R * S * C); + } + + /// Returns output size in number of elements + CUTLASS_HOST_DEVICE + int64_t output_size() const { + + return (N * Z * P * Q * K); + } + + /// Returns output extent as Tensor5DCoord + CUTLASS_HOST_DEVICE + Coord3D padding() const { + + return Coord3D ({pad_d, pad_h, pad_w}); + } + + /// Returns stride as MatrixCoord + CUTLASS_HOST_DEVICE + Coord3D stride() const { + + return Coord3D ({stride_d, stride_h, stride_w}); + } + + /// Returns dilation as MatrixCoord + CUTLASS_HOST_DEVICE + Coord3D dilation() const { + + return Coord3D ({dilation_d, dilation_h, dilation_w}); + } + +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// ImplicitGemm helper functions // +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Determine the problem size of the implicit GEMM operation +CUTLASS_HOST_DEVICE +cutlass::gemm::GemmCoord implicit_gemm_problem_size( + Operator conv_operator, + Conv3dProblemSize const &problem_size) { + // Compute problem size + switch (conv_operator) { + case Operator::kFprop: + return gemm::GemmCoord( + problem_size.N * problem_size.Z * problem_size.P * problem_size.Q, + problem_size.K, + problem_size.T * problem_size.R * problem_size.S * problem_size.C + ); + case Operator::kDgrad: + return gemm::GemmCoord( + problem_size.N * problem_size.D * problem_size.H * problem_size.W, + problem_size.C, + problem_size.T * problem_size.R * problem_size.S * problem_size.K + ); + case Operator::kWgrad: + return gemm::GemmCoord( + problem_size.K, + problem_size.T * problem_size.R * problem_size.S * problem_size.C, + problem_size.N * problem_size.Z * problem_size.P * problem_size.Q + ); + default: + break; + } + return gemm::GemmCoord(); +} + +// Determine the number of gemm_k iterations for conv2d problem using implicit gemm algorithm +CUTLASS_HOST_DEVICE +int implicit_gemm_k_iterations( + Operator conv_operator, + int threadblock_K, + Conv3dProblemSize const &problem_size) { + + int iterations = 0; + int elements_per_split_k_slice = 0; + + switch (conv_operator) { + case Operator::kFprop: + elements_per_split_k_slice = (problem_size.C + problem_size.split_k_slices - 1) / problem_size.split_k_slices; + iterations = problem_size.T * problem_size.R * problem_size.S * ((elements_per_split_k_slice + threadblock_K - 1) / threadblock_K); + break; + + case Operator::kDgrad: + elements_per_split_k_slice = (problem_size.K + problem_size.split_k_slices - 1) / problem_size.split_k_slices; + iterations = problem_size.T * problem_size.R * problem_size.S * ((elements_per_split_k_slice + threadblock_K - 1) / threadblock_K); + break; + + case Operator::kWgrad: + elements_per_split_k_slice = (problem_size.N * problem_size.Z * problem_size.P * problem_size.Q + problem_size.split_k_slices - 1) / problem_size.split_k_slices; + iterations = (elements_per_split_k_slice + threadblock_K - 1) / threadblock_K; + break; + + default: + break; + } + + return iterations; +} + +//////////////////////////////////////////////////////////////////////////////// +// Mapping function (ImplicitGemm A, B, C -> Conv Activation, Filter, Output) +//////////////////////////////////////////////////////////////////////////////// +/// Returns ImplicitGemm tensor A extent as Tensor5DCoord +CUTLASS_HOST_DEVICE +cutlass::Tensor5DCoord implicit_gemm_tensor_a_extent( + Operator conv_operator, + Conv3dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.activation_extent(); + case cutlass::conv::Operator::kDgrad: return problem_size.output_extent(); + case cutlass::conv::Operator::kWgrad: return problem_size.output_extent(); + default : break; + } + return cutlass::Tensor5DCoord(); +} + +/// Returns ImplicitGemm tensor B extent as Tensor5DCoord +CUTLASS_HOST_DEVICE +cutlass::Tensor5DCoord implicit_gemm_tensor_b_extent( + Operator conv_operator, + Conv3dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.filter_extent(); + case cutlass::conv::Operator::kDgrad: return problem_size.filter_extent(); + case cutlass::conv::Operator::kWgrad: return problem_size.activation_extent(); + default : break; + } + return cutlass::Tensor5DCoord(); +} + +/// Returns ImplicitGemm tensor C extent as Tensor5DCoord +CUTLASS_HOST_DEVICE +cutlass::Tensor5DCoord implicit_gemm_tensor_c_extent( + Operator conv_operator, + Conv3dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.output_extent(); + case cutlass::conv::Operator::kDgrad: return problem_size.activation_extent(); + case cutlass::conv::Operator::kWgrad: return problem_size.filter_extent(); + default : break; + } + return cutlass::Tensor5DCoord(); +} + +/// Returns ImplicitGemm tensor A size in number of elements +CUTLASS_HOST_DEVICE +int64_t implicit_gemm_tensor_a_size( + Operator conv_operator, + Conv3dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.activation_size(); + case cutlass::conv::Operator::kDgrad: return problem_size.output_size(); + case cutlass::conv::Operator::kWgrad: return problem_size.output_size(); + default : break; + } + return 0; +} + +/// Returns ImplicitGemm tensor B size in number of elements +CUTLASS_HOST_DEVICE +int64_t implicit_gemm_tensor_b_size( + Operator conv_operator, + Conv3dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.filter_size(); + case cutlass::conv::Operator::kDgrad: return problem_size.filter_size(); + case cutlass::conv::Operator::kWgrad: return problem_size.activation_size(); + default : break; + } + return 0; +} + +/// Returns ImplicitGemm tensor C size in number of elements +CUTLASS_HOST_DEVICE +int64_t implicit_gemm_tensor_c_size( + Operator conv_operator, + Conv3dProblemSize const &problem_size) { + switch (conv_operator) { + case cutlass::conv::Operator::kFprop: return problem_size.output_size(); + case cutlass::conv::Operator::kDgrad: return problem_size.activation_size(); + case cutlass::conv::Operator::kWgrad: return problem_size.filter_size(); + default : break; + } + return 0; +} + +} // namespace conv +} // namespace cutlass + +//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/convolution.h b/include/cutlass/conv/convolution.h new file mode 100644 index 000000000..c743ea6fa --- /dev/null +++ b/include/cutlass/conv/convolution.h @@ -0,0 +1,118 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief + +This file contains definitions and utility functions for describing convolution problem sizes in terms of +activation (NHWC), filter (KRSC), output (NPQK), pading (pad_h, pad_w), stride (stride_h, stride_w), +dilation (dilation_h, dilation_w). Furthermore, it defines helper functions to map cutlass' implicit gemm +tensor extents, sizes, data types to that of convolutions extents, sizes, and data types. + + * Mapping convolutions to Gemm computation * + +Cutlass employs ImplicitGemm algorithm to implement convolutions. ImplicitGemm algorithm runs gemm operation +on convolution tensors Activation, Filter, and Output . The underlying gemm operation follows the standard +gemm definition: + + C = A * B + C + + A and B are input matrices + C is source and output matrix + + +For the three convolutional operators (Fprop, Dgrad, Wgrad), ImplicitGemm matrices A, B, and C are mapped on +to convolution tensors Activation, Filter and Output as per the below table: + + ___________________________________________________________________________ + ConvolutionalOperator | A | B | C + ___________________________________________________________________________ + | | | | | + | Fprop | Activation | Filter | Output | + | Dgrad | Output | Filter | Activation | + | Wgrad | Output | Activation | Filter | + ___________________________________________________________________________ + +In convolution codebase, DO NOT mix using (A, B, C) with (Acvitation, Filter, Output). + +For example, a convolution class/function with A, B, Output is confusing and error-prone. Instead use below +mapping functions and adhere to using either A, B, C or Acvitation, Filter, Output. + +Map elements' data types (ImplicitGemm -> Conv): GemmToConvElementMap +Map elements' data types (Conv -> ImplicitGemm): ConvToGemmElementMap +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/tensor_coord.h" +#include "cutlass/fast_math.h" +#include "cutlass/gemm/gemm.h" +#include "cutlass/matrix_coord.h" + +namespace cutlass { +namespace conv { + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Convolutional operator +enum class Operator { + kFprop, + kDgrad, + kWgrad +}; + +/// Distinguishes convolution from cross correlation +enum class Mode { + kCrossCorrelation, + kConvolution +}; + +/// Selects among several implementation variants trading off performance with simplicity +enum class IteratorAlgorithm { + kAnalytic, ///< functionally correct in all cases but lower performance + kOptimized ///< optimized for R <= 32, S <= 32 and unity-stride dgrad +}; + +/// Distinguishes among partial specializations that accelerate certain problems where convolution +/// stride is unit. +enum class StrideSupport { + kStrided, ///< arbitrary convolution stride + kUnity ///< unit convolution stride +}; + +/// Identifies split-K mode +enum class SplitKMode { + kNone, + kSerial, + kParallel +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace conv +} // namespace cutlass + +//////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/device/implicit_gemm_convolution.h b/include/cutlass/conv/device/implicit_gemm_convolution.h new file mode 100644 index 000000000..0aa03d199 --- /dev/null +++ b/include/cutlass/conv/device/implicit_gemm_convolution.h @@ -0,0 +1,263 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Template for device-level Implicit GEMM Convolution +*/ + +#pragma once + +#include + +#include "cutlass/cutlass.h" +#include "cutlass/device_kernel.h" +#include "cutlass/conv/convolution.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace device { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ImplicitGemmConvolution { +public: + + using ImplicitGemmKernel = ImplicitGemmKernel_; + + using ElementA = typename ImplicitGemmKernel::ElementA; + using LayoutA = typename ImplicitGemmKernel::LayoutA; + using ElementB = typename ImplicitGemmKernel::ElementB; + using LayoutB = typename ImplicitGemmKernel::LayoutB; + using ElementC = typename ImplicitGemmKernel::ElementC; + using LayoutC = typename ImplicitGemmKernel::LayoutC; + using ElementAccumulator = typename ImplicitGemmKernel::ElementAccumulator; + using ElementCompute = typename ImplicitGemmKernel::ElementCompute; + using OperatorClass = typename ImplicitGemmKernel::OperatorClass; + using ArchTag = typename ImplicitGemmKernel::ArchTag; + using ThreadblockShape = typename ImplicitGemmKernel::ThreadblockShape; + using WarpShape = typename ImplicitGemmKernel::WarpShape; + using InstructionShape = typename ImplicitGemmKernel::InstructionShape; + using ThreadblockSwizzle = typename ImplicitGemmKernel::ThreadblockSwizzle; + using EpilogueOutputOp = typename ImplicitGemmKernel::EpilogueOutputOp; + static int const kStages = ImplicitGemmKernel::kStages; + static int const kConvDim = ImplicitGemmKernel::kConvDim; + using WarpMmaOperator = typename ImplicitGemmKernel::WarpMmaOperator; + using ArchMmaOperator = typename ImplicitGemmKernel::ArchMmaOperator; + using MathOperator = typename ImplicitGemmKernel::MathOperator; + + static cutlass::conv::Operator const kConvolutionalOperator = ImplicitGemmKernel::kConvolutionalOperator; + static cutlass::conv::IteratorAlgorithm const kIteratorAlgorithm = ImplicitGemmKernel::kIteratorAlgorithm; + + static int const kWarpCount = + (ThreadblockShape::kM / WarpShape::kM) * + (ThreadblockShape::kN / WarpShape::kN); + + /// Argument structure + using Arguments = typename ImplicitGemmKernel::Arguments; + +private: + + /// Kernel parameters object + typename ImplicitGemmKernel::Params params_; + +public: + + /// Constructs Implicit GEMM + ImplicitGemmConvolution() { } + + /// Determines whether the Implicit GEMM can execute the given problem. + static Status can_implement(Arguments const &args) { + + // dispatch to iterators + Status status = ImplicitGemmKernel::Mma::IteratorA::can_implement(args.problem_size); + if (Status::kSuccess != status) { + return status; + } + + status = ImplicitGemmKernel::Mma::IteratorB::can_implement(args.problem_size); + if (Status::kSuccess != status) { + return status; + } + + // Determine grid shape + ThreadblockSwizzle threadblock_swizzle; + + dim3 grid = threadblock_swizzle.get_grid_shape( + threadblock_swizzle.get_tiled_shape( + cutlass::conv::implicit_gemm_problem_size(kConvolutionalOperator, args.problem_size), + {ThreadblockShape::kM, ThreadblockShape::kN, ThreadblockShape::kK}, + args.problem_size.split_k_slices)); + + if (!(grid.y <= std::numeric_limits::max() && + grid.z <= std::numeric_limits::max())) { + + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + + /// Gets the workspace size + static size_t get_workspace_size(Arguments const &args) { + + size_t workspace_bytes = 0; + + // Determine grid shape + ThreadblockSwizzle threadblock_swizzle; + + cutlass::gemm::GemmCoord grid_tiled_shape = threadblock_swizzle.get_tiled_shape( + cutlass::conv::implicit_gemm_problem_size(kConvolutionalOperator, args.problem_size), + {ThreadblockShape::kM, ThreadblockShape::kN, ThreadblockShape::kK}, + args.problem_size.split_k_slices); + + if(args.split_k_mode == SplitKMode::kParallel) { + + // Split-K parallel: CTAs in k-dimension write the partial results in a temporary workspace. + // The user needs to call a reduction operator to optain the final output tensor + workspace_bytes = + sizeof(ElementAccumulator) * + size_t(cutlass::conv::implicit_gemm_tensor_c_size(kConvolutionalOperator, args.problem_size)) * + size_t(grid_tiled_shape.k()); + } + + else if(args.split_k_mode == SplitKMode::kSerial && args.problem_size.split_k_slices > 1) { + + // Split-K serial: The user workspace is used to store semaphore and serialize writing the + // final reduced output to user's output tensor + workspace_bytes = sizeof(int) * size_t(grid_tiled_shape.m()) * size_t(grid_tiled_shape.n()); + } + + return workspace_bytes; + } + + /// Initializes GEMM state from arguments. + Status initialize( + Arguments const &args, + void *workspace = nullptr, + cudaStream_t stream = nullptr) { + + if (args.problem_size.split_k_slices > 1) { + + if (!workspace) { + return Status::kErrorWorkspaceNull; + } + + cudaError_t status = cudaMemsetAsync(workspace, 0, get_workspace_size(args), stream); + + if (status != cudaSuccess) { + return Status::kErrorInternal; + } + } + + // initialize the params structure from the arguments + params_ = typename ImplicitGemmKernel::Params( + args, + static_cast(workspace) + ); + + int smem_size = int(sizeof(typename ImplicitGemmKernel::SharedStorage)); + + if (smem_size >= (48 << 10)) { + cudaError_t result = cudaFuncSetAttribute(cutlass::Kernel, + cudaFuncAttributeMaxDynamicSharedMemorySize, + smem_size); + + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + result = cudaFuncSetAttribute( + cutlass::Kernel, + cudaFuncAttributePreferredSharedMemoryCarveout, 100); + + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + } + + return Status::kSuccess; + } + + /// Initializes GEMM state from arguments. + Status update(Arguments const &args, void *workspace = nullptr) { + + // update the params structure from the arguments + params_.ptr_A = args.ref_A.data(); + params_.ptr_B = args.ref_B.data(); + params_.ptr_C = args.ref_C.data(); + params_.ptr_D = args.ref_D.data(); + params_.output_op = args.output_op; + params_.semaphore = static_cast(workspace); + + return Status::kSuccess; + } + + /// Runs the kernel using initialized state. + Status run(cudaStream_t stream = nullptr) { + + ThreadblockSwizzle threadblock_swizzle; + + dim3 grid = threadblock_swizzle.get_grid_shape(params_.grid_tiled_shape); + dim3 block(32 * kWarpCount, 1, 1); + + int smem_size = int(sizeof(typename ImplicitGemmKernel::SharedStorage)); + + cutlass::Kernel<<>>(params_); + + cudaError_t result = cudaGetLastError(); + + return result == cudaSuccess ? Status::kSuccess : Status::kErrorInternal; + } + + /// Runs the kernel using initialized state. + Status operator()(cudaStream_t stream = nullptr) { + return run(stream); + } + + /// Runs the kernel using initialized state. + Status operator()( + Arguments const &args, + void *workspace = nullptr, + cudaStream_t stream = nullptr) { + + Status status = initialize(args, workspace); + + if (status == Status::kSuccess) { + status = run(stream); + } + + return status; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} +} +} + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/kernel/default_conv2d.h b/include/cutlass/conv/kernel/default_conv2d.h new file mode 100644 index 000000000..57fae7965 --- /dev/null +++ b/include/cutlass/conv/kernel/default_conv2d.h @@ -0,0 +1,104 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief + Default kernel-level implicit GEMM convolution definitions for threadblock-scoped epilogue. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/gemm/threadblock/default_mma.h" +#include "cutlass/gemm/threadblock/threadblock_swizzle.h" +#include "cutlass/epilogue/threadblock/default_epilogue_simt.h" +#include "cutlass/epilogue/threadblock/default_epilogue_tensor_op.h" +#include "cutlass/epilogue/threadblock/default_epilogue_volta_tensor_op.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/threadblock/conv2d_tile_iterator.h" +#include "cutlass/conv/threadblock/implicit_gemm_pipelined.h" +#include "cutlass/conv/threadblock/implicit_gemm_multistage.h" +#include "cutlass/conv/kernel/implicit_gemm_convolution.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace kernel { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace detail { + +template < + typename ArchTag, + typename Shape, + typename WarpMmaTensorOp, + int PartitionsK, + typename OutputOp +> +struct DefaultConvEpilogue { + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + Shape, + WarpMmaTensorOp, + 1, + OutputOp, + OutputOp::kCount + >::Epilogue; +}; + +template < + typename Shape, + typename WarpMmaTensorOp, + int PartitionsK, + typename OutputOp +> +struct DefaultConvEpilogue< + arch::Sm70, + Shape, + WarpMmaTensorOp, + PartitionsK, + OutputOp +> { + + using Epilogue = typename epilogue::threadblock::DefaultEpilogueVoltaTensorOp< + Shape, + WarpMmaTensorOp, + 1, + OutputOp, + OutputOp::kCount + >::Epilogue; +}; + +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace kernel +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/kernel/default_conv2d_dgrad.h b/include/cutlass/conv/kernel/default_conv2d_dgrad.h new file mode 100644 index 000000000..c590f57ef --- /dev/null +++ b/include/cutlass/conv/kernel/default_conv2d_dgrad.h @@ -0,0 +1,1154 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief + Default kernel-level implicit GEMM convolution definitions combine threadblock-scoped + matrix multiply-add with the appropriate threadblock-scoped epilogue. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/conv/kernel/default_conv2d.h" + +#include "cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_optimized.h" +#include "cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_optimized.h" +#include "cutlass/conv/threadblock/conv2d_tile_iterator.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace kernel { + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv2dDgrad +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag, + conv::IteratorAlgorithm IteratorAlgorithm = IteratorAlgorithm::kAnalytic, + conv::StrideSupport StrideSupport = StrideSupport::kStrided +> struct DefaultConv2dDgrad; + +///////////////////////////////////////////////////////////////////////////////////////////////// +// OpClassTensorOp convolutions +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dDgrad specialzation for Analytic IteratorAlgorithm Dgrad Strided and +// multistage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic, + StrideSupport::kStrided +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kStrided + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; +}; + +/// Defines a kernel for Conv2dDgrad specialzation for Analytic IteratorAlgorithm Dgrad Strided +// and 2 stage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic, + StrideSupport::kStrided +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kStrided + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dDgrad specialzation for Analytic IteratorAlgorithm Dgrad Unity Strided +// and multistage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic, + StrideSupport::kUnity +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kUnity + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; +}; + +/// Defines a kernel for Conv2dDgrad specialzation for Analytic IteratorAlgorithm Dgrad Unity +// 2 stage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic, + StrideSupport::kUnity +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kUnity + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dDgrad specialzation for optimized IteratorAlgorithm Dgrad Unity Strided +// and multistage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kOptimized, + StrideSupport::kUnity +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kUnity + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; +}; + +/// Defines a kernel for Conv2dDgrad specialzation for Optimized IteratorAlgorithm Dgrad Unity +// 2 stage pipeline +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kOptimized, + StrideSupport::kUnity +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kUnity + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// +// OpClassSimt convolutions +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv2dDgrad specialzation for Analytic IteratorAlgorithm, +/// multi-stage pipeline, and FFMA-based mainloop for SM80 + +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic, + StrideSupport::kStrided +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kStrided + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dDgrad specialzation for Optimized IteratorAlgorithm, +/// multi-stage pipeline, and FFMA-based mainloop for SM80 + +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kOptimized, + StrideSupport::kUnity +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kUnity + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dDgrad specialzation for Analytic IteratorAlgorithm, +/// 2 stage pipeline, and FFMA-based mainloop for SM50 +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic, + StrideSupport::kStrided +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kStrided + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dDgrad specialzation for Optimized IteratorAlgorithm, +/// 2 stage pipeline, and FFMA-based mainloop for SM50 +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kOptimized, + StrideSupport::kUnity +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kUnity + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dDgradFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad + >; + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + + +} // namespace kernel +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/kernel/default_conv2d_fprop.h b/include/cutlass/conv/kernel/default_conv2d_fprop.h new file mode 100644 index 000000000..c38d5150b --- /dev/null +++ b/include/cutlass/conv/kernel/default_conv2d_fprop.h @@ -0,0 +1,1379 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: +namespace conv { + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief + Default kernel-level implicit GEMM convolution definitions combine threadblock-scoped + matrix multiply-add with the appropriate threadblock-scoped epilogue. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/conv/kernel/default_conv2d.h" + +#include "cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_optimized.h" +#include "cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_optimized.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace kernel { + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv2dFprop +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag, + conv::IteratorAlgorithm IteratorAlgorithm = IteratorAlgorithm::kAnalytic, + conv::StrideSupport StrideSupport = StrideSupport::kStrided +> struct DefaultConv2dFprop; + +///////////////////////////////////////////////////////////////////////////////////////////////// +// OpClassTensorOp convolutions +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Analytic IteratorAlgorithm and multistage +/// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassTensorOp, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, LayoutA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, LayoutB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Analytic IteratorAlgorithm and multistage +/// pipeline with interleaved layout. +template < + typename ElementA, + typename ElementB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag, + int InterleavedK +> +struct DefaultConv2dFprop < + ElementA, + layout::TensorNCxHWx, + ElementB, + layout::TensorCxRSKx, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajorInterleaved, + ElementB, layout::RowMajorInterleaved, + ElementAccumulator, LayoutC, arch::OpClassTensorOp, + Stages, MathOperatorTag, true>; + + // Define iterators over tiles from the A operand + // Note GEMM shared memory threadmap is used here because conv global memory + // layout needs to be mapped to fprop which is similar to the crosswise + // layout which is used by the interleaved GEMM shared memory threadmap. + // The Interleaved GEMM global memory layout is similar to the congruous + // layout. + using ThreadMapA = typename MmaCore::SmemThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, layout::TensorNCxHWx, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + // Note GEMM shared memory threadmap is used here because conv global memory + // layout needs to be mapped to fprop which is similar to the crosswise + // layout which is used by the interleaved GEMM shared memory threadmap. + // The Interleaved GEMM global memory layout is similar to the congruous + // layout. + using ThreadMapB = typename MmaCore::SmemThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, layout::TensorCxRSKx, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultInterleavedConvEpilogue< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount, + InterleavedK + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Analytic IteratorAlgorithm +/// and 2 stage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassTensorOp, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, LayoutA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, LayoutB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Analytic IteratorAlgorithm and 2 stage +/// pipeline with interleaved layout. +template < + typename ElementA, + typename ElementB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag, + int InterleavedK +> +struct DefaultConv2dFprop < + ElementA, + layout::TensorNCxHWx, + ElementB, + layout::TensorCxRSKx, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajorInterleaved, + ElementB, layout::RowMajorInterleaved, + ElementAccumulator, LayoutC, arch::OpClassTensorOp, + 2, MathOperatorTag, true>; + + // Define iterators over tiles from the A operand + // Note GEMM shared memory threadmap is used here because conv global memory + // layout needs to be mapped to fprop which is similar to the crosswise + // layout which is used by the interleaved GEMM shared memory threadmap. + // The Interleaved GEMM global memory layout is similar to the congruous + // layout. + using ThreadMapA = typename MmaCore::SmemThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, layout::TensorNCxHWx, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + // Note GEMM shared memory threadmap is used here because conv global memory + // layout needs to be mapped to fprop which is similar to the crosswise + // layout which is used by the interleaved GEMM shared memory threadmap. + // The Interleaved GEMM global memory layout is similar to the congruous + // layout. + using ThreadMapB = typename MmaCore::SmemThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, layout::TensorCxRSKx, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultInterleavedConvEpilogue< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount, + InterleavedK + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Optimzed IteratorAlgorithm and +/// multistage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassTensorOp, + Stages, MathOperatorTag + >; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + LayoutA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + LayoutB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Optimzed IteratorAlgorithm and +// multistage pipeline with interleaved layout. +template < + typename ElementA, + typename ElementB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag, + int InterleavedK +> +struct DefaultConv2dFprop < + ElementA, + layout::TensorNCxHWx, + ElementB, + layout::TensorCxRSKx, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajorInterleaved, + ElementB, layout::RowMajorInterleaved, ElementAccumulator, LayoutC, arch::OpClassTensorOp, + Stages, MathOperatorTag, true + >; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::SmemThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + layout::TensorNCxHWx, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::SmemThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + layout::TensorCxRSKx, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultInterleavedConvEpilogue< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount, + InterleavedK + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Optimized IteratorAlgorithm +/// and 2 stage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassTensorOp, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + LayoutA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + LayoutB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Optimized IteratorAlgorithm and 2 stage +/// pipeline with interleaved layout. +template < + typename ElementA, + typename ElementB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag, + int InterleavedK +> +struct DefaultConv2dFprop < + ElementA, + layout::TensorNCxHWx, + ElementB, + layout::TensorCxRSKx, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajorInterleaved, + ElementB, layout::RowMajorInterleaved, + ElementAccumulator, LayoutC, arch::OpClassTensorOp, + 2, MathOperatorTag, true>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::SmemThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, layout::TensorNCxHWx, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::SmemThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, layout::TensorCxRSKx, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultInterleavedConvEpilogue< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount, + InterleavedK + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// +// OpClassSimt convolutions +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv2dFprop specialzation for Analytic IteratorAlgorithm, +/// multi-stage pipeline, and FFMA-based mainloop for SM80 + +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, LayoutA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, LayoutB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Optimized IteratorAlgorithm, +/// multi-stage pipeline, and FFMA-based mainloop for SM80 + +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + LayoutA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + LayoutB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Analytic IteratorAlgorithm, +/// 2 stage pipeline, and FFMA-based mainloop for SM50 +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, LayoutA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, LayoutB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Optimized IteratorAlgorithm, +/// 2 stage pipeline, and FFMA-based mainloop for SM50 +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + LayoutA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dFpropFilterTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + LayoutB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace kernel +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/kernel/default_conv2d_wgrad.h b/include/cutlass/conv/kernel/default_conv2d_wgrad.h new file mode 100644 index 000000000..c7912203a --- /dev/null +++ b/include/cutlass/conv/kernel/default_conv2d_wgrad.h @@ -0,0 +1,928 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief + Default kernel-level implicit GEMM convolution definitions combine threadblock-scoped + matrix multiply-add with the appropriate threadblock-scoped epilogue. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/conv/kernel/default_conv2d.h" + +#include "cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_optimized.h" +#include "cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_optimized.h" +#include "cutlass/conv/threadblock/conv2d_tile_iterator.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace kernel { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag, + conv::IteratorAlgorithm IteratorAlgorithm = IteratorAlgorithm::kAnalytic, + conv::StrideSupport StrideSupport = StrideSupport::kStrided +> struct DefaultConv2dWgrad; +///////////////////////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////////////////// +// OpClassTensorOp convolutions +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad specialzation for Analytic IteratorAlgorithm and multistage +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dWgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dWgradActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad + >; +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad specialzation for Analytic IteratorAlgorithm and two +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dWgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dWgradActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad specialzation for Optimized IteratorAlgorithm and multistage +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dWgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dWgradActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad + >; +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad specialzation for Optimized IteratorAlgorithm and two +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dWgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dWgradActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// +// OpClassSimt convolutions +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv2dWgrad specialzation for Analytic IteratorAlgorithm, +/// multi-stage pipeline, and FFMA-based mainloop for SM80 + +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dWgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dWgradActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad specialzation for Optimized IteratorAlgorithm, +/// multi-stage pipeline, and FFMA-based mainloop for SM80 + +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv2dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv2dWgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv2dWgradActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad specialzation for Analytic IteratorAlgorithm, +/// 2 stage pipeline, and FFMA-based mainloop for SM50 +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dWgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dWgradActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad + >; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad specialzation for Optimized IteratorAlgorithm, +/// 2 stage pipeline, and FFMA-based mainloop for SM50 +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv2dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassSimt, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, arch::OpClassSimt, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dWgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv2dWgradActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaSimtOp = typename MmaCore::MmaWarpSimt; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + WarpMmaSimtOp, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad + >; + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + + +} // namespace kernel +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/kernel/default_conv3d_dgrad.h b/include/cutlass/conv/kernel/default_conv3d_dgrad.h new file mode 100644 index 000000000..a92b4bfb6 --- /dev/null +++ b/include/cutlass/conv/kernel/default_conv3d_dgrad.h @@ -0,0 +1,184 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief + Default kernel-level implicit GEMM convolution definitions combine threadblock-scoped + matrix multiply-add with the appropriate threadblock-scoped epilogue. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/conv/kernel/default_conv2d.h" + +#include "cutlass/conv/threadblock/conv3d_dgrad_output_gradient_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv3d_dgrad_filter_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv2d_tile_iterator.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace kernel { + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv2dDgrad +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag, + conv::IteratorAlgorithm IteratorAlgorithm = IteratorAlgorithm::kAnalytic, + conv::StrideSupport StrideSupport = StrideSupport::kStrided +> struct DefaultConv3dDgrad; + +/// Defines a kernel for Conv2dDgrad specialzation for Analytic IteratorAlgorithm Dgrad Strided +// and multistage pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv3dDgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic, + StrideSupport::kStrided +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv3dDgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA, + StrideSupport::kStrided + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv3dDgradFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kDgrad, + Conv3dProblemSize + >; +}; + + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace kernel +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/kernel/default_conv3d_fprop.h b/include/cutlass/conv/kernel/default_conv3d_fprop.h new file mode 100644 index 000000000..7694c8b9e --- /dev/null +++ b/include/cutlass/conv/kernel/default_conv3d_fprop.h @@ -0,0 +1,181 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief + Default kernel-level implicit GEMM convolution definitions combine threadblock-scoped + matrix multiply-add with the appropriate threadblock-scoped epilogue. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/conv/kernel/default_conv2d.h" + +#include "cutlass/conv/threadblock/conv3d_fprop_activation_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv3d_fprop_filter_tile_access_iterator_analytic.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace kernel { + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv2dFprop +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag, + conv::IteratorAlgorithm IteratorAlgorithm = IteratorAlgorithm::kAnalytic, + conv::StrideSupport StrideSupport = StrideSupport::kStrided +> struct DefaultConv3dFprop; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dFprop specialzation for Analytic IteratorAlgorithm and multistage +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv3dFprop < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + arch::OpClassTensorOp, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::RowMajor, + ElementB, layout::ColumnMajor, ElementAccumulator, layout::RowMajor, arch::OpClassTensorOp, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv3dFpropActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv3dFpropFilterTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Global, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kFprop, + Conv3dProblemSize + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace kernel +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/kernel/default_conv3d_wgrad.h b/include/cutlass/conv/kernel/default_conv3d_wgrad.h new file mode 100644 index 000000000..b0f5b9155 --- /dev/null +++ b/include/cutlass/conv/kernel/default_conv3d_wgrad.h @@ -0,0 +1,504 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief + Default kernel-level implicit GEMM convolution definitions combine threadblock-scoped + matrix multiply-add with the appropriate threadblock-scoped epilogue. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/conv/kernel/default_conv2d.h" + +#include "cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_analytic.h" +#include "cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_optimized.h" +#include "cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_optimized.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace kernel { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv2dWgrad +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag, + conv::IteratorAlgorithm IteratorAlgorithm = IteratorAlgorithm::kAnalytic, + conv::StrideSupport StrideSupport = StrideSupport::kStrided +> struct DefaultConv3dWgrad; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv3dWgrad specialzation for Analytic IteratorAlgorithm and multistage +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv3dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv3dWgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv3dWgradActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad, + Conv3dProblemSize + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv3dWgrad specialzation for Analytic IteratorAlgorithm and two +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv3dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kAnalytic +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv3dWgradOutputGradientTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv3dWgradActivationTileAccessIteratorAnalytic< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad, + Conv3dProblemSize + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Defines a kernel for Conv3dWgrad specialzation for Optimized IteratorAlgorithm and multistage +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + int Stages, + typename MathOperatorTag +> +struct DefaultConv3dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + Stages, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + Stages, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::Conv3dWgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::Conv3dWgradActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmMultistage< + ThreadblockShape, + IteratorA, + SmemIteratorA, + arch::CacheOperation::Always, + IteratorB, + SmemIteratorB, + arch::CacheOperation::Always, + MmaPolicy, + Stages + >; + + // Define the epilogue + using Epilogue = typename epilogue::threadblock::DefaultEpilogueTensorOp< + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad, + Conv3dProblemSize + >; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Defines a kernel for Conv3dWgrad specialzation for Optimized IteratorAlgorithm and two +// pipeline. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementAccumulator, + typename OperatorClass, + typename ArchTag, + typename ThreadblockShape, + typename WarpShape, + typename InstructionShape, + typename EpilogueOutputOp, + typename ThreadblockSwizzle, + typename MathOperatorTag +> +struct DefaultConv3dWgrad < + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + OperatorClass, + ArchTag, + ThreadblockShape, + WarpShape, + InstructionShape, + EpilogueOutputOp, + ThreadblockSwizzle, + 2, + MathOperatorTag, + IteratorAlgorithm::kOptimized +> { + + // Define the core components from GEMM + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, WarpShape, InstructionShape, ElementA, layout::ColumnMajor, + ElementB, layout::RowMajor, ElementAccumulator, layout::RowMajor, OperatorClass, + 2, MathOperatorTag>; + + // Define iterators over tiles from the A operand + using ThreadMapA = typename MmaCore::IteratorThreadMapA; + using IteratorA = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv3dWgradOutputGradientTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementA, + ThreadMapA + > + >; + + using SmemIteratorA = typename MmaCore::SmemIteratorA; + + // Define iterators over tiles from the B operand + using ThreadMapB = typename MmaCore::IteratorThreadMapB; + using IteratorB = + cutlass::conv::threadblock::TileIterator< + cutlass::conv::threadblock::Conv3dWgradActivationTileAccessIteratorOptimized< + cutlass::MatrixShape, + ElementB, + ThreadMapB + > + >; + + using SmemIteratorB = typename MmaCore::SmemIteratorB; + + // Warp-level GEMM components + using WarpMmaTensorOp = typename MmaCore::MmaTensorOp; + using MmaPolicy = typename MmaCore::MmaPolicy; + + // Define the Mma + using Mma = threadblock::ImplicitGemmPipelined< + ThreadblockShape, + IteratorA, + SmemIteratorA, + IteratorB, + SmemIteratorB, + ElementC, + LayoutC, + MmaPolicy + >; + + // Define the epilogue + using Epilogue = typename detail::DefaultConvEpilogue< + ArchTag, + ThreadblockShape, + WarpMmaTensorOp, + 1, + EpilogueOutputOp + >::Epilogue; + + // Define the kernel + using Kernel = cutlass::conv::kernel::ImplicitGemmConvolution< + Mma, + Epilogue, + ThreadblockSwizzle, + conv::Operator::kWgrad, + Conv3dProblemSize + >; +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace kernel +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/kernel/implicit_gemm_convolution.h b/include/cutlass/conv/kernel/implicit_gemm_convolution.h new file mode 100644 index 000000000..2ec156688 --- /dev/null +++ b/include/cutlass/conv/kernel/implicit_gemm_convolution.h @@ -0,0 +1,424 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Template for a pipelined Implicit GEMM kernel. +*/ + +#pragma once + +#include "cutlass/cutlass.h" + +#include "cutlass/aligned_buffer.h" +#include "cutlass/array.h" +#include "cutlass/numeric_types.h" +#include "cutlass/matrix_shape.h" +#include "cutlass/semaphore.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/gemm/gemm.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/conv3d_problem_size.h" +#include "cutlass/epilogue/threadblock/output_iterator_parameter.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace kernel { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate + typename Epilogue_, ///! Epilogue + typename ThreadblockSwizzle_, ///! Threadblock swizzling function + conv::Operator ConvOperator, ///! Convolutional operator (Fprop, Dgrad, Wgrad) + typename ConvProblemSize_ = Conv2dProblemSize ///! Convolutional operator on 2D or 3D problem +> +struct ImplicitGemmConvolution { + + using Mma = Mma_; + using Epilogue = Epilogue_; + using EpilogueOutputOp = typename Epilogue::OutputOp; + using ThreadblockSwizzle = ThreadblockSwizzle_; + static Operator const kConvolutionalOperator = ConvOperator; + + using ElementA = typename Mma::IteratorA::Element; + using LayoutA = typename Mma::IteratorA::Layout; + using ElementB = typename Mma::IteratorB::Element; + using LayoutB = typename Mma::IteratorB::Layout; + using ElementC = typename EpilogueOutputOp::ElementOutput; + + /// Set output tensor C layout + using LayoutC = LayoutA; + + using ElementAccumulator = typename EpilogueOutputOp::ElementAccumulator; + using ElementCompute = typename EpilogueOutputOp::ElementCompute; + + using WarpMmaOperator = typename Mma::Policy::Operator; + + using ArchMmaOperator = typename WarpMmaOperator::ArchMmaOperator; + using MathOperator = typename ArchMmaOperator::Operator; + + using OperatorClass = typename WarpMmaOperator::OperatorClass; + using ArchTag = typename WarpMmaOperator::ArchTag; + + using ThreadblockShape = typename Mma::Shape; + using WarpShape = typename WarpMmaOperator::Shape; + using InstructionShape = typename ArchMmaOperator::Shape; + + static int const kStages = Mma::kStages; + static IteratorAlgorithm const kIteratorAlgorithm = Mma::IteratorA::kIteratorAlgorithm; + + /// Warp count (concept: GemmShape) + using WarpCount = typename Mma::WarpCount; + static int const kThreadCount = 32 * WarpCount::kCount; + + using TensorRefA = typename Mma::IteratorA::TensorRef; + using TensorRefB = typename Mma::IteratorB::TensorRef; + using TensorRefC = cutlass::TensorRef; + + /// Check iterator A and B convolution dimension are the same and + // set device::ImplicitGemmConvolution::kConvDim + static_assert(Mma::IteratorA::kConvDim == Mma::IteratorB::kConvDim, + "Convolution on different different dimensions is not supported"); + static int const kConvDim = Mma::IteratorA::kConvDim; + + /// Conv dimension and problem size structure (Conv2d or Conv3d) + using ConvProblemSize = ConvProblemSize_; + + /// Wgrad C stride idx for implicit gemm algorithm + // Conv2d row-major matrix C (KxRSC) + // Conv3d row-major matrix C (KxTRSC) + static int const kWgradCStrideIdx = + cutlass::platform::is_same::value ? 2 : 3; + + /// This chooses the appropriate stride element of the C tensor. + static int const kTensorCStrideIdx = + (kConvolutionalOperator == conv::Operator::kWgrad ? kWgradCStrideIdx : 0); + + // + // + // + using ConvOutputIteratorParameter = epilogue::threadblock::ConvOutputIteratorParameter< + LayoutC, + typename Epilogue::OutputTileIterator::Layout, + TensorRefC, + ConvOperator, + ConvProblemSize + >; + + /// Argument structure + struct Arguments { + + // + // Data members + // + + ConvProblemSize problem_size; + TensorRefA ref_A; + TensorRefB ref_B; + TensorRefC ref_C; + TensorRefC ref_D; + typename EpilogueOutputOp::Params output_op; + SplitKMode split_k_mode; + + // + // Methods + // + + /// Default ctor + CUTLASS_HOST_DEVICE + Arguments() { } + + CUTLASS_HOST_DEVICE + Arguments( + ConvProblemSize const & problem_size + ): + problem_size(problem_size) { } + + CUTLASS_HOST_DEVICE + Arguments( + ConvProblemSize const & problem_size, + TensorRefA const & ref_A, + TensorRefB const & ref_B, + TensorRefC const & ref_C, + TensorRefC const & ref_D, + typename EpilogueOutputOp::Params const & output_op, + SplitKMode const & split_k_mode = SplitKMode::kSerial + ): + problem_size(problem_size), + ref_A(ref_A), + ref_B(ref_B), + ref_C(ref_C), + ref_D(ref_D), + output_op(output_op), + split_k_mode(split_k_mode) + { + + } + + }; + + /// Parameters structure + struct Params { + ConvProblemSize problem_size; + cutlass::gemm::GemmCoord grid_tiled_shape; + gemm::GemmCoord implicit_gemm_problem_size; + int gemm_k_iterations; + typename Mma::IteratorA::Params iterator_A; + typename Mma::IteratorA::Element const *ptr_A; + typename Mma::IteratorB::Params iterator_B; + typename Mma::IteratorB::Element const *ptr_B; + typename Epilogue::OutputTileIterator::Params iterator_C; + typename Epilogue::OutputTileIterator::Element *ptr_C; + typename Epilogue::OutputTileIterator::Params iterator_D; + typename Epilogue::OutputTileIterator::Element *ptr_D; + typename EpilogueOutputOp::Params output_op; + int *semaphore; + SplitKMode split_k_mode; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Params(): gemm_k_iterations(0) { } + + /// + CUTLASS_HOST_DEVICE + Params( + Arguments const &args, + int *semaphore = nullptr + ): + problem_size(args.problem_size), + implicit_gemm_problem_size(cutlass::conv::implicit_gemm_problem_size(kConvolutionalOperator, args.problem_size)), + grid_tiled_shape(grid_tiled_shape), + iterator_A(args.problem_size, args.ref_A.layout()), + ptr_A(args.ref_A.data()), + iterator_B(args.problem_size, args.ref_B.layout()), + ptr_B(args.ref_B.data()), + iterator_C(ConvOutputIteratorParameter::layout(args.ref_C)), + ptr_C(args.ref_C.data()), + iterator_D(ConvOutputIteratorParameter::layout(args.ref_D)), + ptr_D(args.ref_D.data()), + output_op(args.output_op), + semaphore(semaphore), + split_k_mode(args.split_k_mode) + { + gemm_k_iterations = implicit_gemm_k_iterations(kConvolutionalOperator, ThreadblockShape::kK, args.problem_size); + + ThreadblockSwizzle threadblock_swizzle; + + grid_tiled_shape = threadblock_swizzle.get_tiled_shape( + implicit_gemm_problem_size, + {ThreadblockShape::kM, ThreadblockShape::kN, ThreadblockShape::kK}, + args.problem_size.split_k_slices); + } + }; + + /// Shared memory storage structure + union SharedStorage { + typename Mma::SharedStorage main_loop; + typename Epilogue::SharedStorage epilogue; + }; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + ImplicitGemmConvolution() { } + + /// Executes one ImplicitGEMM + CUTLASS_DEVICE + void operator()(Params const ¶ms, SharedStorage &shared_storage) { + + // Compute threadblock location + ThreadblockSwizzle threadblock_swizzle; + + cutlass::gemm::GemmCoord threadblock_tile_idx = + threadblock_swizzle.get_tile_offset(params.grid_tiled_shape); + + // Early exit if CTA is out of range + if (params.grid_tiled_shape.m() <= threadblock_tile_idx.m() || + params.grid_tiled_shape.n() <= threadblock_tile_idx.n()) { + + return; + } + + // Compute position within threadblock + int thread_idx = threadIdx.x; + + // Construct iterators to A and B operands + typename Mma::IteratorA iterator_A( + params.iterator_A, + params.problem_size, + params.ptr_A, + thread_idx, + MatrixCoord( + threadblock_tile_idx.m() * Mma::Shape::kM, + threadblock_tile_idx.k() * Mma::Shape::kK + ) + ); + + typename Mma::IteratorB iterator_B( + params.iterator_B, + params.problem_size, + params.ptr_B, + thread_idx, + MatrixCoord( + threadblock_tile_idx.k() * Mma::Shape::kK, + threadblock_tile_idx.n() * Mma::Shape::kN + ) + ); + + // Broadcast the warp_id computed by lane 0 to ensure dependent code + // is compiled as warp-uniform. + int warp_idx = __shfl_sync(0xffffffff, threadIdx.x / 32, 0); + int lane_idx = threadIdx.x % 32; + + // + // Main loop + // + + // Construct thread-scoped matrix multiply + Mma mma(shared_storage.main_loop, thread_idx, warp_idx, lane_idx); + + typename Mma::FragmentC accumulators; + + accumulators.clear(); + + // Compute threadblock-scoped matrix multiply-add + mma(params.gemm_k_iterations, accumulators, iterator_A, iterator_B, accumulators); + + // + // Epilogue + // + + EpilogueOutputOp output_op(params.output_op); + + // Construct the semaphore. + int block_idx = threadblock_tile_idx.m() + threadblock_tile_idx.n() * params.grid_tiled_shape.m(); + + Semaphore semaphore(params.semaphore + block_idx, thread_idx); + + // Compute logical position within grid + threadblock_tile_idx = + threadblock_swizzle.get_tile_offset(params.grid_tiled_shape); + + // If performing a reduction via split-K, fetch the initial synchronization + if (params.split_k_mode == SplitKMode::kSerial && params.grid_tiled_shape.k() > 1) { + + // Fetch the synchronization lock initially but do not block. + semaphore.fetch(); + + // Indicate which position in a serial reduction the output operator is currently updating + output_op.set_k_partition(threadblock_tile_idx.k(), params.grid_tiled_shape.k()); + } + + MatrixCoord threadblock_offset( + threadblock_tile_idx.m() * Mma::Shape::kM, + threadblock_tile_idx.n() * Mma::Shape::kN + ); + + // Tile iterator writing to destination tensor + typename Epilogue::OutputTileIterator iterator_D( + params.iterator_D, + params.ptr_D, + ConvOutputIteratorParameter::extent(params.problem_size), + thread_idx, + threadblock_offset + ); + + // Tile iterator reading from source accumulator tensor + typename Epilogue::OutputTileIterator iterator_C( + params.iterator_C, + params.ptr_C, + ConvOutputIteratorParameter::extent(params.problem_size), + thread_idx, + threadblock_offset + ); + + + // Construct the epilogue + Epilogue epilogue( + shared_storage.epilogue, + thread_idx, + warp_idx, + lane_idx); + + // Wait on the semaphore - this latency may have been covered by iterator construction + if (params.split_k_mode == SplitKMode::kSerial && params.grid_tiled_shape.k() > 1) { + + // For subsequent threadblocks, the source matrix is held in the 'D' tensor. + if (threadblock_tile_idx.k()) { + iterator_C = iterator_D; + } + + semaphore.wait(threadblock_tile_idx.k()); + + __threadfence(); + } + // Each split-k-slice writes to a unique tensor location + else if (params.split_k_mode == SplitKMode::kParallel) { + iterator_D.add_pointer_offset(threadblock_tile_idx.k() * + cutlass::conv::implicit_gemm_tensor_c_size(ConvOperator, params.problem_size)); + } + + // Run efficient epilogue + epilogue(output_op, iterator_D, accumulators, iterator_C); + + // + // Release the semaphore + // + + if (params.split_k_mode == SplitKMode::kSerial && params.grid_tiled_shape.k() > 1) { + + int lock = 0; + if (params.grid_tiled_shape.k() == threadblock_tile_idx.k() + 1) { + + // The final threadblock resets the semaphore for subsequent grids. + lock = 0; + } + else { + // Otherwise, the semaphore is incremented + lock = threadblock_tile_idx.k() + 1; + } + + semaphore.release(lock); + } + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace kernel +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_analytic.h new file mode 100644 index 000000000..14c8a4e82 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_analytic.h @@ -0,0 +1,240 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (filter tile) + matrix from memory. + + This iterator assumes TensorNHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv2dDgradFilterTileAccessIteratorAnalytic { +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "DGRAD requires elements of size 8b or larger."); + + // + // Parameters structure + // + + using Params = Conv2dAnalyticParams; + +private: + + Params const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + // For a fixed filter position (r,s) find and fill offset_k_, offset_c_ in strided and contiguous dimension + int filter_r_; + int filter_s_; + int offset_k_[ThreadMap::Iterations::kStrided]; + int offset_c_[ThreadMap::Iterations::kContiguous]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dDgradFilterTileAccessIteratorAnalytic( + Params const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_r_(0), + filter_s_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + CUTLASS_PRAGMA_UNROLL + for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + offset_c_[c] = threadblock_offset.column() + thread_coord.contiguous() + + c * ThreadMap::Delta::kContiguous; + } + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_k_[s] = + threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_k_[s] += Shape::kRow * problem_size_.split_k_slices; + } + } + + /// Returns the coordinate in the filter tensor w that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int c = offset_c_[iteration_contiguous_]; + int k = offset_k_[iteration_strided_]; + + return TensorCoord(k, filter_r_, filter_s_, c); + } + + /// Returns true if the current coordinate is within the filter tensor w + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord coord = at(); + + return coord.n() < problem_size_.K && coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dDgradFilterTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_optimized.h b/include/cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_optimized.h new file mode 100644 index 000000000..f76dcde93 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_dgrad_filter_tile_access_iterator_optimized.h @@ -0,0 +1,283 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (filter tile) + matrix from memory. + + This iterator assumes TensorNHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" + +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_, + conv::StrideSupport StrideSupport_ = conv::StrideSupport::kUnity +> +class Conv2dDgradFilterTileAccessIteratorOptimized { +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kOptimized; + static StrideSupport const kStrideSupport = StrideSupport_; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + // + // Parameters structure + // + + struct Params : Conv2dDgradFilterIteratorOptimizedParams { + + // + // Methods + // + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params(Conv2dDgradFilterIteratorOptimizedParams const &base): + Conv2dDgradFilterIteratorOptimizedParams(base) { } + + CUTLASS_HOST_DEVICE + Params( + Conv2dProblemSize const &problem_size, + Layout const &layout + ): + Conv2dDgradFilterIteratorOptimizedParams( + problem_size, + layout, + sizeof_bits::value, + {Shape::kRow, Shape::kColumn}, + ThreadMap::kThreads, + ThreadMap::kElementsPerAccess, + {ThreadMap::Iterations::kContiguous, ThreadMap::Iterations::kStrided}, + {ThreadMap::Delta::kContiguous, ThreadMap::Delta::kStrided} + ) { } + + }; + +private: + + Conv2dDgradFilterIteratorOptimizedParams const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + uint32_t predicates_; + int filter_rs_; + int filter_k_; + + // + // Assertions + // + + // We map predicates into bits packed in this uint32_t container + static_assert(ThreadMap::Iterations::kStrided * + ThreadMap::Iterations::kContiguous < sizeof(predicates_) * 8, + "Currently, the number of loads per iteration is limited by the size of the predicates container."); + +public: + + CUTLASS_HOST_DEVICE + Conv2dDgradFilterTileAccessIteratorOptimized( + Conv2dDgradFilterIteratorOptimizedParams const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + predicates_(0), + filter_rs_(0), + filter_k_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_k_ = threadblock_offset.row() + thread_coord.strided(); + Index column = threadblock_offset.column() + thread_coord.contiguous(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + CUTLASS_PRAGMA_UNROLL + for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + + int filter_k = filter_k_ + s * ThreadMap::Delta::kStrided; + int filter_c = column + c * ThreadMap::Delta::kContiguous; + + uint32_t pred = ((filter_k < problem_size_.K && filter_c < problem_size_.C) ? 1u : 0); + + int pred_idx = c + s * ThreadMap::Iterations::kContiguous; + + predicates_ |= (pred << pred_idx); + } + } + + pointer_ += ( + filter_k_ * params.layout.stride()[2] + column + ) * sizeof_bits::value / 8; + + set_iteration_index(0); + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + + LongIndex next = params_.inc_next_rs; + + // moves to the next tile + ++filter_rs_; + if (filter_rs_ == params_.RS) { + + filter_rs_ = 0; + next = params_.inc_next_k; + filter_k_ += params_.filter_k_delta; + } + + // Clear predicates if needed + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + if (filter_k_ + s * ThreadMap::Delta::kStrided >= problem_size_.K) { + uint32_t kClearMask = ((1u << ThreadMap::Iterations::kContiguous) - 1) << (s * ThreadMap::Iterations::kContiguous); + predicates_ = (predicates_ & (~kClearMask)); + } + } + + pointer_ += next; + } + + /// Returns true if the current coordinate is within the filter tensor W + CUTLASS_HOST_DEVICE + bool valid() { + LongIndex pred_idx = iteration_contiguous_ + iteration_strided_ * ThreadMap::Iterations::kContiguous; + return (predicates_ & (1u << pred_idx)); + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + return reinterpret_cast(pointer_ + + iteration_contiguous_ * ThreadMap::Delta::kContiguous * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dDgradFilterTileAccessIteratorOptimized &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + + // Move to the next K coordinate within the tile + pointer_ += params_.inc_next_strided; + + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_analytic.h new file mode 100644 index 000000000..d32da7c3b --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_analytic.h @@ -0,0 +1,525 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (output gradient tile) + matrix from memory. + + This iterator assumes TensorNHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// +template < + typename Shape_, + typename Element_, + typename ThreadMap_, + conv::StrideSupport StrideSupport_ = conv::StrideSupport::kStrided +> +class Conv2dDgradOutputGradientTileAccessIteratorAnalytic; +///////////////////////////////////////////////////////////////////////////////////////////////// + +// Conv2dDgradOutputGradientTileAccessIteratorAnalytic strided dgrad needs special handling using +// unscaled coordinations +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv2dDgradOutputGradientTileAccessIteratorAnalytic < + Shape_, + Element_, + ThreadMap_, + conv::StrideSupport::kStrided +> { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "DGRAD requires elements of size 8b or greater."); + + // + // Simpligying assertions + // + + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + using Params = Conv2dAnalyticParams; + +private: + + Params const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_k_; + int filter_r_; + int filter_s_; + + int offset_n_[ThreadMap::Iterations::kStrided]; + int offset_w_[ThreadMap::Iterations::kStrided]; + int offset_h_[ThreadMap::Iterations::kStrided]; + +private: + + /// Returns the coordinate in the output tensor Dy that is currently pointed to + /// by the iterator but DOES NOT scale by the convolution stride. This is needed + /// to compute predicates in the valid() method. The return value of the public at() + /// method is correctly scaled. + CUTLASS_HOST_DEVICE + TensorCoord unscaled_at_() const { + int n = offset_n_[iteration_strided_]; + int h = offset_h_[iteration_strided_]; + int w = offset_w_[iteration_strided_]; + + int r = filter_r_; + int s = filter_s_; + + if (problem_size_.mode == Mode::kConvolution) { + r = (problem_size_.R - 1 - r); + s = (problem_size_.S - 1 - s); + } + + int p = (h + problem_size_.pad_h - r * problem_size_.dilation_h); + int q = (w + problem_size_.pad_w - s * problem_size_.dilation_w); + + return TensorCoord(n, p, q, filter_k_); + } + +public: + + CUTLASS_HOST_DEVICE + Conv2dDgradOutputGradientTileAccessIteratorAnalytic( + Params const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() // threadblock offset - units are whole CTA tiles + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_k_(0), + filter_r_(0), + filter_s_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_k_ = threadblock_offset.column() + thread_coord.contiguous(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + int offset_nhw = threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + + offset_n_[s] = offset_nhw / (problem_size_.H * problem_size_.W); + int residual = offset_nhw % (problem_size_.H * problem_size_.W); + + offset_h_[s] = residual / problem_size_.W; + offset_w_[s] = residual % problem_size_.W; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // move to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + + filter_k_ += Shape_::kColumn * problem_size_.split_k_slices; + } + + /// Returns the coordinate in the output tensor Dy that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + TensorCoord coord = unscaled_at_(); + + return TensorCoord( + coord.n(), + coord.h() / problem_size_.stride_h, + coord.w() / problem_size_.stride_w, + coord.c()); + } + + + /// Returns true if the current coordinate is within the output tensor Dy + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord unscaled_coord = unscaled_at_(); + TensorCoord coord = at(); + + return + !(unscaled_coord.h() % problem_size_.stride_h) && !(unscaled_coord.w() % problem_size_.stride_w) && + coord.n() < problem_size_.N && + coord.h() >= 0 && coord.h() < problem_size_.P && + coord.w() >= 0 && coord.w() < problem_size_.Q && + coord.c() < problem_size_.K; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dDgradOutputGradientTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +// Conv2dDgradOutputGradientTileAccessIteratorAnalytic for unity strides can be optimized by +// eliminating modulo arithmetic to compute unscaled coordinates +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv2dDgradOutputGradientTileAccessIteratorAnalytic < + Shape_, + Element_, + ThreadMap_, + conv::StrideSupport::kUnity +> { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kUnity; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "DGRAD requires elements of size 8b or greater."); + + // + // Simpligying assertions + // + + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + // + // Methods + // + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + Conv2dProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + } + }; + +private: + + Params const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_k_; + int filter_r_; + int filter_s_; + + int offset_n_[ThreadMap::Iterations::kStrided]; + int offset_w_[ThreadMap::Iterations::kStrided]; + int offset_h_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dDgradOutputGradientTileAccessIteratorAnalytic( + Params const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() // threadblock offset - units are whole CTA tiles + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_k_(0), + filter_r_(0), + filter_s_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_k_ = threadblock_offset.column() + thread_coord.contiguous(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + int offset_nhw = threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + + offset_n_[s] = offset_nhw / (problem_size_.H * problem_size_.W); + int residual = offset_nhw % (problem_size_.H * problem_size_.W); + + offset_h_[s] = residual / problem_size_.W; + offset_w_[s] = residual % problem_size_.W; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // move to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + + filter_k_ += Shape_::kColumn * problem_size_.split_k_slices; + } + + /// Returns the coordinate in the output tensor Dy that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int n = offset_n_[iteration_strided_]; + int h = offset_h_[iteration_strided_]; + int w = offset_w_[iteration_strided_]; + + int r = filter_r_; + int s = filter_s_; + + if (problem_size_.mode == Mode::kConvolution) { + r = (problem_size_.R - 1 - r); + s = (problem_size_.S - 1 - s); + } + + int p = (h + problem_size_.pad_h - r * problem_size_.dilation_h) / problem_size_.stride_h; + int q = (w + problem_size_.pad_w - s * problem_size_.dilation_w) / problem_size_.stride_w; + + return TensorCoord(n, p, q, filter_k_); + + } + + + /// Returns true if the current coordinate is within the output tensor Dy + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.h() >= 0 && coord.h() < problem_size_.P && + coord.w() >= 0 && coord.w() < problem_size_.Q && + coord.c() < problem_size_.K; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dDgradOutputGradientTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // Conv2dDgradFilterTileAccessIteratorAnalytic unity stride specialization + // only supports (stride_h, stride_w) = (1, 1) + if (problem_size.stride() != MatrixCoord({1, 1})) { + return Status::kErrorNotSupported; + } + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_optimized.h b/include/cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_optimized.h new file mode 100644 index 000000000..71299cf57 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_dgrad_output_gradient_tile_access_iterator_optimized.h @@ -0,0 +1,437 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (output gradient tile) + matrix from memory. + + This iterator assumes TensorNHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/matrix_shape.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_, + conv::StrideSupport StrideSupport_ = conv::StrideSupport::kUnity +> +class Conv2dDgradOutputGradientTileAccessIteratorOptimized { +public: + + static_assert(StrideSupport_ == conv::StrideSupport::kUnity, + "Only unit-stride dgrad is supported at this time."); + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using TensorCoord = typename Layout::TensorCoord; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kOptimized; + static StrideSupport const kStrideSupport = conv::StrideSupport::kUnity; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + using Mask = uint64_t; + + // + // Simplifying assertions + // + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + struct Params : Conv2dDgradOutputGradientIteratorOptimizedParams { + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params(Conv2dDgradOutputGradientIteratorOptimizedParams const &base): + Conv2dDgradOutputGradientIteratorOptimizedParams(base) { } + + CUTLASS_HOST_DEVICE + Params( + Conv2dProblemSize const &problem_size, + Layout const &layout + ): + Conv2dDgradOutputGradientIteratorOptimizedParams( + problem_size, + layout, + sizeof_bits::value, + {Shape::kRow, Shape::kColumn}, + ThreadMap::kThreads, + ThreadMap::kElementsPerAccess, + {ThreadMap::Iterations::kContiguous, ThreadMap::Iterations::kStrided}, + {ThreadMap::Delta::kContiguous, ThreadMap::Delta::kStrided} + ) { } + }; + +private: + + Conv2dDgradOutputGradientIteratorOptimizedParams const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + + // One pointer per access + char const *pointer_[ThreadMap::Iterations::kStrided]; + + // current filter position (r, s) + int filter_r_; + int filter_s_; + int filter_k_; + + Index masks_[ThreadMap::Iterations::kStrided][2]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dDgradOutputGradientTileAccessIteratorOptimized( + Conv2dDgradOutputGradientIteratorOptimizedParams const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() // tile index - units are threadblock-scoped tiles + ): + params_(params), + problem_size_(problem_size), + filter_k_(0), + filter_r_(0), + filter_s_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_k_ = threadblock_offset.column() + thread_coord.contiguous(); + + int offset_n[ThreadMap::Iterations::kStrided]; + int offset_h[ThreadMap::Iterations::kStrided]; + int offset_w[ThreadMap::Iterations::kStrided]; + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + + pointer_[s] = reinterpret_cast(ptr); + + int offset_nhw = threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + + // The subseqnet fast_divmod() operations are equivalent to the following logical computation: + // + // + // offset_n[s] = offset_nhw / (problem_size_.H * problem_size_.W); + // int residual = offset_nhw % (problem_size_.H * problem_size_.W); + // + // offset_h[s] = residual / problem_size_.W; + // offset_w[s] = residual % problem_size_.W; + // + + int residual; + + params_.hw_divmod(offset_n[s], residual, offset_nhw); + params_.w_divmod(offset_h[s], offset_w[s], residual); + + TensorCoord coord = at_(offset_n[s], offset_h[s], offset_w[s], 0, 0); + + pointer_[s] += params_.layout(coord) * sizeof_bits::value / 8; + } + + clear_mask(); + + CUTLASS_PRAGMA_NO_UNROLL + for (int r = 0; r < problem_size_.R; ++r) { + CUTLASS_PRAGMA_UNROLL + for (int s_idx = 0; s_idx < ThreadMap::Iterations::kStrided; ++s_idx) { + + int r_ = r; + if (problem_size_.mode == Mode::kConvolution) { + r_ = problem_size_.R - 1 - r; + } + + int p = offset_h[s_idx] + problem_size_.pad_h - r_ * problem_size_.dilation_h; + + bool pred = (offset_n[s_idx] < problem_size_.N && p >= 0 && p < problem_size_.P); + masks_[s_idx][0] |= (pred << r); + } + } + + CUTLASS_PRAGMA_NO_UNROLL + for (int s = 0; s < problem_size_.S; ++s) { + CUTLASS_PRAGMA_UNROLL + for (int s_idx = 0; s_idx < ThreadMap::Iterations::kStrided; ++s_idx) { + + int s_ = s; + if (problem_size_.mode == Mode::kConvolution) { + s_ = problem_size_.S - 1 - s; + } + + int q = offset_w[s_idx] + problem_size_.pad_w - s_ * problem_size_.dilation_w; + + bool pred = (q >= 0 && q < problem_size_.Q); + masks_[s_idx][1] |= (pred << s); + } + } + + if (filter_k_ >= problem_size.K) { + clear_mask(); + } + + set_iteration_index(0); + } + +private: + + /// Returns the coordinate in the output gradient tensor dy that is correspoinding to + // output nhw and filter position k, r, s + CUTLASS_HOST_DEVICE + TensorCoord at_(int n, int h, int w, int r, int s) const { + + if (problem_size_.mode == Mode::kConvolution) { + r = problem_size_.R - 1 - r; + s = problem_size_.S - 1 - s; + } + + int p = h + problem_size_.pad_h - r * problem_size_.dilation_h; + int q = w + problem_size_.pad_w - s * problem_size_.dilation_w; + + return TensorCoord(n, p, q, filter_k_); + } + + /// Adds a pointer offset in units of element + CUTLASS_HOST_DEVICE + void add_byte_offset_(LongIndex byte_offset) { + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + pointer_[s] += byte_offset; + } + } + + /// Clears the predicates + CUTLASS_HOST_DEVICE + void clear_mask_(bool clear) { + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + + // We are using inline PTX assembly here to avoid an CUDA C++ compilation + // artifact in which control flow instructions are generated. Instead, our + // intent is to predicate the mov instructions. + #if defined(__CUDA_ARCH__) + asm volatile( + "{\n" + " .reg .pred p;\n" + " .reg .u32 m;" + " mov.u32 m, %2;" + " setp.ne.b32 p, %1, 0;\n" + " @p mov.u32 m, 0;\n" + " mov.u32 %0, m;\n" + "}\n" + : + "=r"(masks_[s][0]) + : + "r"((int)clear), + "r"(masks_[s][0]) + ); + asm volatile( + "{\n" + " .reg .pred p;\n" + " .reg .u32 m;" + " mov.u32 m, %2;" + " setp.ne.b32 p, %1, 0;\n" + " @p mov.u32 m, 0;\n" + " mov.u32 %0, m;\n" + "}\n" + : + "=r"(masks_[s][1]) + : + "r"((int)clear), + "r"(masks_[s][1]) + ); + #else + if (clear) { + masks_[s][0] = 0; + masks_[s][1] = 0; + } + #endif + } + } + +public: + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + add_byte_offset_(pointer_offset * sizeof_bits::value / 8); + } + + CUTLASS_HOST_DEVICE + void advance() { + + int next_idx = 0; + + // moves to the next tile + ++filter_s_; + if (filter_s_ == problem_size_.S) { + filter_s_ = 0; + ++filter_r_; + + if (filter_r_ < problem_size_.R) { + next_idx = 1; + } + else { + filter_r_ = 0; + next_idx = 2; + } + } + + add_byte_offset_(params_.inc_next[next_idx]); + + if (next_idx == 2) { + filter_k_ += params_.filter_k_delta; + } + + clear_mask_(filter_k_ >= problem_size_.K); + } + + /// Clears the predicates + CUTLASS_HOST_DEVICE + void clear_mask() { + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + masks_[s][0] = Mask(0); + masks_[s][1] = Mask(0); + } + } + + CUTLASS_HOST_DEVICE + bool valid() { + + return + (masks_[iteration_strided_][0] & (Index(1) << filter_r_)) && + (masks_[iteration_strided_][1] & (Index(1) << filter_s_)); + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + return reinterpret_cast(pointer_[iteration_strided_]); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dDgradOutputGradientTileAccessIteratorOptimized &operator++() { + + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // This is specialized for unit stride + if (problem_size.stride() != MatrixCoord({1, 1})) { + return Status::kErrorNotSupported; + } + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorNotSupported; + } + + // Limit on filter size + if (problem_size.R > 32 || problem_size.S > 32) { + return Status::kErrorNotSupported; + } + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h new file mode 100644 index 000000000..92dd705d6 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h @@ -0,0 +1,274 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (activation tile) + matrix from memory. + + This iterator assumes TensorNHWC or TensorNCxHWx layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/matrix_shape.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename Layout_, + typename ThreadMap_ +> +class Conv2dFpropActivationTileAccessIteratorAnalytic { +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = Layout_; + using TensorCoord = typename Layout::TensorCoord; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + // + // Simplifying assertions + // + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + using Params = Conv2dAnalyticParams; + +private: + + Params const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_c_; + int filter_r_; + int filter_s_; + + int offset_n_[ThreadMap::Iterations::kStrided]; + int offset_p_[ThreadMap::Iterations::kStrided]; + int offset_q_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dFpropActivationTileAccessIteratorAnalytic( + Params const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() // tile index - units are threadblock-scoped tiles + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_c_(0), + filter_r_(0), + filter_s_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_c_ = threadblock_offset.column() + thread_coord.contiguous(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + int offset_npq = threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + + offset_n_[s] = offset_npq / (problem_size_.P * problem_size_.Q); + int residual = offset_npq % (problem_size_.P * problem_size_.Q); + + offset_p_[s] = residual / problem_size_.Q; + offset_q_[s] = residual % problem_size_.Q; + } + + set_iteration_index(0); + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + + filter_c_ += Shape::kColumn * problem_size_.split_k_slices; + } + + /// Returns the coordinate in the activations tensor X that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + int n = offset_n_[iteration_strided_]; + int p = offset_p_[iteration_strided_]; + int q = offset_q_[iteration_strided_]; + + int r = filter_r_; + int s = filter_s_; + + if (problem_size_.mode == Mode::kConvolution) { + r = (problem_size_.R - 1 - filter_r_); + s = (problem_size_.S - 1 - filter_s_); + } + + int h = p * problem_size_.stride_h - problem_size_.pad_h + r * problem_size_.dilation_h; + int w = q * problem_size_.stride_w - problem_size_.pad_w + s * problem_size_.dilation_w; + + return TensorCoord(n, h, w, filter_c_); + } + + /// Returns true if the current coordinate is within the activations tensor X + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.h() >= 0 && coord.h() < problem_size_.H && + coord.w() >= 0 && coord.w() < problem_size_.W && + coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + AccessType const *ptr = reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + + return ptr; + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dFpropActivationTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + if (platform::is_same>::value) { + if (problem_size.C % 32) { + return Status::kErrorInvalidProblem; + } + } + + if (platform::is_same>::value) { + if (problem_size.C % 64) { + return Status::kErrorInvalidProblem; + } + } + + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_optimized.h b/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_optimized.h new file mode 100644 index 000000000..afb015d35 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_optimized.h @@ -0,0 +1,438 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (activation tile) + matrix from memory. + + This iterator assumes TensorNHWC or TensorNCxHWx layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/matrix_shape.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename Layout_, + typename ThreadMap_ +> +class Conv2dFpropActivationTileAccessIteratorOptimized { +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = Layout_; + using TensorCoord = typename Layout::TensorCoord; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kOptimized; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + using Mask = uint64_t; + + // + // Simplifying assertions + // + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + struct Params : Conv2dFpropActivationIteratorOptimizedParams { + + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params(Conv2dFpropActivationIteratorOptimizedParams const &base): + Conv2dFpropActivationIteratorOptimizedParams(base) { } + + CUTLASS_HOST_DEVICE + Params( + Conv2dProblemSize const &problem_size, + Layout const &layout + ): + Conv2dFpropActivationIteratorOptimizedParams( + problem_size, + layout, + sizeof_bits::value, + {Shape::kRow, Shape::kColumn}, + ThreadMap::kThreads, + ThreadMap::kElementsPerAccess, + {ThreadMap::Iterations::kContiguous, ThreadMap::Iterations::kStrided}, + {ThreadMap::Delta::kContiguous, ThreadMap::Delta::kStrided} + ) { + + } + }; + +private: + + Conv2dFpropActivationIteratorOptimizedParams const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + + // One pointer per access + char const *pointer_[ThreadMap::Iterations::kStrided]; + + // current filter position (r, s) + int filter_r_; + int filter_s_; + int filter_c_; + + Index masks_[ThreadMap::Iterations::kStrided][2]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dFpropActivationTileAccessIteratorOptimized( + Conv2dFpropActivationIteratorOptimizedParams const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() // tile index - units are threadblock-scoped tiles + ): + params_(params), + problem_size_(problem_size), + filter_c_(0), + filter_r_(0), + filter_s_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_c_ = threadblock_offset.column() + thread_coord.contiguous(); + + int offset_n[ThreadMap::Iterations::kStrided]; + int offset_p[ThreadMap::Iterations::kStrided]; + int offset_q[ThreadMap::Iterations::kStrided]; + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + + pointer_[s] = reinterpret_cast(ptr); + + int offset_npq = threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + + // The subseqnet fast_divmod() operations are equivalent to the following logical computation: + // + // + // offset_n[s] = offset_npq / (problem_size_.P * problem_size_.Q); + // int residual = offset_npq % (problem_size_.P * problem_size_.Q); + // + // offset_p[s] = residual / problem_size_.Q; + // offset_q[s] = residual % problem_size_.Q; + // + + int residual; + + params.pq_divmod(offset_n[s], residual, offset_npq); + params.q_divmod(offset_p[s], offset_q[s], residual); + + TensorCoord coord = at_(offset_n[s], offset_p[s], offset_q[s], 0, 0); + + pointer_[s] += params_.layout(coord) * sizeof_bits::value / 8; + } + + clear_mask(); + + CUTLASS_PRAGMA_NO_UNROLL + for (int r = 0; r < problem_size_.R; ++r) { + CUTLASS_PRAGMA_UNROLL + for (int s_idx = 0; s_idx < ThreadMap::Iterations::kStrided; ++s_idx) { + + int r_ = r; + if (problem_size_.mode == Mode::kConvolution) { + r_ = problem_size_.R - 1 - r; + } + + int h = offset_p[s_idx] * problem_size_.stride_h - problem_size_.pad_h + r_ * problem_size_.dilation_h; + + bool pred = (offset_n[s_idx] < problem_size_.N && h >= 0 && h < problem_size_.H); + masks_[s_idx][0] |= (pred << r); + } + } + + CUTLASS_PRAGMA_NO_UNROLL + for (int s = 0; s < problem_size_.S; ++s) { + CUTLASS_PRAGMA_UNROLL + for (int s_idx = 0; s_idx < ThreadMap::Iterations::kStrided; ++s_idx) { + + int s_ = s; + if (problem_size_.mode == Mode::kConvolution) { + s_ = problem_size_.S - 1 - s; + } + + int w = offset_q[s_idx] * problem_size_.stride_w - problem_size_.pad_w + s_ * problem_size_.dilation_w; + + bool pred = (w >= 0 && w < problem_size_.W); + masks_[s_idx][1] |= (pred << s); + } + } + + if (filter_c_ >= problem_size.C) { + clear_mask(); + } + + set_iteration_index(0); + } + +private: + + /// Returns the coordinate in the activations tensor X that is correspoinding to + // output npq and filter position r, s + CUTLASS_HOST_DEVICE + TensorCoord at_(int n, int p, int q, int r, int s) const { + + if (problem_size_.mode == Mode::kConvolution) { + r = problem_size_.R - 1 - r; + s = problem_size_.S - 1 - s; + } + + int h = p * problem_size_.stride_h - problem_size_.pad_h + r * problem_size_.dilation_h; + int w = q * problem_size_.stride_w - problem_size_.pad_w + s * problem_size_.dilation_w; + + return TensorCoord(n, h, w, filter_c_); + } + + /// Adds a pointer offset in units of element + CUTLASS_HOST_DEVICE + void add_byte_offset_(LongIndex byte_offset) { + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + pointer_[s] += byte_offset; + } + } + + /// Clears the predicates + CUTLASS_HOST_DEVICE + void clear_mask_(bool clear) { + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + + // We are using inline PTX assembly here to avoid an CUDA C++ compilation + // artifact in which control flow instructions are generated. Instead, our + // intent is to predicate the mov instructions. + #if defined(__CUDA_ARCH__) + asm volatile( + "{\n" + " .reg .pred p;\n" + " .reg .u32 m;" + " mov.u32 m, %2;" + " setp.ne.b32 p, %1, 0;\n" + " @p mov.u32 m, 0;\n" + " mov.u32 %0, m;\n" + "}\n" + : + "=r"(masks_[s][0]) + : + "r"((int)clear), + "r"(masks_[s][0]) + ); + asm volatile( + "{\n" + " .reg .pred p;\n" + " .reg .u32 m;" + " mov.u32 m, %2;" + " setp.ne.b32 p, %1, 0;\n" + " @p mov.u32 m, 0;\n" + " mov.u32 %0, m;\n" + "}\n" + : + "=r"(masks_[s][1]) + : + "r"((int)clear), + "r"(masks_[s][1]) + ); + #else + if (clear) { + masks_[s][0] = 0; + masks_[s][1] = 0; + } + #endif + } + } + +public: + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + add_byte_offset_(pointer_offset * sizeof_bits::value / 8); + } + + CUTLASS_HOST_DEVICE + void advance() { + + int next_idx = 0; + + // moves to the next tile + ++filter_s_; + if (filter_s_ == problem_size_.S) { + filter_s_ = 0; + ++filter_r_; + + if (filter_r_ < problem_size_.R) { + next_idx = 1; + } + else { + filter_r_ = 0; + next_idx = 2; + } + } + + add_byte_offset_(params_.inc_next[next_idx]); + + if (next_idx == 2) { + filter_c_ += params_.filter_c_delta; + } + + clear_mask_(filter_c_ >= problem_size_.C); + } + + /// Clears the predicates + CUTLASS_HOST_DEVICE + void clear_mask() { + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + masks_[s][0] = Mask(0); + masks_[s][1] = Mask(0); + } + } + + CUTLASS_HOST_DEVICE + bool valid() { + + return + (masks_[iteration_strided_][0] & (Index(1) << filter_r_)) && + (masks_[iteration_strided_][1] & (Index(1) << filter_s_)); + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + return reinterpret_cast(pointer_[iteration_strided_]); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dFpropActivationTileAccessIteratorOptimized &operator++() { + + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + if (platform::is_same>::value) { + if (problem_size.C % 32) { + return Status::kErrorInvalidProblem; + } + } + + if (platform::is_same>::value) { + if (problem_size.C % 64) { + return Status::kErrorInvalidProblem; + } + } + + // Conv2dFpropActivationTileAccessIteratorOptimized has constraint on filter positions + // due to the number of mask bits. + if (problem_size.R > 32 || problem_size.S > 32) { + return Status::kErrorNotSupported; + } + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_analytic.h new file mode 100644 index 000000000..6547e9c5b --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_analytic.h @@ -0,0 +1,252 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (filter tile) + matrix from memory. + + This iterator assumes TensorNHWC or TensorCxRSKx layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename Layout_, + typename ThreadMap_ +> +class Conv2dFpropFilterTileAccessIteratorAnalytic { +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = Layout_; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + // + // Simplifying assertions + // + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + using Params = Conv2dAnalyticParams; + +private: + + Params const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_r_; + int filter_s_; + int filter_c_; + + int offset_k_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dFpropFilterTileAccessIteratorAnalytic( + Params const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_r_(0), + filter_s_(0), + filter_c_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_c_ = threadblock_offset.row() + thread_coord.contiguous(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_k_[s] = threadblock_offset.column() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + } + + set_iteration_index(0); + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * 8 / sizeof_bits::value; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + + filter_c_ += Shape::kRow * problem_size_.split_k_slices; + } + + /// Returns the coordinate in the filter tensor W that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int k = offset_k_[iteration_strided_]; + + return TensorCoord(k, filter_r_, filter_s_, filter_c_); + } + + /// Returns true if the current coordinate is within the activations tensor W + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord coord = at(); + + return coord.n() < problem_size_.K && + coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dFpropFilterTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + if (platform::is_same>::value) { + if (problem_size.K % 32) { + return Status::kErrorInvalidProblem; + } + } + + if (platform::is_same>::value) { + if (problem_size.K % 64) { + return Status::kErrorInvalidProblem; + } + } + + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_optimized.h b/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_optimized.h new file mode 100644 index 000000000..bf0d1d312 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_optimized.h @@ -0,0 +1,282 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (filter tile) + matrix from memory. + + This iterator assumes TensorNHWC or TensorCxRSKx layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" + +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename Layout_, + typename ThreadMap_ +> +class Conv2dFpropFilterTileAccessIteratorOptimized{ +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = Layout_; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kOptimized; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + // + // Simplifying assertions + // + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + struct Params : Conv2dFpropFilterIteratorOptimizedParams { + + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params(Conv2dFpropFilterIteratorOptimizedParams const &base): + Conv2dFpropFilterIteratorOptimizedParams(base) { } + + CUTLASS_HOST_DEVICE + Params( + Conv2dProblemSize const &problem_size, + Layout const &layout + ): + Conv2dFpropFilterIteratorOptimizedParams( + problem_size, + layout, + sizeof_bits::value, + {Shape::kRow, Shape::kColumn}, + ThreadMap::kThreads, + ThreadMap::kElementsPerAccess, + {ThreadMap::Iterations::kContiguous, ThreadMap::Iterations::kStrided}, + {ThreadMap::Delta::kContiguous, ThreadMap::Delta::kStrided} + ) { + + } + }; + +private: + + Conv2dFpropFilterIteratorOptimizedParams const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + uint32_t predicates_; + int filter_rs_; + int filter_c_; + + // + // Assertions + // + + // We map predicates into bits packed in this uint32_t container + static_assert(ThreadMap::Iterations::kStrided < sizeof(predicates_) * 8, + "Currently, the number of loads per iteration is limited by the size of the predicates container."); + +public: + + CUTLASS_HOST_DEVICE + Conv2dFpropFilterTileAccessIteratorOptimized( + Conv2dFpropFilterIteratorOptimizedParams const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + predicates_(0), + filter_rs_(0), + filter_c_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_c_ = threadblock_offset.row() + thread_coord.contiguous(); + Index column = threadblock_offset.column() + thread_coord.strided(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + uint32_t pred = ((column + s * ThreadMap::Delta::kStrided < problem_size_.K) ? 1u : 0); + predicates_ |= (pred << s); + } + + if (filter_c_ >= problem_size.C) { + predicates_ = 0u; + } + + pointer_ += ( + params_.layout({filter_c_, column}) + ) * sizeof_bits::value / 8; + + set_iteration_index(0); + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + + LongIndex next = params_.inc_next_rs; + + // moves to the next tile + ++filter_rs_; + if (filter_rs_ == params_.RS) { + + filter_rs_ = 0; + next = params_.inc_next_c; + filter_c_ += params_.filter_c_delta; + } + + if (filter_c_ >= problem_size_.C) { + predicates_ = 0; + } + + pointer_ += next; + } + + /// Returns true if the current coordinate is within the filter tensor W + CUTLASS_HOST_DEVICE + bool valid() { + return (predicates_ & (1u << iteration_strided_)); + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + return reinterpret_cast(pointer_); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dFpropFilterTileAccessIteratorOptimized &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + + // Move to the next K coordinate within the tile + pointer_ += params_.inc_next_k; + + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + if (platform::is_same>::value) { + if (problem_size.K % 32) { + return Status::kErrorInvalidProblem; + } + } + + if (platform::is_same>::value) { + if (problem_size.K % 64) { + return Status::kErrorInvalidProblem; + } + } + + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/threadblock/conv2d_params.h b/include/cutlass/conv/threadblock/conv2d_params.h new file mode 100644 index 000000000..ac6b2e309 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_params.h @@ -0,0 +1,609 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! + \file + \brief Extracts the host-params objects into non-template code. +*/ + +#pragma once + +#define TRACE_CONV_PARAMS_INITIALIZERS_ENABLED 0 + +#include "cutlass/cutlass.h" +#include "cutlass/fast_math.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" + +#if TRACE_CONV_PARAMS_INITIALIZERS_ENABLED +#include +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Params structure used for all Conv2d analytic tile iterators +template< typename Layout_ = layout::TensorNHWC > +struct Conv2dAnalyticParams { + + using Layout = Layout_; + + Layout layout; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Conv2dAnalyticParams() { } + + CUTLASS_HOST_DEVICE + Conv2dAnalyticParams( + Conv2dProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +#if TRACE_CONV_PARAMS_INITIALIZERS_ENABLED + +CUTLASS_HOST_DEVICE +void TraceIteratorParams( + char const *conv_operator, + char const *operand, + int element_size_bits, + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta +) { + +#if !defined(__CUDA_ARCH__) + + char const *fname = "conv_iterator_params.csv"; + + std::ifstream test(fname); + bool file_exists = test.is_open(); + + if (file_exists) { + test.close(); + } + + std::ofstream trace("conv_iterator_params.csv", std::ofstream::app); + + if (!file_exists) { + trace + << "Operator,Operand,ElementSize,CtaRows,CtaColumns,ThreadCount,AccessSize," + << "IterationsContiguous,IterationsStrided,DeltaContiguous,DeltaStrided\n"; + } + + trace << conv_operator << "," << operand << "," << element_size_bits << "," + << threadblock_shape.row() << "," << threadblock_shape.column() + << "," << thread_count << "," << access_size + << "," << threadmap_iterations.contiguous() << "," << threadmap_iterations.strided() + << "," << threadmap_delta.contiguous() << "," << threadmap_delta.strided() << "\n"; +#endif +} + +#define TRACE_CONV_INITIALIZERS(conv_op, operand, element_size, cta_shape, thread_count, access_size, iterations, delta) \ + TraceIteratorParams(conv_op, operand, element_size, cta_shape, thread_count, access_size, iterations, delta); + +#else + +#define TRACE_CONV_INITIALIZERS(conv_op, operand, element_size, cta_shape, thread_count, access_size, iterations, delta) {} + +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Parameters structure used for Conv2dFpropActivationTileIteratorOptimized +template< typename Layout_ = layout::TensorNHWC > +struct Conv2dFpropActivationIteratorOptimizedParams; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Parameters structure used for Conv2dFpropActivationTileIteratorOptimized +template<> +struct Conv2dFpropActivationIteratorOptimizedParams { + + using Layout = layout::TensorNHWC; + + Layout layout; + + int64_t inc_next[3]; // {next S, next R, next C} + int filter_c_delta; // number of logical elements to add to filter_c_ + int PQ; // product of P*Q + + FastDivmod pq_divmod; + FastDivmod q_divmod; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Conv2dFpropActivationIteratorOptimizedParams() { } + + CUTLASS_HOST_DEVICE + Conv2dFpropActivationIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout, ///< layout object + int element_size_bits, ///< size of each element in bits + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta + ): + layout(layout), PQ(problem_size.P * problem_size.Q), pq_divmod(PQ), q_divmod(problem_size.Q) { + + TRACE_CONV_INITIALIZERS("conv2d_fprop", "activation", + element_size_bits, threadblock_shape, thread_count, access_size, threadmap_iterations, threadmap_delta); + + int conv_sign = (problem_size.mode == Mode::kConvolution ? -1 : 1); + + // next S + inc_next[0] = conv_sign * (int64_t(layout.stride()[0]) * problem_size.dilation_w) * element_size_bits / 8; + + // next R + inc_next[1] = conv_sign * ( + int64_t(layout.stride()[1]) * problem_size.dilation_h + - (problem_size.S - 1) * layout.stride()[0] * problem_size.dilation_w + ) * element_size_bits / 8; + + // next C + inc_next[2] = ( + threadblock_shape.column() * problem_size.split_k_slices + - conv_sign * int64_t(problem_size.R - 1) * layout.stride()[1] * problem_size.dilation_h + - conv_sign * int64_t(problem_size.S - 1) * layout.stride()[0] * problem_size.dilation_w + ) * element_size_bits / 8; + + // logical offset added to internal channel counter - units are elements, not bytes + filter_c_delta = threadblock_shape.column() * problem_size.split_k_slices; + } +}; + +/// Parameters structure used for Conv2dFpropActivationTileIteratorOptimized +template +struct Conv2dFpropActivationIteratorOptimizedParams> { + static int const kInterleaved = Interleaved_; + + using Layout = layout::TensorNCxHWx; + + Layout layout; + + int64_t inc_next[3]; // {next S, next R, next C} + int filter_c_delta; // number of logical elements to add to filter_c_ + int PQ; // product of P*Q + + FastDivmod pq_divmod; + FastDivmod q_divmod; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Conv2dFpropActivationIteratorOptimizedParams() { } + + CUTLASS_HOST_DEVICE + Conv2dFpropActivationIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout, ///< layout object + int element_size_bits, ///< size of each element in bits + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta + ): + layout(layout), PQ(problem_size.P * problem_size.Q), pq_divmod(PQ), q_divmod(problem_size.Q) { + + TRACE_CONV_INITIALIZERS("conv2d_fprop", "activation", + element_size_bits, threadblock_shape, thread_count, access_size, threadmap_iterations, threadmap_delta); + + int conv_sign = (problem_size.mode == Mode::kConvolution ? -1 : 1); + + // next S + inc_next[0] = conv_sign * (kInterleaved * problem_size.dilation_w) * element_size_bits / 8; + + // next R + inc_next[1] = conv_sign * ( + int64_t(layout.stride()[0]) * problem_size.dilation_h + - (problem_size.S - 1) * kInterleaved * problem_size.dilation_w + ) * element_size_bits / 8; + + // next C + inc_next[2] = ( + threadblock_shape.column() * problem_size.split_k_slices / kInterleaved * int64_t(layout.stride()[1]) + - conv_sign * int64_t(problem_size.R - 1) * layout.stride()[0] * problem_size.dilation_h + - conv_sign * int64_t(problem_size.S - 1) * kInterleaved * problem_size.dilation_w + ) * element_size_bits / 8; + + // logical offset added to internal channel counter - units are elements, not bytes + filter_c_delta = threadblock_shape.column() * problem_size.split_k_slices; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template< typename Layout_ = layout::TensorNHWC > +struct Conv2dFpropFilterIteratorOptimizedParams; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template<> +struct Conv2dFpropFilterIteratorOptimizedParams +{ + + using Layout = layout::TensorNHWC; + + Layout layout; + int RS; + int filter_c_delta; + + int64_t inc_next_k; // offset in units of bytes to next K position + int64_t inc_next_rs; // offset in units of bytes to next RS position + int64_t inc_next_c; // offset in units of bytes to next C position + + // + // Methods + // + CUTLASS_HOST_DEVICE + Conv2dFpropFilterIteratorOptimizedParams() { } + + CUTLASS_HOST_DEVICE + Conv2dFpropFilterIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout, + int element_size_bits, ///< size of each element in bits + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta + ): + layout(layout) { + + TRACE_CONV_INITIALIZERS("conv2d_fprop", "filter", + element_size_bits, threadblock_shape, thread_count, access_size, threadmap_iterations, threadmap_delta); + + RS = problem_size.R * problem_size.S; + + inc_next_k = (int64_t(layout.stride()[2]) * threadmap_delta.strided() * element_size_bits) / 8; + + inc_next_rs = + ( int64_t(layout.stride()[0]) + - int64_t(layout.stride()[2]) * (threadmap_iterations.strided() - 1) * threadmap_delta.strided() + ) * element_size_bits / 8; + + inc_next_c = + ( + threadblock_shape.row() * problem_size.split_k_slices + - int64_t(RS - 1) * layout.stride()[0] + - int64_t(threadmap_iterations.strided() - 1) * threadmap_delta.strided() * layout.stride()[2] + ) * element_size_bits / 8; + + filter_c_delta = threadblock_shape.row() * problem_size.split_k_slices; + } +}; + +template +struct Conv2dFpropFilterIteratorOptimizedParams> +{ + static int const kInterleaved = Interleaved_; + using Layout = layout::TensorCxRSKx; + + Layout layout; + int RS; + int filter_c_delta; + + int64_t inc_next_k; // offset in units of bytes to next K position + int64_t inc_next_rs; // offset in units of bytes to next RS position + int64_t inc_next_c; // offset in units of bytes to next C position + + // + // Methods + // + CUTLASS_HOST_DEVICE + Conv2dFpropFilterIteratorOptimizedParams() { } + + CUTLASS_HOST_DEVICE + Conv2dFpropFilterIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout, + int element_size_bits, ///< size of each element in bits + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta + ): + layout(layout) { + + TRACE_CONV_INITIALIZERS("conv2d_fprop", "filter", + element_size_bits, threadblock_shape, thread_count, access_size, threadmap_iterations, threadmap_delta); + + RS = problem_size.R * problem_size.S; + + inc_next_k = (kInterleaved * threadmap_delta.strided() * element_size_bits) / 8; + + inc_next_rs = + ( int64_t(layout.stride()[0]) + - kInterleaved * (threadmap_iterations.strided() - 1) * threadmap_delta.strided() + ) * element_size_bits / 8; + + inc_next_c = + ( + threadblock_shape.row() * problem_size.split_k_slices / kInterleaved * int64_t(layout.stride()[2]) + - int64_t(RS - 1) * layout.stride()[0] + - int64_t(threadmap_iterations.strided() - 1) * threadmap_delta.strided() * kInterleaved + ) * element_size_bits / 8; + + filter_c_delta = threadblock_shape.row() * problem_size.split_k_slices; + } +}; + +/// Parameters object for Conv2d DGRAD OutputGradient (dy) iterator +struct Conv2dDgradOutputGradientIteratorOptimizedParams { + + using Layout = layout::TensorNHWC; + + Layout layout; + + int64_t inc_next[3]; // {next S, next R, next K} + + int filter_k_delta; // number of logical elements to add to filter_k_ + + int HW; // product of H*W + + FastDivmod hw_divmod; + FastDivmod w_divmod; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Conv2dDgradOutputGradientIteratorOptimizedParams() { } + + CUTLASS_HOST_DEVICE + Conv2dDgradOutputGradientIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout, + int element_size_bits, ///< size of each element in bits + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta + ): + layout(layout), HW(problem_size.H *problem_size.W), hw_divmod(HW), w_divmod(problem_size.W) { + + TRACE_CONV_INITIALIZERS("conv2d_dgrad", "output_gradient", + element_size_bits, threadblock_shape, thread_count, access_size, threadmap_iterations, threadmap_delta); + + int conv_sign = (problem_size.mode == Mode::kConvolution ? 1 : -1); + + // next S + inc_next[0] = conv_sign * (layout.stride()[0] * problem_size.dilation_w) * element_size_bits / 8; + + // next R + inc_next[1] = conv_sign * ( + layout.stride()[1] * problem_size.dilation_h + - (problem_size.S - 1) * layout.stride()[0] * problem_size.dilation_w + ) * element_size_bits / 8; + + // next K + inc_next[2] = ( + threadblock_shape.column() * problem_size.split_k_slices + - conv_sign * (problem_size.R - 1) * layout.stride()[1] * problem_size.dilation_h + - conv_sign * (problem_size.S - 1) * layout.stride()[0] * problem_size.dilation_w + ) * element_size_bits / 8; + + // logical offset added to internal channel counter - units are elements, not bytes + filter_k_delta = threadblock_shape.column() * problem_size.split_k_slices; + } +}; + +/// Parameters object for Conv2d DGRAD Filter (w) iterator +struct Conv2dDgradFilterIteratorOptimizedParams { + + using Layout = layout::TensorNHWC; + + Layout layout; + int RS; + int filter_k_delta; + + int64_t inc_next_strided; // offset in units of bytes to next K coordinate within tile + int64_t inc_next_rs; // offset in units of bytes to next RS position + int64_t inc_next_k; // offset in units of bytes to next K position in subsequent tile + + // + // Methods + // + CUTLASS_HOST_DEVICE + Conv2dDgradFilterIteratorOptimizedParams() { } + + CUTLASS_HOST_DEVICE + Conv2dDgradFilterIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout, + int element_size_bits, ///< size of each element in bits + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta + ): + layout(layout), RS(problem_size.R * problem_size.S) { + + TRACE_CONV_INITIALIZERS("conv2d_dgrad", "filter", + element_size_bits, threadblock_shape, thread_count, access_size, threadmap_iterations, threadmap_delta); + + inc_next_strided = (layout.stride()[2] * threadmap_delta.strided() * element_size_bits) / 8; + + inc_next_rs = + ( layout.stride()[0] + - (threadmap_iterations.strided() - 1) * threadmap_delta.strided() * layout.stride()[2] + ) * element_size_bits / 8; + + inc_next_k = + ( + threadblock_shape.row() * problem_size.split_k_slices * layout.stride()[2] + - (problem_size.R * problem_size.S - 1) * layout.stride()[0] + - (threadmap_iterations.strided() - 1) * threadmap_delta.strided() * layout.stride()[2] + ) * element_size_bits / 8; + + filter_k_delta = threadblock_shape.row() * problem_size.split_k_slices; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Parameters object for Conv2d WGRAD Output Gradient (dy) iterator +struct Conv2dWgradOutputGradientIteratorOptimizedParams { + + using Layout = layout::TensorNHWC; + + Layout layout; + + int NPQ; // precomputd product of N*P*Q for clearing predicates + + FastDivmod pq_divmod; + FastDivmod q_divmod; + + int64_t offset_next_strided; // offset in units of bytes to next npq coordinate within tile + int64_t offset_next_contiguous; // offset in units of bytes to next k coordinate within tile + int64_t inc_next_npq; // offset in units of bytes to next npq position in subsequent tile + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Conv2dWgradOutputGradientIteratorOptimizedParams() { } + + CUTLASS_HOST_DEVICE + Conv2dWgradOutputGradientIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout, + int element_size_bits, ///< size of each element in bits + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta + ): + layout(layout), + NPQ(problem_size.N * problem_size.P * problem_size.Q), + pq_divmod(problem_size.P * problem_size.Q), + q_divmod(problem_size.Q) { + + TRACE_CONV_INITIALIZERS("conv2d_wgrad", "output_gradient", + element_size_bits, threadblock_shape, thread_count, access_size, threadmap_iterations, threadmap_delta); + + // Incremental offsets in unites of bytes (number of elements) * sizeof_bits::value / 8 + offset_next_strided = (threadmap_delta.strided() * layout.stride()[0]) + * element_size_bits / 8; + + offset_next_contiguous = (threadmap_delta.contiguous()) + * element_size_bits / 8; + + inc_next_npq = (threadblock_shape.column() * problem_size.split_k_slices * layout.stride()[0]) + * element_size_bits / 8; + } +}; + +struct Conv2dWgradActivationIteratorOptimizedParams { + + using Layout = layout::TensorNHWC; + + Layout layout; + + FastDivmod sc_divmod; + FastDivmod pq_divmod; + FastDivmod q_divmod; + FastDivmod c_divmod; + + // + // Methods + // + CUTLASS_HOST_DEVICE + Conv2dWgradActivationIteratorOptimizedParams() { } + + CUTLASS_HOST_DEVICE + Conv2dWgradActivationIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout + ): + layout(layout), + sc_divmod(problem_size.S * problem_size.C), + pq_divmod(problem_size.P * problem_size.Q), + q_divmod(problem_size.Q), + c_divmod(problem_size.C) { + + } + + CUTLASS_HOST_DEVICE + Conv2dWgradActivationIteratorOptimizedParams( + Conv2dProblemSize const &problem_size, + Layout const &layout, + int element_size_bits, ///< size of each element in bits + MatrixCoord threadblock_shape, + int thread_count, + int access_size, + layout::PitchLinearCoord threadmap_iterations, + layout::PitchLinearCoord threadmap_delta + ): + Conv2dWgradActivationIteratorOptimizedParams( + problem_size, + layout + ) { + + TRACE_CONV_INITIALIZERS("conv2d_wgrad", "activation", + element_size_bits, threadblock_shape, thread_count, access_size, threadmap_iterations, threadmap_delta); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/threadblock/conv2d_tile_iterator.h b/include/cutlass/conv/threadblock/conv2d_tile_iterator.h new file mode 100644 index 000000000..ce52017e3 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_tile_iterator.h @@ -0,0 +1,170 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Template wraps the tile access iterator concept to load whole tiles from tensors in + memory used for implicit GEMM convolution. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/matrix_shape.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template +class TileIterator { +public: + using TileAccessIterator = TileAccessIterator_; + + using Shape = typename TileAccessIterator::Shape; + using Element = typename TileAccessIterator::Element; + using Layout = typename TileAccessIterator::Layout; + using TensorCoord = typename Layout::TensorCoord; + using ThreadMap = typename TileAccessIterator::ThreadMap; + using AccessType = typename TileAccessIterator::AccessType; + using TensorRef = typename TileAccessIterator::TensorRef; + using Index = typename TileAccessIterator::Index; + using LongIndex = typename TileAccessIterator::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = TileAccessIterator::kIteratorAlgorithm; + static StrideSupport const kStrideSupport = TileAccessIterator::kStrideSupport; + using Params = typename TileAccessIterator::Params; + static int const kConvDim = TileAccessIterator::kConvDim; + using ConvProblemSize = typename TileAccessIterator::ConvProblemSize; + + /// Fragment object to be loaded or stored + using Fragment = cutlass::Array< + Element, + ThreadMap::Iterations::kCount * ThreadMap::kElementsPerAccess>; + +private: + + /// Internal state + TileAccessIterator tile_access_iterator_; + +public: + + /// Constructor + CUTLASS_HOST_DEVICE + TileIterator( + Params const ¶ms, + ConvProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + tile_access_iterator_(params, problem_size, ptr, thread_idx, threadblock_offset) { } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + tile_access_iterator_.add_pointer_offset(pointer_offset); + } + + /// Advances to the next tile in memory. + CUTLASS_HOST_DEVICE + TileIterator &operator++() { + tile_access_iterator_.advance(); + return *this; + } + + /// Advances to the next tile in memory. + CUTLASS_HOST_DEVICE + TileIterator operator++(int) { + TileIterator self(*this); + operator++(); + return self; + } + + /// Loads a fragment from memory + CUTLASS_DEVICE + void load_with_pointer_offset(Fragment &frag, Index pointer_offset) { + + frag.clear(); + AccessType *frag_ptr = reinterpret_cast(&frag); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + CUTLASS_PRAGMA_UNROLL + for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + + cutlass::arch::global_load< + AccessType, + sizeof(AccessType) + >( + frag_ptr[c + s * ThreadMap::Iterations::kContiguous], + tile_access_iterator_.get() + pointer_offset, + tile_access_iterator_.valid() + ); + + ++tile_access_iterator_; + } + } + } + + /// Loads a fragment from memory + CUTLASS_DEVICE + void load(Fragment &frag) { + tile_access_iterator_.set_iteration_index(0); + load_with_pointer_offset(frag, 0); + } + + CUTLASS_DEVICE + void advance() { + tile_access_iterator_.advance(); + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(ConvProblemSize const &problem_size) { + + // dispatch to iterator implementation + return TileAccessIterator::can_implement(problem_size); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/include/cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_analytic.h new file mode 100644 index 000000000..13d8338c2 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_analytic.h @@ -0,0 +1,254 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (activation tile) + matrix from memory. + + This iterator assumes TensorNHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv2dWgradActivationTileAccessIteratorAnalytic { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "WGRAD requires elements of size 8b or greater."); + + // + // Parameters structure + // + + using Params = Conv2dAnalyticParams; + +private: + + Params const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + // Filter postion (r,s,c) in contiguous dimension stays constant for each gemm_iteration_k + int filter_r_[ThreadMap::Iterations::kContiguous]; + int filter_s_[ThreadMap::Iterations::kContiguous]; + int filter_c_[ThreadMap::Iterations::kContiguous]; + + int offset_npq_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dWgradActivationTileAccessIteratorAnalytic( + Params const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)) + { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + // initialize r,s,c filter position for every contiguous iteration + CUTLASS_PRAGMA_UNROLL + for(int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + + int rsc_offset = threadblock_offset.column() + thread_coord.contiguous() + + c * ThreadMap::Delta::kContiguous; + + filter_r_[c] = rsc_offset / (problem_size_.S * problem_size_.C); + int residual = rsc_offset % (problem_size_.S * problem_size_.C); + + filter_s_[c] = residual / problem_size_.C; + filter_c_[c] = residual % problem_size_.C; + } + + // initialize n, p, q offset for every strided iteration + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + + offset_npq_[s] = threadblock_offset.row() + thread_coord.strided() + + s * ThreadMap::Delta::kStrided; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + + // moves to the next GEMM-K offset (offset_npq_) in GEMM-B by a CTA-K tile + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_npq_[s] += Shape::kRow * problem_size_.split_k_slices; + } + } + + /// Returns the coordinate in the activation tensor x that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int r = filter_r_[iteration_contiguous_]; + int s = filter_s_[iteration_contiguous_]; + + if (problem_size_.mode == Mode::kConvolution) { + r = (problem_size_.R - 1 - r); + s = (problem_size_.S - 1 - s); + } + + int n = offset_npq_[iteration_strided_] / (problem_size_.P * problem_size_.Q); + int residual = offset_npq_[iteration_strided_] % (problem_size_.P * problem_size_.Q); + + int p = residual / problem_size_.Q; + int q = residual % problem_size_.Q; + + int h = p * problem_size_.stride_h - problem_size_.pad_h + r * problem_size_.dilation_h; + int w = q * problem_size_.stride_w - problem_size_.pad_w + s * problem_size_.dilation_w; + + return TensorCoord(n, h, w, filter_c_[iteration_contiguous_]); + } + + /// Returns true if the current coordinate is within the activation tensor x + CUTLASS_HOST_DEVICE + bool valid() const { + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.h() >= 0 && coord.h() < problem_size_.H && + coord.w() >= 0 && coord.w() < problem_size_.W && + coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dWgradActivationTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_optimized.h b/include/cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_optimized.h new file mode 100644 index 000000000..74a887794 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_wgrad_activation_tile_access_iterator_optimized.h @@ -0,0 +1,273 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (activation tile) + matrix from memory. + + This iterator assumes TensorNHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv2dWgradActivationTileAccessIteratorOptimized { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "WGRAD requires elements of size 8b or greater."); + + // + // Parameters structure + // + + using Params = Conv2dWgradActivationIteratorOptimizedParams; + +private: + + Conv2dWgradActivationIteratorOptimizedParams const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + // Precomputed effective filter postion (r,s) in contiguous dimension stays constant for each gemm_iteration_k + // required for npq -> nhw translation + int precomputed_filter_r_[ThreadMap::Iterations::kContiguous]; + int precomputed_filter_s_[ThreadMap::Iterations::kContiguous]; + + // Channel dimension in contiguous dimension stays constant for each gemm_iteration_k + int filter_c_[ThreadMap::Iterations::kContiguous]; + + int offset_npq_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dWgradActivationTileAccessIteratorOptimized( + Conv2dWgradActivationIteratorOptimizedParams const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)) + { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + // initialize r,s,c filter position for every contiguous iteration + CUTLASS_PRAGMA_UNROLL + for(int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + + int rsc_offset = threadblock_offset.column() + thread_coord.contiguous() + + c * ThreadMap::Delta::kContiguous; + + // The subseqnet fast_divmod() operations are equivalent to the following logical computation: + // + // + // filter_r_[c] = rsc_offset / (problem_size_.S * problem_size_.C); + // int residual = rsc_offset % (problem_size_.S * problem_size_.C); + // + // filter_s_[c] = residual / problem_size_.C; + // filter_c_[c] = residual % problem_size_.C; + + int residual; + params_.sc_divmod(precomputed_filter_r_[c], residual, rsc_offset); + params_.c_divmod(precomputed_filter_s_[c], filter_c_[c], residual); + + int r = precomputed_filter_r_[c]; + int s = precomputed_filter_s_[c]; + + if (problem_size_.mode == Mode::kConvolution) { + r = (problem_size_.R - 1 - r); + s = (problem_size_.S - 1 - s); + } + + precomputed_filter_r_[c] = - problem_size_.pad_h + r * problem_size_.dilation_h; + precomputed_filter_s_[c] = - problem_size_.pad_w + s * problem_size_.dilation_w; + + } + + // initialize n, p, q offset for every strided iteration + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + + offset_npq_[s] = threadblock_offset.row() + thread_coord.strided() + + s * ThreadMap::Delta::kStrided; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + + // moves to the next GEMM-K offset (offset_npq_) in GEMM-B by a CTA-K tile + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_npq_[s] += Shape::kRow * problem_size_.split_k_slices; + } + } + + /// Returns the coordinate in the activation tensor x that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + // The subseqnet fast_divmod() operations are equivalent to the following logical computation: + // + // + // int n = offset_npq_[iteration_strided_] / (problem_size_.P * problem_size_.Q); + // int residual = offset_npq_[iteration_strided_] % (problem_size_.P * problem_size_.Q); + // + // int p = residual / problem_size_.Q; + // int q = residual % problem_size_.Q; + + int residual, n, p, q; + + params_.pq_divmod(n, residual, offset_npq_[iteration_strided_]); + params_.q_divmod(p, q, residual); + + int h = p * problem_size_.stride_h + precomputed_filter_r_[iteration_contiguous_]; + int w = q * problem_size_.stride_w + precomputed_filter_s_[iteration_contiguous_]; + + return TensorCoord(n, h, w, filter_c_[iteration_contiguous_]); + } + + /// Returns true if the current coordinate is within the activation tensor x + CUTLASS_HOST_DEVICE + bool valid() const { + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.h() >= 0 && coord.h() < problem_size_.H && + coord.w() >= 0 && coord.w() < problem_size_.W && + coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dWgradActivationTileAccessIteratorOptimized &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_analytic.h new file mode 100644 index 000000000..84c788d6d --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_analytic.h @@ -0,0 +1,234 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (output gradient tile) + matrix from memory. + + This iterator assumes TensorNHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" +#include "cutlass/conv/threadblock/conv2d_params.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv2dWgradOutputGradientTileAccessIteratorAnalytic { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "WGRAD requires elements of size 8b or greater."); + + // + // Parameters structure + // + + using Params = Conv2dAnalyticParams; + +private: + + Params const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_k_[ThreadMap::Iterations::kContiguous]; + + int offset_npq_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv2dWgradOutputGradientTileAccessIteratorAnalytic( + Params const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + // initialize filter_k for every contiguous iteration + CUTLASS_PRAGMA_UNROLL + for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + filter_k_[c] = threadblock_offset.row() + thread_coord.contiguous() + + c * ThreadMap::Delta::kContiguous; + } + + // initialize n, p, q offset for every strided iteration + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_npq_[s] = threadblock_offset.column() + thread_coord.strided() + + s * ThreadMap::Delta::kStrided; + + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next GEMM-K offset (offset_npq_) in GEMM-A by a CTA-K tile + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_npq_[s] += Shape::kColumn * problem_size_.split_k_slices; + } + } + + /// Returns the coordinate in the output gradient tensor Dy that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int npq = offset_npq_[iteration_strided_]; + + int n = npq / (problem_size_.P * problem_size_.Q); + int residual = npq % (problem_size_.P * problem_size_.Q); + + int p = residual / problem_size_.Q; + int q = residual % problem_size_.Q; + + return TensorCoord(n, p, q, filter_k_[iteration_contiguous_]); + } + + + /// Returns true if the current coordinate is within the output gradient tensor Dy + CUTLASS_HOST_DEVICE + bool valid() const { + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.h() < problem_size_.P && + coord.w() < problem_size_.Q && + coord.c() < problem_size_.K; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dWgradOutputGradientTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_optimized.h b/include/cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_optimized.h new file mode 100644 index 000000000..4a20cb1d8 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv2d_wgrad_output_gradient_tile_access_iterator_optimized.h @@ -0,0 +1,300 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (output gradient tile) + matrix from memory. + + This iterator assumes TensorNHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv2dWgradOutputGradientTileAccessIteratorOptimized { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kOptimized; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 2; + using ConvProblemSize = typename conv::Conv2dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "WGRAD requires elements of size 8b or greater."); + + // + // Parameters structure + // + + struct Params : Conv2dWgradOutputGradientIteratorOptimizedParams { + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params(Conv2dWgradOutputGradientIteratorOptimizedParams const &base): + Conv2dWgradOutputGradientIteratorOptimizedParams(base) { } + + CUTLASS_HOST_DEVICE + Params( + Conv2dProblemSize const &problem_size, + Layout const &layout + ): + Conv2dWgradOutputGradientIteratorOptimizedParams( + problem_size, + layout, + sizeof_bits::value, + {Shape::kRow, Shape::kColumn}, + ThreadMap::kThreads, + ThreadMap::kElementsPerAccess, + {ThreadMap::Iterations::kContiguous, ThreadMap::Iterations::kStrided}, + {ThreadMap::Delta::kContiguous, ThreadMap::Delta::kStrided} + ) { } + }; + +private: + + Conv2dWgradOutputGradientIteratorOptimizedParams const ¶ms_; + Conv2dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + uint32_t predicates_; + int filter_k_; + int offset_npq_; + +public: + + CUTLASS_HOST_DEVICE + Conv2dWgradOutputGradientTileAccessIteratorOptimized( + Conv2dWgradOutputGradientIteratorOptimizedParams const ¶ms, + Conv2dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + predicates_(0), + filter_k_(0), + offset_npq_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_k_ = threadblock_offset.row() + thread_coord.contiguous(); + offset_npq_ = threadblock_offset.column() + thread_coord.strided(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + CUTLASS_PRAGMA_UNROLL + for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + + int filter_k = filter_k_ + c * ThreadMap::Delta::kContiguous; + int offset_npq = offset_npq_ + s * ThreadMap::Delta::kStrided; + + bool predicate = valid_(at_(offset_npq, filter_k)); + + uint32_t pred = (predicate ? 1u : 0); + + int pred_idx = c + s * ThreadMap::Iterations::kContiguous; + + predicates_ |= (pred << pred_idx); + } + } + + // Offset pointer to (iteration_strided_, iteration_contiguous_) = (0, 0) + pointer_ += ( + offset_npq_ * params.layout.stride()[0] + filter_k_ + ) * sizeof_bits::value / 8; + + set_iteration_index(0); + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next GEMM-K offset (offset_npq_) in GEMM-A by a CTA-K tile + offset_npq_ += Shape::kColumn * problem_size_.split_k_slices; + + // Clear predicates if needed + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + if (offset_npq_ + s * ThreadMap::Delta::kStrided >= params_.NPQ) { + uint32_t kClearMask = ((1u << ThreadMap::Iterations::kContiguous) - 1) << (s * ThreadMap::Iterations::kContiguous); + predicates_ = (predicates_ & (~kClearMask)); + } + } + + pointer_ += params_.inc_next_npq; + } + +private: + /// Returns the coordinate in the output gradient tensor Dy that is pointed to + /// by offset_npq and k. + CUTLASS_HOST_DEVICE + TensorCoord at_(int offset_npq, int k) const { + + // The subseqnet fast_divmod() operations are equivalent to the following logical computation: + // + // + // int npq = offset_npq; + // int n = npq / (problem_size_.P * problem_size_.Q); + // int residual = npq % (problem_size_.P * problem_size_.Q); + // + // int p = residual / problem_size_.Q; + // int q = residual % problem_size_.Q; + + int residual, n, p, q; + + params_.pq_divmod(n, residual, offset_npq); + params_.q_divmod(p, q, residual); + + return TensorCoord(n, p, q, k); + } + + /// Returns true if the coord is within the output gradient tensor Dy + CUTLASS_HOST_DEVICE + bool valid_(TensorCoord coord) const { + + return coord.n() < problem_size_.N && + coord.c() < problem_size_.K; + } + +public: + + /// Returns true if the current coordinate is within the output gradient tensor Dy + CUTLASS_HOST_DEVICE + bool valid() const { + + LongIndex pred_idx = iteration_contiguous_ + iteration_strided_ * ThreadMap::Iterations::kContiguous; + return (predicates_ & (1u << pred_idx)); + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + return reinterpret_cast( + pointer_ + + iteration_strided_ * params_.offset_next_strided + + iteration_contiguous_ * params_.offset_next_contiguous + ); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv2dWgradOutputGradientTileAccessIteratorOptimized &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv2dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv3d_dgrad_filter_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv3d_dgrad_filter_tile_access_iterator_analytic.h new file mode 100644 index 000000000..003356827 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv3d_dgrad_filter_tile_access_iterator_analytic.h @@ -0,0 +1,263 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (filter tile) + matrix from memory. + + This iterator assumes TensorNDHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv3dDgradFilterTileAccessIteratorAnalytic { +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNDHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 3; + using ConvProblemSize = typename conv::Conv3dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "DGRAD requires elements of size 8b or larger."); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + // + // Methods + // + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + Conv3dProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + } + }; + +private: + + Params const ¶ms_; + Conv3dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + // For a fixed filter position (t,r,s) find and fill offset_k_, offset_c_ in strided and contiguous dimension + int filter_t_; + int filter_r_; + int filter_s_; + int offset_k_[ThreadMap::Iterations::kStrided]; + int offset_c_[ThreadMap::Iterations::kContiguous]; + +public: + + CUTLASS_HOST_DEVICE + Conv3dDgradFilterTileAccessIteratorAnalytic( + Params const ¶ms, + Conv3dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_t_(0), + filter_r_(0), + filter_s_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + CUTLASS_PRAGMA_UNROLL + for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + offset_c_[c] = threadblock_offset.column() + thread_coord.contiguous() + + c * ThreadMap::Delta::kContiguous; + } + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_k_[s] = + threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + ++filter_t_; + if (filter_t_ < problem_size_.T) { + return; + } + filter_t_ = 0; + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_k_[s] += Shape::kRow * problem_size_.split_k_slices; + } + } + + /// Returns the coordinate in the filter tensor w that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int c = offset_c_[iteration_contiguous_]; + int k = offset_k_[iteration_strided_]; + + return TensorCoord(k, filter_t_, filter_r_, filter_s_, c); + } + + /// Returns true if the current coordinate is within the filter tensor w + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord coord = at(); + + return coord.n() < problem_size_.K && coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv3dDgradFilterTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv3dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv3d_dgrad_output_gradient_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv3d_dgrad_output_gradient_tile_access_iterator_analytic.h new file mode 100644 index 000000000..47e7de46a --- /dev/null +++ b/include/cutlass/conv/threadblock/conv3d_dgrad_output_gradient_tile_access_iterator_analytic.h @@ -0,0 +1,331 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (output gradient tile) + matrix from memory. + + This iterator assumes TensorNDHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// +template < + typename Shape_, + typename Element_, + typename ThreadMap_, + conv::StrideSupport StrideSupport_ = conv::StrideSupport::kStrided +> +class Conv3dDgradOutputGradientTileAccessIteratorAnalytic; +///////////////////////////////////////////////////////////////////////////////////////////////// + +// Conv3dDgradOutputGradientTileAccessIteratorAnalytic strided dgrad needs special handling using +// unscaled coordinations +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv3dDgradOutputGradientTileAccessIteratorAnalytic < + Shape_, + Element_, + ThreadMap_, + conv::StrideSupport::kStrided +> { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNDHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 3; + using ConvProblemSize = typename conv::Conv3dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "DGRAD requires elements of size 8b or greater."); + + // + // Simpligying assertions + // + + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + // + // Methods + // + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + ConvProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + } + }; + +private: + + Params const ¶ms_; + ConvProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_k_; + int filter_t_; + int filter_r_; + int filter_s_; + + int offset_n_[ThreadMap::Iterations::kStrided]; + int offset_d_[ThreadMap::Iterations::kStrided]; + int offset_w_[ThreadMap::Iterations::kStrided]; + int offset_h_[ThreadMap::Iterations::kStrided]; + +private: + + /// Returns the coordinate in the output tensor Dy that is currently pointed to + /// by the iterator but DOES NOT scale by the convolution stride. This is needed + /// to compute predicates in the valid() method. The return value of the public at() + /// method is correctly scaled. + CUTLASS_HOST_DEVICE + TensorCoord unscaled_at_() const { + int n = offset_n_[iteration_strided_]; + int d = offset_d_[iteration_strided_]; + int h = offset_h_[iteration_strided_]; + int w = offset_w_[iteration_strided_]; + + int t = filter_t_; + int r = filter_r_; + int s = filter_s_; + + if (problem_size_.mode == Mode::kConvolution) { + t = (problem_size_.T - 1 - t); + r = (problem_size_.R - 1 - r); + s = (problem_size_.S - 1 - s); + } + + int z = (d + problem_size_.pad_d - t * problem_size_.dilation_d); + int p = (h + problem_size_.pad_h - r * problem_size_.dilation_h); + int q = (w + problem_size_.pad_w - s * problem_size_.dilation_w); + + return TensorCoord(n, z, p, q, filter_k_); + } + +public: + + CUTLASS_HOST_DEVICE + Conv3dDgradOutputGradientTileAccessIteratorAnalytic( + Params const ¶ms, + ConvProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() // threadblock offset - units are whole CTA tiles + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_k_(0), + filter_t_(0), + filter_r_(0), + filter_s_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_k_ = threadblock_offset.column() + thread_coord.contiguous(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + int offset_ndhw = threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + + offset_n_[s] = offset_ndhw / (problem_size_.D * problem_size_.H * problem_size_.W); + int residual = offset_ndhw % (problem_size_.D * problem_size_.H * problem_size_.W); + + offset_d_[s] = residual / (problem_size_.H * problem_size_.W); + residual = residual % (problem_size_.H * problem_size_.W); + + offset_h_[s] = residual / problem_size_.W; + offset_w_[s] = residual % problem_size_.W; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // move to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + ++filter_t_; + if (filter_t_ < problem_size_.T) { + return; + } + filter_t_ = 0; + + filter_k_ += Shape_::kColumn * problem_size_.split_k_slices; + } + + /// Returns the coordinate in the output tensor Dy that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + TensorCoord coord = unscaled_at_(); + + return TensorCoord( + coord.n(), + coord.d() / problem_size_.stride_d, + coord.h() / problem_size_.stride_h, + coord.w() / problem_size_.stride_w, + coord.c()); + } + + + /// Returns true if the current coordinate is within the output tensor Dy + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord unscaled_coord = unscaled_at_(); + TensorCoord coord = at(); + + return + !(unscaled_coord.d() % problem_size_.stride_d) && + !(unscaled_coord.h() % problem_size_.stride_h) && + !(unscaled_coord.w() % problem_size_.stride_w) && + coord.n() < problem_size_.N && + coord.d() >= 0 && coord.d() < problem_size_.Z && + coord.h() >= 0 && coord.h() < problem_size_.P && + coord.w() >= 0 && coord.w() < problem_size_.Q && + coord.c() < problem_size_.K; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv3dDgradOutputGradientTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(ConvProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv3d_fprop_activation_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv3d_fprop_activation_tile_access_iterator_analytic.h new file mode 100644 index 000000000..f5d14b5b1 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv3d_fprop_activation_tile_access_iterator_analytic.h @@ -0,0 +1,296 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (activation tile) + matrix from memory. + + This iterator assumes TensorNDHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/matrix_shape.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv3dFpropActivationTileAccessIteratorAnalytic { +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNDHWC; + using TensorCoord = typename Layout::TensorCoord; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 3; + using ConvProblemSize = typename conv::Conv3dProblemSize; + + // + // Simplifying assertions + // + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + ConvProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + } + }; + +private: + + Params const ¶ms_; + ConvProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_t_; + int filter_r_; + int filter_s_; + int filter_c_; + + int offset_n_[ThreadMap::Iterations::kStrided]; + int offset_z_[ThreadMap::Iterations::kStrided]; + int offset_p_[ThreadMap::Iterations::kStrided]; + int offset_q_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv3dFpropActivationTileAccessIteratorAnalytic( + Params const ¶ms, + ConvProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() // tile index - units are threadblock-scoped tiles + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_t_(0), + filter_r_(0), + filter_s_(0), + filter_c_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_c_ = threadblock_offset.column() + thread_coord.contiguous(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + int offset_nzpq = threadblock_offset.row() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + + offset_n_[s] = offset_nzpq / (problem_size_.Z * problem_size_.P * problem_size_.Q); + int residual = offset_nzpq % (problem_size_.Z * problem_size_.P * problem_size_.Q); + + offset_z_[s] = residual / (problem_size_.P * problem_size_.Q); + residual = residual % (problem_size_.P * problem_size_.Q); + + offset_p_[s] = residual / problem_size_.Q; + offset_q_[s] = residual % problem_size_.Q; + } + + set_iteration_index(0); + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + ++filter_t_; + if (filter_t_ < problem_size_.T) { + return; + } + filter_t_ = 0; + + filter_c_ += Shape::kColumn * problem_size_.split_k_slices; + } + + /// Returns the coordinate in the activations tensor X that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + int n = offset_n_[iteration_strided_]; + int z = offset_z_[iteration_strided_]; + int p = offset_p_[iteration_strided_]; + int q = offset_q_[iteration_strided_]; + + int t = filter_t_; + int r = filter_r_; + int s = filter_s_; + + if (problem_size_.mode == Mode::kConvolution) { + t = (problem_size_.T - 1 - filter_t_); + r = (problem_size_.R - 1 - filter_r_); + s = (problem_size_.S - 1 - filter_s_); + } + + int d = z * problem_size_.stride_d - problem_size_.pad_d + t * problem_size_.dilation_d; + int h = p * problem_size_.stride_h - problem_size_.pad_h + r * problem_size_.dilation_h; + int w = q * problem_size_.stride_w - problem_size_.pad_w + s * problem_size_.dilation_w; + + return TensorCoord(n, d, h, w, filter_c_); + } + + /// Returns true if the current coordinate is within the activations tensor X + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.d() >= 0 && coord.d() < problem_size_.D && + coord.h() >= 0 && coord.h() < problem_size_.H && + coord.w() >= 0 && coord.w() < problem_size_.W && + coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + AccessType const *ptr = reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + + return ptr; + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv3dFpropActivationTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(ConvProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv3d_fprop_filter_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv3d_fprop_filter_tile_access_iterator_analytic.h new file mode 100644 index 000000000..bad6598ba --- /dev/null +++ b/include/cutlass/conv/threadblock/conv3d_fprop_filter_tile_access_iterator_analytic.h @@ -0,0 +1,262 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (filter tile) + matrix from memory. + + This iterator assumes TensorNDHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv3dFpropFilterTileAccessIteratorAnalytic { +public: + + // + // Types + // + + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNDHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 3; + using ConvProblemSize = typename conv::Conv3dProblemSize; + + // + // Simplifying assertions + // + static_assert(ThreadMap::Iterations::kContiguous == 1, + "Require Iterations::kContiguous == 1"); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + // + // Methods + // + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + ConvProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + } + }; + +private: + + Params const ¶ms_; + ConvProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_t_; + int filter_r_; + int filter_s_; + int filter_c_; + + int offset_k_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv3dFpropFilterTileAccessIteratorAnalytic( + Params const ¶ms, + ConvProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + filter_t_(0), + filter_r_(0), + filter_s_(0), + filter_c_(0) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_c_ = threadblock_offset.row() + thread_coord.contiguous(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_k_[s] = threadblock_offset.column() + thread_coord.strided() + s * ThreadMap::Delta::kStrided; + } + + set_iteration_index(0); + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * 8 / sizeof_bits::value; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + + ++filter_t_; + if (filter_t_ < problem_size_.T) { + return; + } + filter_t_ = 0; + + filter_c_ += Shape::kRow * problem_size_.split_k_slices; + } + + /// Returns the coordinate in the filter tensor W that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int k = offset_k_[iteration_strided_]; + + return TensorCoord(k, filter_t_, filter_r_, filter_s_, filter_c_); + } + + /// Returns true if the current coordinate is within the activations tensor W + CUTLASS_HOST_DEVICE + bool valid() const { + + TensorCoord coord = at(); + + return coord.n() < problem_size_.K && + coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv3dFpropFilterTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(ConvProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + return Status::kSuccess; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_analytic.h new file mode 100644 index 000000000..0ad49abd3 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_analytic.h @@ -0,0 +1,281 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (activation tile) + matrix from memory. + + This iterator assumes TensorNDHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv3dWgradActivationTileAccessIteratorAnalytic { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNDHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 3; + using ConvProblemSize = typename conv::Conv3dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "WGRAD requires elements of size 8b or greater."); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + // + // Methods + // + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + Conv3dProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + } + }; + +private: + + Params const ¶ms_; + Conv3dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + // Filter postion (t,r,s,c) in contiguous dimension stays constant for each gemm_iteration_k + int filter_t_[ThreadMap::Iterations::kContiguous]; + int filter_r_[ThreadMap::Iterations::kContiguous]; + int filter_s_[ThreadMap::Iterations::kContiguous]; + int filter_c_[ThreadMap::Iterations::kContiguous]; + + int offset_nzpq_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv3dWgradActivationTileAccessIteratorAnalytic( + Params const ¶ms, + Conv3dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + // initialize t,r,s,c filter position for every contiguous iteration + CUTLASS_PRAGMA_UNROLL + for(int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + + int trsc_offset = threadblock_offset.column() + thread_coord.contiguous() + + c * ThreadMap::Delta::kContiguous; + + filter_t_[c] = trsc_offset / (problem_size_.R * problem_size_.S * problem_size_.C); + int residual = trsc_offset % (problem_size_.R * problem_size_.S * problem_size_.C); + + filter_r_[c] = residual / (problem_size_.S * problem_size_.C); + residual = residual % (problem_size_.S * problem_size_.C); + + filter_s_[c] = residual / problem_size_.C; + filter_c_[c] = residual % problem_size_.C; + + } + + // initialize n, z, p, q offset for every strided iteration + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + + offset_nzpq_[s] = threadblock_offset.row() + thread_coord.strided() + + s * ThreadMap::Delta::kStrided; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + + // moves to the next GEMM-K offset (offset_nzpq_) in GEMM-B by a CTA-K tile + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_nzpq_[s] += Shape::kRow * problem_size_.split_k_slices; + } + } + + /// Returns the coordinate in the activation tensor x that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int t = filter_t_[iteration_contiguous_]; + int r = filter_r_[iteration_contiguous_]; + int s = filter_s_[iteration_contiguous_]; + + if (problem_size_.mode == Mode::kConvolution) { + t = (problem_size_.T - 1 - t); + r = (problem_size_.R - 1 - r); + s = (problem_size_.S - 1 - s); + } + + int n = offset_nzpq_[iteration_strided_] / (problem_size_.Z * problem_size_.P * problem_size_.Q); + int residual = offset_nzpq_[iteration_strided_] % (problem_size_.Z * problem_size_.P * problem_size_.Q); + + int z = residual / (problem_size_.P * problem_size_.Q); + residual = residual % (problem_size_.P * problem_size_.Q); + + int p = residual / problem_size_.Q; + int q = residual % problem_size_.Q; + + int d = z * problem_size_.stride_d - problem_size_.pad_d + t * problem_size_.dilation_d; + int h = p * problem_size_.stride_h - problem_size_.pad_h + r * problem_size_.dilation_h; + int w = q * problem_size_.stride_w - problem_size_.pad_w + s * problem_size_.dilation_w; + + return TensorCoord(n, d, h, w, filter_c_[iteration_contiguous_]); + } + + /// Returns true if the current coordinate is within the activation tensor x + CUTLASS_HOST_DEVICE + bool valid() const { + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.d() >= 0 && coord.d() < problem_size_.D && + coord.h() >= 0 && coord.h() < problem_size_.H && + coord.w() >= 0 && coord.w() < problem_size_.W && + coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv3dWgradActivationTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv3dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_optimized.h b/include/cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_optimized.h new file mode 100644 index 000000000..35c464305 --- /dev/null +++ b/include/cutlass/conv/threadblock/conv3d_wgrad_activation_tile_access_iterator_optimized.h @@ -0,0 +1,346 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM B (activation tile) + matrix from memory. + + This iterator assumes TensorNDHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv3dWgradActivationTileAccessIteratorOptimized { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNDHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kOptimized; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 3; + using ConvProblemSize = typename conv::Conv3dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "WGRAD requires elements of size 8b or greater."); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + int RSC; // product of R*S*C + unsigned rsc_mul; // precomputed quantities for fast computation of div/% by RSC + unsigned rsc_shr; // in device code. + + int SC; // product of S*C + unsigned sc_mul; // precomputed quantities for fast computation of div/% by SC + unsigned sc_shr; // in device code. + + unsigned c_mul; // precomputed quantities for fast computation of div/% by C + unsigned c_shr; // in device code. + + int ZPQ; // product of Z*P*Q + unsigned zpq_mul; // precomputed quantities for fast computation of div/% by ZPQ + unsigned zpq_shr; // in device code. + + int PQ; // product of P*Q + unsigned pq_mul; // precomputed quantities for fast computation of div/% by PQ + unsigned pq_shr; // in device code. + + unsigned q_mul; // precomputed quantities for fast computation of div/% by Q + unsigned q_shr; // in device code. + + // + // Methods + // + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + Conv3dProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + // Precompute several quantities for fast modulo arithmetic. + RSC = problem_size.R * problem_size.S * problem_size.C; + find_divisor(rsc_mul, rsc_shr, RSC); + + SC = problem_size.S * problem_size.C; + find_divisor(sc_mul, sc_shr, SC); + + find_divisor(c_mul, c_shr, problem_size.C); + + ZPQ = problem_size.Z * problem_size.P * problem_size.Q; + find_divisor(zpq_mul, zpq_shr, ZPQ); + + PQ = problem_size.P * problem_size.Q; + find_divisor(pq_mul, pq_shr, PQ); + + find_divisor(q_mul, q_shr, problem_size.Q); + + } + }; + +private: + + Params const ¶ms_; + Conv3dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + // Precomputed effective filter postion (t,r,s) in contiguous dimension stays constant for each gemm_iteration_k + // required for nzpq -> ndhw translation + int precomputed_filter_t_[ThreadMap::Iterations::kContiguous]; + int precomputed_filter_r_[ThreadMap::Iterations::kContiguous]; + int precomputed_filter_s_[ThreadMap::Iterations::kContiguous]; + + // Channel dimension in contiguous dimension stays constant for each gemm_iteration_k + int filter_c_[ThreadMap::Iterations::kContiguous]; + + int offset_nzpq_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv3dWgradActivationTileAccessIteratorOptimized( + Params const ¶ms, + Conv3dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)) { + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + // initialize t,r,s,c filter position for every contiguous iteration + CUTLASS_PRAGMA_UNROLL + for(int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + + int trsc_offset = threadblock_offset.column() + thread_coord.contiguous() + + c * ThreadMap::Delta::kContiguous; + + // The subseqnet fast_divmod() operations are equivalent to the following logical computation: + // + // + // filter_t_[c] = trsc_offset / (problem_size_.R * problem_size_.S * problem_size_.C); + // int residual = trsc_offset % (problem_size_.R * problem_size_.S * problem_size_.C); + // + // filter_r_[c] = residual / (problem_size_.S * problem_size_.C); + // residual = residual % (problem_size_.S * problem_size_.C); + // + // filter_s_[c] = residual / problem_size_.C; + // filter_c_[c] = residual % problem_size_.C; + + int residual; + fast_divmod(precomputed_filter_t_[c], residual, trsc_offset, params_.RSC, params_.rsc_mul, params_.rsc_shr); + fast_divmod(precomputed_filter_r_[c], residual, residual, params_.SC, params_.sc_mul, params_.sc_shr); + fast_divmod(precomputed_filter_s_[c], filter_c_[c], residual, problem_size_.C, params_.c_mul, params_.c_shr); + + int t = precomputed_filter_t_[c]; + int r = precomputed_filter_r_[c]; + int s = precomputed_filter_s_[c]; + + if (problem_size_.mode == Mode::kConvolution) { + t = (problem_size_.T - 1 - t); + r = (problem_size_.R - 1 - r); + s = (problem_size_.S - 1 - s); + } + + // efective t,r,s for every contiguous dimension + precomputed_filter_t_[c] = - problem_size_.pad_d + t * problem_size_.dilation_d; + precomputed_filter_r_[c] = - problem_size_.pad_h + r * problem_size_.dilation_h; + precomputed_filter_s_[c] = - problem_size_.pad_w + s * problem_size_.dilation_w; + + + } + + // initialize n, z, p, q offset for every strided iteration + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + + offset_nzpq_[s] = threadblock_offset.row() + thread_coord.strided() + + s * ThreadMap::Delta::kStrided; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + + // moves to the next GEMM-K offset (offset_nzpq_) in GEMM-B by a CTA-K tile + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_nzpq_[s] += Shape::kRow * problem_size_.split_k_slices; + } + } + + /// Returns the coordinate in the activation tensor x that is currently pointed to + /// by the iterator. + + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + // The subseqnet fast_divmod() operations are equivalent to the following logical computation: + // + // + // int n = offset_nzpq_[iteration_strided_] / (problem_size_.Z * problem_size_.P * problem_size_.Q); + // int residual = offset_nzpq_[iteration_strided_] % (problem_size_.Z * problem_size_.P * problem_size_.Q); + // + // int z = residual / (problem_size_.P * problem_size_.Q); + // residual = residual % (problem_size_.P * problem_size_.Q); + // + // int p = residual / problem_size_.Q; + // int q = residual % problem_size_.Q; + + int residual, n, z, p, q; + fast_divmod(n, residual, offset_nzpq_[iteration_strided_], params_.ZPQ, params_.zpq_mul, params_.zpq_shr); + fast_divmod(z, residual, residual, params_.PQ, params_.pq_mul, params_.pq_shr); + fast_divmod(p, q, residual, problem_size_.Q, params_.q_mul, params_.q_shr); + + int d = z * problem_size_.stride_d + precomputed_filter_t_[iteration_contiguous_]; + int h = p * problem_size_.stride_h + precomputed_filter_r_[iteration_contiguous_];; + int w = q * problem_size_.stride_w + precomputed_filter_s_[iteration_contiguous_]; + + return TensorCoord(n, d, h, w, filter_c_[iteration_contiguous_]); + } + + /// Returns true if the current coordinate is within the activation tensor x + CUTLASS_HOST_DEVICE + bool valid() const { + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.d() >= 0 && coord.d() < problem_size_.D && + coord.h() >= 0 && coord.h() < problem_size_.H && + coord.w() >= 0 && coord.w() < problem_size_.W && + coord.c() < problem_size_.C; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv3dWgradActivationTileAccessIteratorOptimized &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv3dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.K % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_analytic.h b/include/cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_analytic.h new file mode 100644 index 000000000..74017c09f --- /dev/null +++ b/include/cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_analytic.h @@ -0,0 +1,256 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (output gradient tile) + matrix from memory. + + This iterator assumes TensorNDHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv3dWgradOutputGradientTileAccessIteratorAnalytic { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNDHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kAnalytic; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 3; + using ConvProblemSize = typename conv::Conv3dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "WGRAD requires elements of size 8b or greater."); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + Conv3dProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + } + }; + +private: + + Params const ¶ms_; + Conv3dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + int filter_k_[ThreadMap::Iterations::kContiguous]; + + int offset_nzpq_[ThreadMap::Iterations::kStrided]; + +public: + + CUTLASS_HOST_DEVICE + Conv3dWgradOutputGradientTileAccessIteratorAnalytic( + Params const ¶ms, + Conv3dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)) { + + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + // initialize filter_k for every contiguous iteration + CUTLASS_PRAGMA_UNROLL + for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + filter_k_[c] = threadblock_offset.row() + thread_coord.contiguous() + + c * ThreadMap::Delta::kContiguous; + } + + // initialize n, p, q offset for every strided iteration + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_nzpq_[s] = threadblock_offset.column() + thread_coord.strided() + + s * ThreadMap::Delta::kStrided; + + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next GEMM-K offset (offset_nzpq_) in GEMM-A by a CTA-K tile + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + offset_nzpq_[s] += Shape::kColumn * problem_size_.split_k_slices; + } + } + + /// Returns the coordinate in the output gradient tensor Dy that is currently pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at() const { + + int nzpq = offset_nzpq_[iteration_strided_]; + + int n = nzpq / (problem_size_.Z * problem_size_.P * problem_size_.Q); + int residual = nzpq % (problem_size_.Z * problem_size_.P * problem_size_.Q); + + int z = residual / (problem_size_.P * problem_size_.Q); + residual = residual % (problem_size_.P * problem_size_.Q); + + int p = residual / problem_size_.Q; + int q = residual % problem_size_.Q; + + return TensorCoord(n, z, p, q, filter_k_[iteration_contiguous_]); + } + + + /// Returns true if the current coordinate is within the output gradient tensor Dy + CUTLASS_HOST_DEVICE + bool valid() const { + TensorCoord coord = at(); + + return coord.n() < problem_size_.N && + coord.d() < problem_size_.Z && + coord.h() < problem_size_.P && + coord.w() < problem_size_.Q && + coord.c() < problem_size_.K; + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + TensorCoord coord = at(); + LongIndex offset = params_.layout(coord); + + return reinterpret_cast(pointer_ + offset * sizeof_bits::value / 8); + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv3dWgradOutputGradientTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv3dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_optimized.h b/include/cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_optimized.h new file mode 100644 index 000000000..2cab09d1f --- /dev/null +++ b/include/cutlass/conv/threadblock/conv3d_wgrad_output_gradient_tile_access_iterator_optimized.h @@ -0,0 +1,330 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Templates implementing loading of convolution tiles mapped to GEMM A (output gradient tile) + matrix from memory. + + This iterator assumes TensorNDHWC layout of tensors in Global Memory. + + The iterator is specialized for each of the three convolution operators: forward propagation (Fprop), + backward data gradient (Dgrad), and backward weight gradient (Wgrad). +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/coord.h" +#include "cutlass/predicate_vector.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv3d_problem_size.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + typename Shape_, + typename Element_, + typename ThreadMap_ +> +class Conv3dWgradOutputGradientTileAccessIteratorOptimized { +public: + + // + // Types + // + using Shape = Shape_; + using Element = Element_; + using Layout = layout::TensorNDHWC; + using ThreadMap = ThreadMap_; + using AccessType = AlignedArray; + using TensorRef = cutlass::TensorRef; + using TensorCoord = typename Layout::TensorCoord; + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + static IteratorAlgorithm const kIteratorAlgorithm = conv::IteratorAlgorithm::kOptimized; + static StrideSupport const kStrideSupport = conv::StrideSupport::kStrided; + static int const kConvDim = 3; + using ConvProblemSize = typename conv::Conv3dProblemSize; + + static_assert(sizeof_bits::value >= 8, + "WGRAD requires elements of size 8b or greater."); + + // + // Parameters structure + // + + struct Params { + + Layout layout; + + int NZPQ; // precomputd product of N*Z*P*Q for clearing predicates + int ZPQ; // product of Z*P*Q + unsigned zpq_mul; // precomputed quantities for fast computation of div/% by ZPQ + unsigned zpq_shr; // in device code. + + int PQ; // product of P*Q + unsigned pq_mul; // precomputed quantities for fast computation of div/% by PQ + unsigned pq_shr; // in device code. + + unsigned q_mul; // precomputed quantities for fast computation of div/% by Q + unsigned q_shr; // in device code. + + LongIndex offset_next_strided; // offset in units of bytes to next nzpq coordinate within tile + LongIndex offset_next_contiguous; // offset in units of bytes to next k coordinate within tile + LongIndex inc_next_nzpq; // offset in units of bytes to next nzpq position in subsequent tile + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Params() { } + + CUTLASS_HOST_DEVICE + Params( + Conv3dProblemSize const &problem_size, + Layout const &layout + ): layout(layout) { + + // Incremental offsets in unites of bytes (number of elements) * sizeof_bits::value / 8 + offset_next_strided = (ThreadMap::Delta::kStrided * layout.stride()[0]) + * sizeof_bits::value / 8; + + offset_next_contiguous = (ThreadMap::Delta::kContiguous) + * sizeof_bits::value / 8; + + inc_next_nzpq = (Shape::kColumn * problem_size.split_k_slices * layout.stride()[0]) + * sizeof_bits::value / 8; + + // Precompute several quantities for fast modulo arithmetic. + NZPQ = problem_size.N * problem_size.Z * problem_size.P * problem_size.Q; + ZPQ = problem_size.Z * problem_size.P * problem_size.Q; + find_divisor(zpq_mul, zpq_shr, ZPQ); + + PQ = problem_size.P * problem_size.Q; + find_divisor(pq_mul, pq_shr, PQ); + + find_divisor(q_mul, q_shr, problem_size.Q); + + } + }; + +private: + + Params const ¶ms_; + Conv3dProblemSize const &problem_size_; + LongIndex iteration_contiguous_; + LongIndex iteration_strided_; + char const *pointer_; + + uint32_t predicates_; + int filter_k_; + int offset_nzpq_; + +public: + + CUTLASS_HOST_DEVICE + Conv3dWgradOutputGradientTileAccessIteratorOptimized( + Params const ¶ms, + Conv3dProblemSize const &problem_size, + Element const *ptr, + int thread_idx, + MatrixCoord const &threadblock_offset = MatrixCoord() + ): + params_(params), + problem_size_(problem_size), + pointer_(reinterpret_cast(ptr)), + predicates_(0), + filter_k_(0), + offset_nzpq_(0) { + + + layout::PitchLinearCoord thread_coord = ThreadMap::initial_offset(thread_idx); + + filter_k_ = threadblock_offset.row() + thread_coord.contiguous(); + offset_nzpq_ = threadblock_offset.column() + thread_coord.strided(); + + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + CUTLASS_PRAGMA_UNROLL + for (int c = 0; c < ThreadMap::Iterations::kContiguous; ++c) { + + int filter_k = filter_k_ + c * ThreadMap::Delta::kContiguous; + int offset_nzpq = offset_nzpq_ + s * ThreadMap::Delta::kStrided; + + bool predicate = valid_(at_(offset_nzpq, filter_k)); + + uint32_t pred = (predicate ? 1u : 0); + + int pred_idx = c + s * ThreadMap::Iterations::kContiguous; + + predicates_ |= (pred << pred_idx); + } + } + + // Offset pointer to (iteration_strided_, iteration_contiguous_) = (0, 0) + pointer_ += ( + offset_nzpq_ * params.layout.stride()[0] + filter_k_ + ) * sizeof_bits::value / 8; + + set_iteration_index(0); + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(Index index) { + iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; + iteration_strided_ = index / ThreadMap::Iterations::kContiguous; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + CUTLASS_HOST_DEVICE + void advance() { + // moves to the next GEMM-K offset (offset_npq_) in GEMM-A by a CTA-K tile + offset_nzpq_ += Shape::kColumn * problem_size_.split_k_slices; + + // Clear predicates if needed + CUTLASS_PRAGMA_UNROLL + for (int s = 0; s < ThreadMap::Iterations::kStrided; ++s) { + if (offset_nzpq_ + s * ThreadMap::Delta::kStrided >= params_.NZPQ) { + uint32_t kClearMask = ((1u << ThreadMap::Iterations::kContiguous) - 1) << (s * ThreadMap::Iterations::kContiguous); + predicates_ = (predicates_ & (~kClearMask)); + } + } + pointer_ += params_.inc_next_nzpq; + } + +private: + /// Returns the coordinate in the output gradient tensor Dy that is (offset_nzpq, k) pointed to + /// by the iterator. + CUTLASS_HOST_DEVICE + TensorCoord at_(int offset_nzpq, int k) const { + + // The subseqnet fast_divmod() operations are equivalent to the following logical computation: + // + // + // int nzpq = offset_nzpq_; + // int n = nzpq / (problem_size_.Z * problem_size_.P * problem_size_.Q); + // int residual = nzpq % (problem_size_.Z * problem_size_.P * problem_size_.Q); + // + // int z = residual / (problem_size_.P * problem_size_.Q); + // residual = residual % (problem_size_.P * problem_size_.Q); + // + // int p = residual / problem_size_.Q; + // int q = residual % problem_size_.Q; + + int residual, n, z, p, q; + fast_divmod(n, residual, offset_nzpq, params_.ZPQ, params_.zpq_mul, params_.zpq_shr); + fast_divmod(z, residual, residual, params_.PQ, params_.pq_mul, params_.pq_shr); + fast_divmod(p, q, residual, problem_size_.Q, params_.q_mul, params_.q_shr); + + return TensorCoord(n, z, p, q, k); + } + + /// Returns true if the coord is within the output gradient tensor Dy + CUTLASS_HOST_DEVICE + bool valid_(TensorCoord coord) const { + + return coord.n() < problem_size_.N && + coord.c() < problem_size_.K; + } + +public: + + /// Returns true if the current coordinate is within the output gradient tensor Dy + CUTLASS_HOST_DEVICE + bool valid() const { + + LongIndex pred_idx = iteration_contiguous_ + iteration_strided_ * ThreadMap::Iterations::kContiguous; + return (predicates_ & (1u << pred_idx)); + } + + /// Returns a pointer to the vector starting at the current coordinate + CUTLASS_HOST_DEVICE + AccessType const *get() const { + + return reinterpret_cast( + pointer_ + + iteration_strided_ * params_.offset_next_strided + + iteration_contiguous_ * params_.offset_next_contiguous + ); + + } + + /// Increments to the next memory access + CUTLASS_HOST_DEVICE + Conv3dWgradOutputGradientTileAccessIteratorOptimized &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; + } + + /// Determines whether the Implicit GEMM can execute the given problem. + CUTLASS_HOST_DEVICE + static Status can_implement(Conv3dProblemSize const &problem_size) { + + // check alignment constraint on iterator's contiguous dimension + if (problem_size.C % (128/sizeof_bits::value)) { + return Status::kErrorInvalidProblem; + } + + return Status::kSuccess; + } + +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace conv +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/include/cutlass/conv/threadblock/implicit_gemm_multistage.h b/include/cutlass/conv/threadblock/implicit_gemm_multistage.h new file mode 100644 index 000000000..1702847c1 --- /dev/null +++ b/include/cutlass/conv/threadblock/implicit_gemm_multistage.h @@ -0,0 +1,480 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Template for a multistage threadblock-scoped Implicit GEMM Convolution kernel. +*/ + +#pragma once + +#include "cutlass/aligned_buffer.h" +#include "cutlass/arch/memory.h" +#include "cutlass/array.h" +#include "cutlass/cutlass.h" +#include "cutlass/gemm/gemm.h" +#include "cutlass/matrix_shape.h" +#include "cutlass/numeric_types.h" +#include "cutlass/arch/cache_operation.h" +#include "cutlass/gemm/threadblock/mma_base.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Structure to compute the matrix product targeting CUDA cores and SIMT math +/// instructions. +template < + /// Size of the Gemm problem - concept: gemm::GemmShape<> + typename Shape_, + /// Iterates over tiles of A operand in global memory + // (concept: ReadableTileIterator | ForwardTileIterator | + // MaskedTileIterator) + typename IteratorA_, + /// Iterates over tiles of A operand in shared memory + /// (concept: WriteableTileIterator | RandomAccessTileIterator) + typename SmemIteratorA_, + /// Cache operation for operand A + cutlass::arch::CacheOperation::Kind CacheOpA, + /// Iterates over tiles of B operand in global memory + // (concept: ReadableTileIterator | ForwardTileIterator | + // MaskedTileIterator) + typename IteratorB_, + /// Iterates over tiles of B operand in shared memory + /// (concept: WriteableTileIterator | RandomAccessTileIterator) + typename SmemIteratorB_, + /// Cache operation for operand B + cutlass::arch::CacheOperation::Kind CacheOpB, + /// Policy describing tuning details (concept: MmaPolicy) + typename Policy_, + /// Number of stages, + int Stages, + /// Used for partial specialization + typename Enable = bool> +class ImplicitGemmMultistage : + public gemm::threadblock::MmaBase { +public: + ///< Base class + using Base = gemm::threadblock::MmaBase; + ///< Size of the Gemm problem - concept: gemm::GemmShape<> + using Shape = Shape_; + ///< Iterates over tiles of A operand in global memory + using IteratorA = IteratorA_; + ///< Iterates over tiles of B operand in global memory + using IteratorB = IteratorB_; + ///< Policy describing tuning details + using Policy = Policy_; + + using SmemIteratorA = SmemIteratorA_; + using SmemIteratorB = SmemIteratorB_; + + static cutlass::arch::CacheOperation::Kind const kCacheOpA = CacheOpA; + static cutlass::arch::CacheOperation::Kind const kCacheOpB = CacheOpB; + + // + // Dependent types + // + + /// Fragment of accumulator tile + + using ElementC = typename Policy::Operator::ElementC; + using FragmentC = typename Policy::Operator::FragmentC; + + /// Warp-level Mma + using Operator = typename Policy::Operator; + + /// Internal structure exposed for introspection. + struct Detail { + + static_assert(Base::kWarpGemmIterations > 1, + "The pipelined structure requires at least two warp-level " + "GEMM operations."); + + /// Number of cp.async instructions to load one stage of operand A + static int const AsyncCopyIterationsPerStageA = + IteratorA::ThreadMap::Iterations::kCount; + + /// Number of cp.async instructions to load one stage of operand B + static int const AsyncCopyIterationsPerStageB = + IteratorB::ThreadMap::Iterations::kCount; + + /// Number of stages + static int const kStages = Stages; + + /// Number of cp.async instructions to load on group of operand A + static int const kAccessesPerGroupA = + (AsyncCopyIterationsPerStageA + Base::kWarpGemmIterations - 1) / Base::kWarpGemmIterations; + + /// Number of cp.async instructions to load on group of operand B + static int const kAccessesPerGroupB = + (AsyncCopyIterationsPerStageB + Base::kWarpGemmIterations - 1) / Base::kWarpGemmIterations; + }; + + private: + + using WarpLoadedFragmentA = typename Operator::FragmentA; + using WarpLoadedFragmentB = typename Operator::FragmentB; + using WarpTransformedFragmentA = typename Operator::TransformedFragmentA; + using WarpTransformedFragmentB = typename Operator::TransformedFragmentB; + + private: + + // + // Data members + // + + /// Iterator to write threadblock-scoped tile of A operand to shared memory + SmemIteratorA smem_iterator_A_; + + /// Iterator to write threadblock-scoped tile of B operand to shared memory + SmemIteratorB smem_iterator_B_; + +public: + + /// Construct from tensor references + CUTLASS_DEVICE + ImplicitGemmMultistage( + ///< Shared storage needed for internal use by threadblock-scoped GEMM + typename Base::SharedStorage &shared_storage, + ///< ID within the threadblock + int thread_idx, + ///< ID of warp + int warp_idx, + ///< ID of each thread within a warp + int lane_idx + ): + Base(shared_storage, thread_idx, warp_idx, lane_idx), + smem_iterator_A_(shared_storage.operand_A_ref(), thread_idx), + smem_iterator_B_(shared_storage.operand_B_ref(), thread_idx) + { + // Compute warp location within threadblock tile by mapping the warp_id to + // three coordinates: + // _m: the warp's position within the threadblock along the M dimension + // _n: the warp's position within the threadblock along the N dimension + // _k: the warp's position within the threadblock along the K dimension + + int warp_idx_mn = warp_idx % (Base::WarpCount::kM * Base::WarpCount::kN); + int warp_idx_k = warp_idx / (Base::WarpCount::kM * Base::WarpCount::kN); + + int warp_idx_m = warp_idx_mn % Base::WarpCount::kM; + int warp_idx_n = warp_idx_mn / Base::WarpCount::kM; + + // Add per-warp offsets in units of warp-level tiles + this->warp_tile_iterator_A_.add_tile_offset( + {warp_idx_m, Base::kWarpGemmIterations * warp_idx_k}); + this->warp_tile_iterator_B_.add_tile_offset( + {Base::kWarpGemmIterations * warp_idx_k, warp_idx_n}); + } + + CUTLASS_DEVICE + void copy_tiles_and_advance( + IteratorA &iterator_A, IteratorB &iterator_B, + int group_start_A = 0, int group_start_B = 0) { + + iterator_A.set_iteration_index(group_start_A); + this->smem_iterator_A_.set_iteration_index(group_start_A); + + // Async Copy for operand A + CUTLASS_PRAGMA_UNROLL + for (int j = 0; j < Detail::kAccessesPerGroupA; ++j) { + + if (group_start_A + j < Detail::AsyncCopyIterationsPerStageA) { + typename IteratorA::AccessType *dst_ptr = + reinterpret_cast( + this->smem_iterator_A_.get()); + + int const kSrcBytes = sizeof_bits::value * + IteratorA::ThreadMap::kElementsPerAccess / 8; + + cutlass::arch::cp_async_zfill( + dst_ptr, iterator_A.get(), iterator_A.valid()); + + ++iterator_A; + + ++this->smem_iterator_A_; + } + } + + iterator_B.set_iteration_index(group_start_B); + + this->smem_iterator_B_.set_iteration_index(group_start_B); + + // Async Copy for operand B + CUTLASS_PRAGMA_UNROLL + for (int j = 0; j < Detail::kAccessesPerGroupB; ++j) { + if (group_start_B + j < Detail::AsyncCopyIterationsPerStageB) { + typename IteratorB::AccessType *dst_ptr = + reinterpret_cast( + this->smem_iterator_B_.get()); + + int const kSrcBytes = sizeof_bits::value * + IteratorB::ThreadMap::kElementsPerAccess / 8; + + cutlass::arch::cp_async_zfill( + dst_ptr, iterator_B.get(), iterator_B.valid()); + + ++iterator_B; + ++this->smem_iterator_B_; + } + } + } + + /// Perform a threadblock-scoped matrix multiply-accumulate + CUTLASS_DEVICE + void operator()( + ///< problem size of GEMM + int gemm_k_iterations, + ///< destination accumulator tile + FragmentC &accum, + ///< iterator over A operand in global memory + IteratorA iterator_A, + ///< iterator over B operand in global memory + IteratorB iterator_B, + ///< initial value of accumulator + FragmentC const &src_accum, + ///< Imaginary strides used for planar-complex only - ignored here + int64_t imag_stride_A = 0, + int64_t imag_stride_B = 0) { + + // + // Prologue + // + + // Issue several complete stages + CUTLASS_PRAGMA_UNROLL + for (int stage = 0; stage < Base::kStages - 1; + ++stage, --gemm_k_iterations) { + + iterator_A.set_iteration_index(0); + this->smem_iterator_A_.set_iteration_index(0); + + // Async Copy for operand A + CUTLASS_PRAGMA_UNROLL + for (int j = 0; j < Detail::AsyncCopyIterationsPerStageA; ++j) { + typename IteratorA::AccessType *dst_ptr = + reinterpret_cast( + this->smem_iterator_A_.get()); + + int const kSrcBytes = + sizeof_bits::value * + IteratorA::ThreadMap::kElementsPerAccess / 8; + + cutlass::arch::cp_async_zfill( + dst_ptr, iterator_A.get(), iterator_A.valid()); + + ++iterator_A; + ++this->smem_iterator_A_; + } + + iterator_B.set_iteration_index(0); + this->smem_iterator_B_.set_iteration_index(0); + + // Async Copy for operand B + CUTLASS_PRAGMA_UNROLL + for (int j = 0; j < Detail::AsyncCopyIterationsPerStageB; ++j) { + typename IteratorB::AccessType *dst_ptr = + reinterpret_cast( + this->smem_iterator_B_.get()); + + int const kSrcBytes = + sizeof_bits::value * + IteratorB::ThreadMap::kElementsPerAccess / 8; + + cutlass::arch::cp_async_zfill( + dst_ptr, iterator_B.get(), iterator_B.valid()); + + ++iterator_B; + ++this->smem_iterator_B_; + } + + // Move to the next stage + iterator_A.advance(); + iterator_B.advance(); + + this->smem_iterator_A_.add_tile_offset({0, 1}); + this->smem_iterator_B_.add_tile_offset({1, 0}); + + // Inserts a fence to group cp.async instructions into stages. + cutlass::arch::cp_async_fence(); + } + + // Perform accumulation in the 'd' output operand + accum = src_accum; + + // Waits until kStages-2 stages have committed. + cutlass::arch::cp_async_wait(); + __syncthreads(); + + // Pair of fragments used to overlap shared memory loads and math + // instructions + WarpLoadedFragmentA warp_loaded_frag_A[2]; + WarpLoadedFragmentB warp_loaded_frag_B[2]; + WarpTransformedFragmentA warp_transformed_frag_A[2]; + WarpTransformedFragmentB warp_transformed_frag_B[2]; + + Operator warp_mma; + + this->warp_tile_iterator_A_.set_kgroup_index(0); + this->warp_tile_iterator_B_.set_kgroup_index(0); + + this->warp_tile_iterator_A_.load(warp_loaded_frag_A[0]); + this->warp_tile_iterator_B_.load(warp_loaded_frag_B[0]); + + ++this->warp_tile_iterator_A_; + ++this->warp_tile_iterator_B_; + + // Start issuing the first group of the next stage outside of the mainloop + copy_tiles_and_advance(iterator_A, iterator_B); + + int smem_write_stage_idx = Base::kStages - 1; + int smem_read_stage_idx = 0; + + warp_mma.transform(warp_transformed_frag_A[0], warp_transformed_frag_B[0], + warp_loaded_frag_A[0], warp_loaded_frag_B[0]); + + // + // Mainloop + // + + CUTLASS_GEMM_LOOP + for (; gemm_k_iterations > (-Base::kStages + 1);) { + // + // Loop over GEMM K dimension + // + + // Computes a warp-level GEMM on data held in shared memory + // Each "warp_mma_k" refers to a warp-level matrix multiply-accumulate + CUTLASS_PRAGMA_UNROLL + for (int warp_mma_k = 0; warp_mma_k < Base::kWarpGemmIterations; + ++warp_mma_k) { + + // Load warp-level tiles from shared memory, wrapping to k offset if + // this is the last group as the case may be. + + this->warp_tile_iterator_A_.set_kgroup_index((warp_mma_k + 1) % Base::kWarpGemmIterations); + this->warp_tile_iterator_B_.set_kgroup_index((warp_mma_k + 1) % Base::kWarpGemmIterations); + + this->warp_tile_iterator_A_.load(warp_loaded_frag_A[(warp_mma_k + 1) % 2]); + this->warp_tile_iterator_B_.load(warp_loaded_frag_B[(warp_mma_k + 1) % 2]); + + ++this->warp_tile_iterator_A_; + ++this->warp_tile_iterator_B_; + + if (warp_mma_k > 0) + warp_mma.transform(warp_transformed_frag_A[warp_mma_k % 2], + warp_transformed_frag_B[warp_mma_k % 2], + warp_loaded_frag_A[warp_mma_k % 2], + warp_loaded_frag_B[warp_mma_k % 2]); + + // Issue global->shared copies for the next stage + int group_start_iteration_A, group_start_iteration_B; + + if (warp_mma_k + 1 == Base::kWarpGemmIterations) { + group_start_iteration_A = 0; + group_start_iteration_B = 0; + } else { + group_start_iteration_A = + (warp_mma_k + 1) * Detail::kAccessesPerGroupA; + group_start_iteration_B = + (warp_mma_k + 1) * Detail::kAccessesPerGroupB; + } + + copy_tiles_and_advance(iterator_A, iterator_B, group_start_iteration_A, + group_start_iteration_B); + + warp_mma( + accum, + warp_transformed_frag_A[warp_mma_k % 2], + warp_transformed_frag_B[warp_mma_k % 2], + accum + ); + + if (warp_mma_k + 1 == Base::kWarpGemmIterations) + warp_mma.transform(warp_transformed_frag_A[(warp_mma_k + 1) % 2], + warp_transformed_frag_B[(warp_mma_k + 1) % 2], + warp_loaded_frag_A[(warp_mma_k + 1) % 2], + warp_loaded_frag_B[(warp_mma_k + 1) % 2]); + + if (warp_mma_k + 2 == Base::kWarpGemmIterations) { + // Inserts a fence to group cp.async instructions into stages. + cutlass::arch::cp_async_fence(); + + // Waits until kStages-2 stages of cp.async have committed + arch::cp_async_wait(); + __syncthreads(); + + // Move to the next stage + iterator_A.advance(); + iterator_B.advance(); + + this->smem_iterator_A_.add_tile_offset({0, 1}); + this->smem_iterator_B_.add_tile_offset({1, 0}); + + // Add negative offsets to return iterators to the 'start' of the + // circular buffer in shared memory + if (smem_write_stage_idx == (Base::kStages - 1)) { + this->smem_iterator_A_.add_tile_offset({0, -Base::kStages}); + this->smem_iterator_B_.add_tile_offset({-Base::kStages, 0}); + smem_write_stage_idx = 0; + } else { + ++smem_write_stage_idx; + } + + if (smem_read_stage_idx == (Base::kStages - 1)) { + this->warp_tile_iterator_A_.add_tile_offset( + {0, -Base::kStages * Policy::kPartitionsK * + Base::kWarpGemmIterations}); + this->warp_tile_iterator_B_.add_tile_offset( + {-Base::kStages * Policy::kPartitionsK * + Base::kWarpGemmIterations, + 0}); + smem_read_stage_idx = 0; + } else { + ++smem_read_stage_idx; + } + + --gemm_k_iterations; + } + } + + } + + // Insert fence and wait for all outstanding cp.async operations to commit. + cutlass::arch::cp_async_fence(); + cutlass::arch::cp_async_wait<0>(); + __syncthreads(); + + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace gemm +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/conv/threadblock/implicit_gemm_pipelined.h b/include/cutlass/conv/threadblock/implicit_gemm_pipelined.h new file mode 100644 index 000000000..0d56ab6b3 --- /dev/null +++ b/include/cutlass/conv/threadblock/implicit_gemm_pipelined.h @@ -0,0 +1,313 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Template for a double-buffered threadblock-scoped GEMM kernel. +*/ + +#pragma once + +#include "cutlass/cutlass.h" +#include "cutlass/array.h" +#include "cutlass/aligned_buffer.h" +#include "cutlass/numeric_conversion.h" + +#include "cutlass/numeric_types.h" +#include "cutlass/matrix_shape.h" + +#include "cutlass/gemm/gemm.h" +#include "cutlass/gemm/threadblock/mma_base.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace conv { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Structure to compute the matrix product targeting CUDA cores and SIMT math instructions. +template < + /// Size of the Gemm problem - concept: gemm::GemmShape<> + typename Shape_, + /// Iterates over tiles of A operand in global memory + // (concept: ReadableTileIterator | ForwardTileIterator | MaskedTileIterator) + typename IteratorA_, + /// Iterates over tiles of A operand in shared memory + /// (concept: WriteableTileIterator | RandomAccessTileIterator) + typename SmemIteratorA_, + /// Iterates over tiles of B operand in global memory + // (concept: ReadableTileIterator | ForwardTileIterator | MaskedTileIterator) + typename IteratorB_, + /// Iterates over tiles of B operand in shared memory + /// (concept: WriteableTileIterator | RandomAccessTileIterator) + typename SmemIteratorB_, + /// Data type of accumulator matrix + typename ElementC_, + /// Data type of accumulator matrix + typename LayoutC_, + /// Policy describing tuning details (concept: MmaPolicy) + typename Policy_, + /// Transformation applied to A operand + typename TransformA_ = NumericArrayConverter< + typename SmemIteratorA_::Element, + typename IteratorA_::Element, + IteratorA_::Fragment::kElements>, + /// + /// Transformation applied to A operand + typename TransformB_ = NumericArrayConverter< + typename SmemIteratorB_::Element, + typename IteratorB_::Element, + IteratorB_::Fragment::kElements>, + /// Used for partial specialization + typename Enable = bool +> +class ImplicitGemmPipelined : public gemm::threadblock::MmaBase { +public: + + ///< Base class + using Base = gemm::threadblock::MmaBase; + + using Shape = Shape_; ///< Size of the Gemm problem - concept: gemm::GemmShape<> + using IteratorA = IteratorA_; ///< Iterates over tiles of A operand in global memory + using IteratorB = IteratorB_; ///< Iterates over tiles of B operand in global memory + using ElementC = ElementC_; ///< Data type of accumulator matrix + using LayoutC = LayoutC_; ///< Layout of accumulator matrix + using Policy = Policy_; ///< Policy describing tuning details + + using SmemIteratorA = SmemIteratorA_; + using SmemIteratorB = SmemIteratorB_; + + using TransformA = TransformA_; + using TransformB = TransformB_; + + // + // Dependent types + // + + /// Fragment of operand A loaded from global memory + using FragmentA = typename IteratorA::Fragment; + + /// Fragment of operand B loaded from global memory + using FragmentB = typename IteratorB::Fragment; + + /// Fragment of accumulator tile + using FragmentC = typename Policy::Operator::FragmentC; + + /// Warp-level Mma + using Operator = typename Policy::Operator; + + /// Obtain the arch tag from the warp-level operator + using ArchTag = typename Policy::Operator::ArchTag; + + /// Complex transform on A operand + static ComplexTransform const kTransformA = Operator::kTransformA; + + /// Complex transform on B operand + static ComplexTransform const kTransformB = Operator::kTransformB; + + // staticaly assert kStages for MmaPipelined is two (Double-buffered pipeline) + static_assert((Base::kStages==2), "MmaPipelined requires kStages set to value 2"); + +private: + + using WarpFragmentA = typename Operator::FragmentA; + using WarpFragmentB = typename Operator::FragmentB; + +protected: + + /// Iterator to write threadblock-scoped tile of A operand to shared memory + SmemIteratorA smem_iterator_A_; + + /// Iterator to write threadblock-scoped tile of B operand to shared memory + SmemIteratorB smem_iterator_B_; + +public: + + /// Construct from tensor references + CUTLASS_DEVICE + ImplicitGemmPipelined( + typename Base::SharedStorage &shared_storage, ///< Shared storage needed for internal use by threadblock-scoped GEMM + int thread_idx, ///< ID within the threadblock + int warp_idx, ///< ID of warp + int lane_idx ///< ID of each thread within a warp + ): + Base(shared_storage, thread_idx, warp_idx, lane_idx), + smem_iterator_A_(shared_storage.operand_A_ref(), thread_idx), + smem_iterator_B_(shared_storage.operand_B_ref(), thread_idx) { + + // Compute warp location within threadblock tile by mapping the warp_id to + // three coordinates: + // _m: the warp's position within the threadblock along the M dimension + // _n: the warp's position within the threadblock along the N dimension + // _k: the warp's position within the threadblock along the K dimension + + int warp_idx_mn = warp_idx % (Base::WarpCount::kM * Base::WarpCount::kN); + int warp_idx_k = warp_idx / (Base::WarpCount::kM * Base::WarpCount::kN); + + int warp_idx_m = warp_idx_mn % Base::WarpCount::kM; + int warp_idx_n = warp_idx_mn / Base::WarpCount::kM; + + // Add per-warp offsets in units of warp-level tiles + this->warp_tile_iterator_A_.add_tile_offset({warp_idx_m, Base::kWarpGemmIterations * warp_idx_k}); + this->warp_tile_iterator_B_.add_tile_offset({Base::kWarpGemmIterations * warp_idx_k, warp_idx_n}); + } + + /// Perform a threadblock-scoped matrix multiply-accumulate + CUTLASS_DEVICE + void operator()( + int gemm_k_iterations, ///< number of iterations of the mainloop + FragmentC &accum, ///< destination accumulator tile + IteratorA iterator_A, ///< iterator over A operand in global memory + IteratorB iterator_B, ///< iterator over B operand in global memory + FragmentC const &src_accum, ///< source accumulator tile + TransformA transform_A = TransformA(), ///< transformation applied to A fragment + TransformB transform_B = TransformB()) { ///< transformation applied to B fragment + + // + // Prologue + // + + // Perform accumulation in the 'd' output operand + accum = src_accum; + + FragmentA tb_frag_A; + FragmentB tb_frag_B; + + tb_frag_A.clear(); + tb_frag_B.clear(); + + // The last kblock is loaded in the prolog + iterator_A.load(tb_frag_A); + iterator_B.load(tb_frag_B); + + ++iterator_A; + ++iterator_B; + + this->smem_iterator_A_.store(transform_A(tb_frag_A)); + this->smem_iterator_B_.store(transform_B(tb_frag_B)); + + ++this->smem_iterator_A_; + ++this->smem_iterator_B_; + + __syncthreads(); + + // Pair of fragments used to overlap shared memory loads and math instructions + WarpFragmentA warp_frag_A[2]; + WarpFragmentB warp_frag_B[2]; + + this->warp_tile_iterator_A_.set_kgroup_index(0); + this->warp_tile_iterator_B_.set_kgroup_index(0); + + this->warp_tile_iterator_A_.load(warp_frag_A[0]); + this->warp_tile_iterator_B_.load(warp_frag_B[0]); + + ++this->warp_tile_iterator_A_; + ++this->warp_tile_iterator_B_; + + Operator warp_mma; + + int smem_write_stage_idx = 1; + + // Issue loads during the first warp-level matrix multiply-add *AFTER* issuing + // shared memory loads (which have the tighest latency requirement). + + // + // Mainloop + // + + // Note: The main loop does not support Base::kWarpGemmIterations == 2. + CUTLASS_GEMM_LOOP + for (; gemm_k_iterations > 0; --gemm_k_iterations) { + // + // Loop over GEMM K dimension + // + + CUTLASS_PRAGMA_UNROLL + for (int warp_mma_k = 0; warp_mma_k < Base::kWarpGemmIterations; ++warp_mma_k) { + + // Load warp-level tiles from shared memory, wrapping to k offset if this is the last group + // as the case may be. + + if (warp_mma_k == Base::kWarpGemmIterations - 1) { + + // Write fragments to shared memory + this->smem_iterator_A_.store(transform_A(tb_frag_A)); + + this->smem_iterator_B_.store(transform_B(tb_frag_B)); + + __syncthreads(); + + ++this->smem_iterator_A_; + ++this->smem_iterator_B_; + + // Add negative offsets to return iterators to the 'start' of the circular buffer in shared memory + if (smem_write_stage_idx == 1) { + this->smem_iterator_A_.add_tile_offset({0, -Base::kStages}); + this->smem_iterator_B_.add_tile_offset({-Base::kStages, 0}); + } + else { + this->warp_tile_iterator_A_.add_tile_offset( + {0, -Base::kStages * Policy::kPartitionsK * Base::kWarpGemmIterations}); + this->warp_tile_iterator_B_.add_tile_offset( + {-Base::kStages * Policy::kPartitionsK * Base::kWarpGemmIterations, + 0}); + } + + smem_write_stage_idx ^= 1; + } + + this->warp_tile_iterator_A_.set_kgroup_index((warp_mma_k + 1) % Base::kWarpGemmIterations); + this->warp_tile_iterator_B_.set_kgroup_index((warp_mma_k + 1) % Base::kWarpGemmIterations); + + this->warp_tile_iterator_A_.load(warp_frag_A[(warp_mma_k + 1) % 2]); + this->warp_tile_iterator_B_.load(warp_frag_B[(warp_mma_k + 1) % 2]); + + ++this->warp_tile_iterator_A_; + ++this->warp_tile_iterator_B_; + + if (warp_mma_k == 0) { + + iterator_A.load(tb_frag_A); + iterator_B.load(tb_frag_B); + + ++iterator_A; + ++iterator_B; + } + + warp_mma(accum, warp_frag_A[warp_mma_k % 2], + warp_frag_B[warp_mma_k % 2], accum); + } + } + + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace gemm +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/core_io.h b/include/cutlass/core_io.h index 1f624f1fa..bd69a707d 100644 --- a/include/cutlass/core_io.h +++ b/include/cutlass/core_io.h @@ -38,6 +38,9 @@ #include "cutlass/layout/pitch_linear.h" #include "cutlass/tensor_view.h" #include "cutlass/gemm/gemm.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/conv3d_problem_size.h" /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -156,13 +159,23 @@ namespace gemm { template inline std::ostream & operator<<(std::ostream &out, GemmShape const &gemm_shape) { - out << "cutlass::GemmShape::(kM, kN, kK) {" + out << "cutlass::gemm::GemmShape::(kM, kN, kK) {" << cutlass::gemm::GemmShape::kM <<"," << cutlass::gemm::GemmShape::kN <<"," << cutlass::gemm::GemmShape::kK << "}"; return out; } +/// Default printing to ostream for GemmCoord +inline +std::ostream & operator<<(std::ostream &out, GemmCoord const &gemm_coord) { + out << "cutlass::gemm::GemmCoord:: {" + << gemm_coord.m() <<"," + << gemm_coord.n() <<"," + << gemm_coord.k() << "}"; + return out; +} + } //namespace gemm /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -185,5 +198,44 @@ std::ostream & operator<<(std::ostream &out, PitchLinearShape(intermediate[i]); + scaled_accumulator[i] = __float2int_rn(intermediate[i]); } // Convert to destination numeric type @@ -385,7 +385,7 @@ public: CUTLASS_PRAGMA_UNROLL for (int i = 0; i < kCount; ++i) { - scaled_accumulator[i] = static_cast(intermediate[i]); + scaled_accumulator[i] = __float2int_rn(intermediate[i]); } // Convert to destination numeric type @@ -495,7 +495,7 @@ class FastLinearCombinationClamp { /// Functionally required for serial reduction in the epilogue CUTLASS_HOST_DEVICE - void set_k_partition(int k_partition) { + void set_k_partition(int k_partition, int k_partition_count) { if (k_partition) { beta_ = ElementCompute(1); } diff --git a/include/cutlass/epilogue/thread/linear_combination_planar_complex.h b/include/cutlass/epilogue/thread/linear_combination_planar_complex.h index 3934af104..68f334bdb 100644 --- a/include/cutlass/epilogue/thread/linear_combination_planar_complex.h +++ b/include/cutlass/epilogue/thread/linear_combination_planar_complex.h @@ -134,7 +134,7 @@ public: /// Functionally required for serial reduction in the epilogue CUTLASS_HOST_DEVICE - void set_k_partition(int k_partition) { + void set_k_partition(int k_partition, int k_partition_count) { if (k_partition) { beta_ = ElementCompute(1); } diff --git a/include/cutlass/epilogue/thread/linear_combination_relu.h b/include/cutlass/epilogue/thread/linear_combination_relu.h index 7a2fa9e8a..7a4140479 100644 --- a/include/cutlass/epilogue/thread/linear_combination_relu.h +++ b/include/cutlass/epilogue/thread/linear_combination_relu.h @@ -28,6 +28,7 @@ #pragma once +#include #include "cutlass/cutlass.h" #include "cutlass/numeric_types.h" #include "cutlass/array.h" @@ -77,7 +78,6 @@ public: ElementCompute threshold; ///< minimum value that is output ElementCompute const *alpha_ptr; ///< pointer to accumulator scalar - if not null, loads it from memory ElementCompute const *beta_ptr; ///< pointer to source scalar - if not null, loads it from memory - ElementCompute const *threshold_ptr; ///< pointer to threshold scalar - if not null, loads from memory // // Methods // @@ -88,15 +88,14 @@ public: beta(ElementCompute(0)), threshold(ElementCompute(0)), alpha_ptr(nullptr), - beta_ptr(nullptr), - threshold_ptr(nullptr) { } + beta_ptr(nullptr) { } CUTLASS_HOST_DEVICE Params( ElementCompute alpha, ElementCompute beta, ElementCompute threshold = ElementCompute(0) - ): alpha(alpha), beta(beta), threshold(threshold), alpha_ptr(nullptr), beta_ptr(nullptr), threshold_ptr(nullptr) { + ): alpha(alpha), beta(beta), threshold(threshold), alpha_ptr(nullptr), beta_ptr(nullptr) { } @@ -104,8 +103,8 @@ public: Params( ElementCompute const *alpha_ptr, ElementCompute const *beta_ptr, - ElementCompute const *threshold_ptr = nullptr - ): alpha(0), beta(0), alpha_ptr(alpha_ptr), beta_ptr(beta_ptr), threshold_ptr(threshold_ptr) { + ElementCompute threshold = ElementCompute(0) + ): alpha(0), beta(0), threshold(threshold), alpha_ptr(alpha_ptr), beta_ptr(beta_ptr) { } }; @@ -128,7 +127,7 @@ public: alpha_ = (params.alpha_ptr ? *params.alpha_ptr : params.alpha); beta_ = (params.beta_ptr ? *params.beta_ptr : params.beta); - threshold_ = (params.threshold_ptr ? *params.threshold_ptr : params.threshold); + threshold_ = params.threshold; } /// Returns true if source is needed @@ -139,10 +138,16 @@ public: /// Functionally required for serial reduction in the epilogue CUTLASS_HOST_DEVICE - void set_k_partition(int k_partition) { + void set_k_partition(int k_partition, int k_partition_count) { if (k_partition) { beta_ = ElementCompute(1); } + + if (k_partition != k_partition_count - 1) { + // set to NaN to make ReLU no-op for all except last k partitions + int64_t allones = -1; + threshold_ = reinterpret_cast(allones); + } } /// Computes linear scaling: D = alpha * accumulator + beta * source @@ -205,7 +210,6 @@ public: } }; - ///////////////////////////////////////////////////////////////////////////////////////////////// // Conditional guards to enable partial specialization for packed integers @@ -245,7 +249,6 @@ public: ElementCompute threshold; ///< minimum value that is output ElementCompute const *alpha_ptr; ///< pointer to accumulator scalar - if not null, loads it from memory ElementCompute const *beta_ptr; ///< pointer to source scalar - if not null, loads it from memory - ElementCompute const *threshold_ptr; ///< pointer to threshold scalar - if not null, loads from memory // // Methods // @@ -256,15 +259,14 @@ public: beta(ElementCompute(0)), threshold(ElementCompute(0)), alpha_ptr(nullptr), - beta_ptr(nullptr), - threshold_ptr(nullptr) { } + beta_ptr(nullptr) { } CUTLASS_HOST_DEVICE Params( ElementCompute alpha, ElementCompute beta, ElementCompute threshold = ElementCompute(0) - ): alpha(alpha), beta(beta), threshold(threshold), alpha_ptr(nullptr), beta_ptr(nullptr), threshold_ptr(nullptr) { + ): alpha(alpha), beta(beta), threshold(threshold), alpha_ptr(nullptr), beta_ptr(nullptr) { } @@ -272,8 +274,8 @@ public: Params( ElementCompute const *alpha_ptr, ElementCompute const *beta_ptr, - ElementCompute const *threshold_ptr = nullptr - ): alpha(0), beta(0), alpha_ptr(alpha_ptr), beta_ptr(beta_ptr), threshold_ptr(threshold_ptr) { + ElementCompute threshold = ElementCompute(0) + ): alpha(0), beta(0), threshold(threshold), alpha_ptr(alpha_ptr), beta_ptr(beta_ptr) { } }; @@ -296,7 +298,7 @@ public: alpha_ = (params.alpha_ptr ? *params.alpha_ptr : params.alpha); beta_ = (params.beta_ptr ? *params.beta_ptr : params.beta); - threshold_ = (params.threshold_ptr ? *params.threshold_ptr : params.threshold); + threshold_ = params.threshold; } /// Returns true if source is needed @@ -307,10 +309,16 @@ public: /// Functionally required for serial reduction in the epilogue CUTLASS_HOST_DEVICE - void set_k_partition(int k_partition) { + void set_k_partition(int k_partition, int k_partition_count) { if (k_partition) { beta_ = ElementCompute(1); } + + if (k_partition != k_partition_count - 1) { + // set to NaN to make ReLU no-op for all except last k partitions + int64_t allones = -1; + threshold_ = reinterpret_cast(allones); + } } /// Computes linear scaling: D = alpha * accumulator + beta * source @@ -331,26 +339,41 @@ public: multiplies mul_add_source; multiply_add mul_add_accumulator; - ReLu relu; + ReLu relu; intermediate = mul_add_source(beta_, converted_source); // X = beta * C + uniform intermediate = mul_add_accumulator(alpha_, converted_accumulator, intermediate); // D = alpha * Accum + X - // Convert floats back to INT - FragmentAccumulator scaled_accumulator; - - CUTLASS_PRAGMA_UNROLL - for (int i = 0; i < kCount; ++i) { - scaled_accumulator[i] = static_cast(intermediate[i]); - } - // Compute threshold optionally - scaled_accumulator = relu(threshold_, scaled_accumulator); + intermediate = relu(threshold_, intermediate); - // Convert to destination numeric type - NumericArrayConverter destination_converter; + if (platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value) { + // Convert floats back to INT + FragmentAccumulator scaled_accumulator; - return destination_converter(scaled_accumulator); + CUTLASS_PRAGMA_UNROLL + for (int i = 0; i < kCount; ++i) { + scaled_accumulator[i] = __float2int_rn(intermediate[i]); + } + + // Convert to destination numeric type + NumericArrayConverter + destination_converter; + + return destination_converter(scaled_accumulator); + } else { + NumericArrayConverter + destination_converter; + return destination_converter(intermediate); + } } /// Computes linear scaling: D = alpha * accumulator @@ -367,25 +390,48 @@ public: ComputeFragment intermediate; multiplies mul_accumulator; - ReLu relu; + ReLu relu; intermediate = mul_accumulator(alpha_, converted_accumulator); // D = alpha * Accum + // Compute threshold optionally + intermediate = relu(threshold_, intermediate); + // Convert floats back to INT FragmentAccumulator scaled_accumulator; CUTLASS_PRAGMA_UNROLL for (int i = 0; i < kCount; ++i) { - scaled_accumulator[i] = static_cast(intermediate[i]); + scaled_accumulator[i] = __float2int_rn(intermediate[i]); } - // Compute threshold optionally - scaled_accumulator = relu(threshold_, scaled_accumulator); + if (platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value || + platform::is_same::value) { + // Convert floats back to INT + FragmentAccumulator scaled_accumulator; - // Convert to destination numeric type - NumericArrayConverter destination_converter; + CUTLASS_PRAGMA_UNROLL + for (int i = 0; i < kCount; ++i) { + scaled_accumulator[i] = __float2int_rn(intermediate[i]); + } - return destination_converter(scaled_accumulator); + // Convert to destination numeric type + NumericArrayConverter + destination_converter; + + return destination_converter(scaled_accumulator); + } else { + NumericArrayConverter + destination_converter; + return destination_converter(intermediate); + } } }; @@ -398,4 +444,3 @@ public: } // namespace cutlass ///////////////////////////////////////////////////////////////////////////////////////////////// - diff --git a/include/cutlass/epilogue/thread/linear_combination_sigmoid.h b/include/cutlass/epilogue/thread/linear_combination_sigmoid.h index 3a65c49ac..dbefd2258 100644 --- a/include/cutlass/epilogue/thread/linear_combination_sigmoid.h +++ b/include/cutlass/epilogue/thread/linear_combination_sigmoid.h @@ -133,7 +133,7 @@ public: /// Functionally required for serial reduction in the epilogue CUTLASS_HOST_DEVICE - void set_k_partition(int k_partition) { + void set_k_partition(int k_partition, int k_partition_count) { if (k_partition) { beta_ = ElementCompute(1); } diff --git a/include/cutlass/epilogue/threadblock/default_epilogue_tensor_op.h b/include/cutlass/epilogue/threadblock/default_epilogue_tensor_op.h index 8390ee0b4..08b829be1 100644 --- a/include/cutlass/epilogue/threadblock/default_epilogue_tensor_op.h +++ b/include/cutlass/epilogue/threadblock/default_epilogue_tensor_op.h @@ -367,6 +367,52 @@ struct DefaultInterleavedEpilogueTensorOp { //////////////////////////////////////////////////////////////////////////////// +/// Defines sensible defaults for epilogues for TensorOps which uses +/// intereleaved output layout. For this case, shared memory is not needed. +template +struct DefaultInterleavedConvEpilogue { + using Shape = Shape_; + using WarpMmaTensorOp = WarpMmaTensorOp_; + static int const kPartitionsK = PartitionsK; + using OutputOp = OutputOp_; + static int const kElementsPerAccess = ElementsPerAccess; + + using ElementOutput = typename OutputOp::ElementOutput; + using ElementAccumulator = typename WarpMmaTensorOp::ElementC; + + // + // Thread map + // + using OutputTileThreadMap = typename cutlass::epilogue::threadblock:: + DefaultInterleavedConvThreadMapTensorOp< + Shape, typename WarpMmaTensorOp::Shape, kPartitionsK, ElementOutput, + kElementsPerAccess, InterleavedK>::Type; + + using OutputTileIterator = + cutlass::epilogue::threadblock::InterleavedConvPredicatedTileIterator< + OutputTileThreadMap, ElementOutput, InterleavedK>; + + using AccumulatorFragmentIterator = + cutlass::epilogue::warp::FragmentIteratorTensorOp< + typename WarpMmaTensorOp::Shape, + typename WarpMmaTensorOp::Policy::Operator::Shape, + typename WarpMmaTensorOp::Policy::Operator::ElementC, + typename WarpMmaTensorOp::Policy::Operator::FragmentC, + // can reuse the gemm version here to do element selection + layout::ColumnMajorInterleaved>; + + // + // Define the epilogue + // + using Epilogue = cutlass::epilogue::threadblock::InterleavedEpilogue< + Shape, WarpMmaTensorOp, kPartitionsK, OutputTileIterator, + AccumulatorFragmentIterator, OutputOp, InterleavedK, IsBetaZero>; +}; + +//////////////////////////////////////////////////////////////////////////////// + } // namespace threadblock } // namespace epilogue } // namespace cutlass diff --git a/include/cutlass/epilogue/threadblock/default_thread_map_tensor_op.h b/include/cutlass/epilogue/threadblock/default_thread_map_tensor_op.h index 96e4335ca..752b1ee9b 100644 --- a/include/cutlass/epilogue/threadblock/default_thread_map_tensor_op.h +++ b/include/cutlass/epilogue/threadblock/default_thread_map_tensor_op.h @@ -144,6 +144,55 @@ struct DefaultInterleavedThreadMapTensorOp { Detail::kThreads, kElementsPerAccess, sizeof_bits::value>; }; + +//////////////////////////////////////////////////////////////////////////////// + +/// Defines the optimal thread map for TensorOp accumulator layouts +template +struct DefaultInterleavedConvThreadMapTensorOp { + using ThreadblockShape = ThreadblockShape_; + using WarpShape = WarpShape_; + static int const kPartitionsK = PartitionsK; + using Element = Element_; + static int const kElementsPerAccess = ElementsPerAccess; + static int const kInterleavedK = InterleavedK; + + // + // Definitions + // + + struct Detail { + /// Tensor Operations fundamentally perform operations on 8 rows + static int const kTensorOpRows = 8; + static int const kWarpSize = 32; + + static_assert(!(ThreadblockShape::kM % WarpShape::kM) && + !(ThreadblockShape::kN % WarpShape::kN), + "Divisibility"); + + /// Number of warps + using WarpCount = + gemm::GemmShape; + + /// Number of participating threads + static int const kThreads = WarpCount::kCount * kWarpSize; + }; + + // + // ThreadMap + // + + /// ThreadMap to be used by epilogue::MaskedTileIterator satisfying concept + /// InterleavedOutputTileThreadMap + using Type = InterleavedConvOutputTileThreadMap< + MatrixShape, + MatrixShape, + Detail::kThreads, kElementsPerAccess, sizeof_bits::value>; +}; + //////////////////////////////////////////////////////////////////////////////// } // namespace threadblock diff --git a/include/cutlass/epilogue/threadblock/output_iterator_parameter.h b/include/cutlass/epilogue/threadblock/output_iterator_parameter.h new file mode 100644 index 000000000..8cfba768c --- /dev/null +++ b/include/cutlass/epilogue/threadblock/output_iterator_parameter.h @@ -0,0 +1,92 @@ +#pragma once + +#include "cutlass/cutlass.h" + +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/conv3d_problem_size.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/tensor_ref.h" + +namespace cutlass { +namespace epilogue { +namespace threadblock { + +template< + typename TensorLayout_, ///! The original output tensor layout + typename OutputIteratorLayout_, ///! Layout used by epilogue output iterator + typename TensorRef_, ///! Input tensor to epilogue output iterator + conv::Operator ConvOperator, ///! Convolutional operator (Fprop, Dgrad, Wgrad) + typename ConvProblemSize_ ///! Convolutional operator on 2D or 3D problem +> +struct ConvOutputIteratorParameter { + + using TensorLayout = TensorLayout_; + using OutputIteratorLayout = OutputIteratorLayout_; + using OutputTensorCoord = typename OutputIteratorLayout::TensorCoord; + using TensorRef = TensorRef_; + static conv::Operator const kConvolutionalOperator = ConvOperator; + using ConvProblemSize = ConvProblemSize_; + + /// Wgrad stride idx for implicit gemm algorithm + // Conv2d row-major matrix (KxRSC) + // Conv3d row-major matrix (KxTRSC) + static int const kWgradStrideIdx = + platform::is_same::value ? 2 : 3; + + /// This chooses the appropriate stride element of the C tensor. + static int const kTensorStrideIdx = + (kConvolutionalOperator == conv::Operator::kWgrad ? kWgradStrideIdx : 0); + + + CUTLASS_HOST_DEVICE + static OutputIteratorLayout layout(const TensorRef & ref) { + return ref.stride(kTensorStrideIdx); + } + + CUTLASS_HOST_DEVICE + static OutputTensorCoord extent(ConvProblemSize problem_size) { + return conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn(); + } + +}; + + + +template < + int InterleavedK, + typename TensorRef_, + conv::Operator ConvOperator, + typename ConvProblemSize_ +> +struct ConvOutputIteratorParameter< + layout::TensorNCxHWx, + layout::TensorNCxHWx, + TensorRef_, + ConvOperator, + ConvProblemSize_> +{ + + using TensorLayout = typename layout::TensorNCxHWx; + using OutputIteratorLayout = typename layout::TensorNCxHWx; + using OutputTensorCoord = typename OutputIteratorLayout::TensorCoord; + using TensorRef = TensorRef_; + static conv::Operator const kConvolutionalOperator = ConvOperator; + using ConvProblemSize = ConvProblemSize_; + + CUTLASS_HOST_DEVICE + static OutputIteratorLayout layout(const TensorRef & ref) { + return ref.stride(); + } + + CUTLASS_HOST_DEVICE + static OutputTensorCoord extent(ConvProblemSize problem_size) { + return problem_size.output_extent(); + } + +}; + +} // namespace threadblock +} // namespace epilogue +} // namespace cutlass diff --git a/include/cutlass/epilogue/threadblock/output_tile_thread_map.h b/include/cutlass/epilogue/threadblock/output_tile_thread_map.h index 4eb5e3784..cfe13cc16 100644 --- a/include/cutlass/epilogue/threadblock/output_tile_thread_map.h +++ b/include/cutlass/epilogue/threadblock/output_tile_thread_map.h @@ -488,6 +488,68 @@ struct InterleavedOutputTileThreadMap { } }; + +//////////////////////////////////////////////////////////////////////////////// + +/// Template metaprogram for partitioning a 4D interleaved layout across warps +/// to achieve several performance objectives: +/// +/// - coalesced memory accesses in units of 64 Byte lines +/// - minimal address arithmetic +/// - minimal predicate calculations +/// +template +struct InterleavedConvOutputTileThreadMap { + using WarpCount = WarpCount_; + + static int const kWarpSize = 32; + static int const kThreads = Threads; + static int const kWarpCount = kThreads / kWarpSize; + + static int const kElementsPerAccess = ElementsPerAccess; + static int const kElementSize = ElementSize; + + // + // Metaprogram computation + // + + struct Detail {}; + + // + // Output + // + + using Iterations = Iterations_; + + using Delta = MatrixShape; + + /// Initial offset function + CUTLASS_HOST_DEVICE + static MatrixCoord initial_offset(int thread_idx) { + int warp_idx = thread_idx / kWarpSize; + int lane_idx = thread_idx % kWarpSize; + + // Compute warp location + MatrixCoord warp_footprint{ + Delta::kRow * Iterations::kRow, + Delta::kColumn * Iterations::kColumn, + }; + + MatrixCoord warp_offset{warp_idx % WarpCount::kRow, + warp_idx / WarpCount::kRow}; + + // Compute per-lane offset + MatrixCoord thread_offset_in_warp{lane_idx / 4, + (lane_idx % 4) * kElementsPerAccess}; + + MatrixCoord thread_offset_in_threadblock_tile = + warp_footprint * warp_offset + thread_offset_in_warp; + + return thread_offset_in_threadblock_tile; + } +}; + //////////////////////////////////////////////////////////////////////////////// } // namespace threadblock diff --git a/include/cutlass/epilogue/threadblock/predicated_tile_iterator.h b/include/cutlass/epilogue/threadblock/predicated_tile_iterator.h index 05af759a5..1be50cbd9 100644 --- a/include/cutlass/epilogue/threadblock/predicated_tile_iterator.h +++ b/include/cutlass/epilogue/threadblock/predicated_tile_iterator.h @@ -43,6 +43,7 @@ #include "cutlass/epilogue/threadblock/output_tile_thread_map.h" #include "cutlass/arch/arch.h" #include "cutlass/arch/memory.h" +#include "cutlass/epilogue/threadblock/predicated_tile_iterator_params.h" //////////////////////////////////////////////////////////////////////////////// @@ -102,68 +103,20 @@ public: // Parameters struct // - struct Params { - - // - // Data members - // - - LongIndex stride; ///< stride in bytes between rows - - LongIndex increment_row; ///< increment quantity (in bytes) to advance when moving between rows - LongIndex increment_group; ///< increment quantity (in bytes) to advance when moving to the next group - LongIndex increment_cluster; ///< increment quantity (in bytes) to advance when moving to the next cluster - - LongIndex advance_row; ///< amount to add to move to the next 'row' position - LongIndex advance_group; ///< amount to add to move to the next 'group' position - LongIndex advance_cluster; ///< amount to add to move to the next 'cluster' position - LongIndex advance_tile; ///< amount to add to move to the next 'tile' - - // - // Methods - // + /// Uses a non-template class + struct Params : PredicatedTileIteratorParams { CUTLASS_HOST_DEVICE - Status initialize(Index stride_) { - - stride = LongIndex(stride_); - - increment_row = stride * ThreadMap::Delta::kRow; - - increment_group = stride * ThreadMap::Delta::kGroup - - stride * ThreadMap::Delta::kRow * (ThreadMap::Iterations::kRow - 1); - - increment_cluster = stride * ThreadMap::Delta::kCluster - - stride * ThreadMap::Delta::kGroup * (ThreadMap::Iterations::kGroup - 1) - - stride * ThreadMap::Delta::kRow * (ThreadMap::Iterations::kRow - 1); - - advance_row = stride * ThreadMap::Shape::kRow; - - advance_group = stride * (ThreadMap::Shape::kGroup - 1) * ThreadMap::Shape::kRow * ThreadMap::Count::kRow; - - advance_cluster = - stride * - ThreadMap::Count::kGroup * ThreadMap::Shape::kGroup * ThreadMap::Count::kRow * ThreadMap::Shape::kRow;; - - advance_tile = - stride * - ThreadMap::Shape::kGroup * - ThreadMap::Shape::kRow * - ThreadMap::Shape::kCluster * - ThreadMap::Shape::kTile; - - return Status::kSuccess; - } + Params() { } CUTLASS_HOST_DEVICE - Params() { - initialize(0); - } - - CUTLASS_HOST_DEVICE - Params(Layout const &layout) { - - initialize(layout.stride(0) * int(sizeof(AccessType)) / kElementsPerAccess); + Params(Layout const &layout): + PredicatedTileIteratorParams( + layout.stride(0) * int(sizeof(AccessType)) / kElementsPerAccess, + make_OutputTileThreadMapDesc() + ) + { + } }; @@ -207,7 +160,7 @@ private: // /// Parameters structure containing reference and precomputed state. - Params params_; + PredicatedTileIteratorParams params_; /// Byte-level pointer uint8_t *byte_pointer_; @@ -239,12 +192,13 @@ public: /// Constructor CUTLASS_DEVICE PredicatedTileIterator( - Params const & params, + PredicatedTileIteratorParams const & params, Element *pointer, TensorCoord extent, int thread_idx, TensorCoord threadblock_offset = TensorCoord() - ): params_(params) + ): + params_(params) { TensorCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset; @@ -745,6 +699,309 @@ public: }; /////////////////////////////////////////////////////////////////////////////// + +/// Tile iterator used to load output tile from shared memory in epilogue. +/// +/// Satisfies: ReadableTileIterator | InterleavedMaskedTileIterator | ForwardTileIterator +/// +template < + typename ThreadMap_, ///< Thread map (conept: OutputTileThreadMap) + typename Element_, ///< Element data type + int InterleavedN ///< Number of Interleaved N +> +class InterleavedConvPredicatedTileIterator { +public: + using ThreadMap = ThreadMap_; + + using Element = Element_; + + using Layout = layout::TensorNCxHWx; + using TensorRef = TensorRef; + using ConstTensorRef = typename TensorRef::ConstTensorRef; + + using Index = typename Layout::Index; + using LongIndex = typename Layout::LongIndex; + using TensorCoord = Tensor4DCoord; + + static int const kElementsPerAccess = ThreadMap::kElementsPerAccess; + static int const kThreads = ThreadMap::kThreads; + static int const kIterations = ThreadMap::Iterations::kCount; + + /// Fragment object + using Fragment = Array; + + /// Memory access size + using AccessType = AlignedArray; + + // + // Parameters struct + // + + struct Params { + + // + // Data members + // + + LongIndex stride_col; ///< stride in bytes between columns + LongIndex stride_row; ///< stride in bytes between rows + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Status initialize(typename Layout::Stride stride_) { + stride_col = stride_[1]; + stride_row = stride_[2]; + + return Status::kSuccess; + } + + CUTLASS_HOST_DEVICE + Params() { + initialize(cutlass::make_Coord(0, 0, 0)); + } + + CUTLASS_HOST_DEVICE + Params(Layout const &layout) { + + initialize(layout.stride()); + } + }; + + /// Mask object + struct Mask { + static int const kCount = + (ThreadMap::Iterations::kRow < 8) ? 8 : ThreadMap::Iterations::kRow; + + /// Predicate state + bool predicates[kCount]; + + // + // Mask + // + CUTLASS_HOST_DEVICE + Mask() { + enable(); + } + + ///< Efficiently disables all accesses guarded by mask + CUTLASS_HOST_DEVICE void clear() { + CUTLASS_PRAGMA_UNROLL + for (int i = 0; i < kCount; ++i) { + predicates[i] = false; + } + } + + ///< CUTLASS_HOST_DEVICE enables all accesses guarded by mask + CUTLASS_DEVICE void enable() { + CUTLASS_PRAGMA_UNROLL + for (int i = 0; i < kCount; ++i) { + predicates[i] = true; + } + } + }; + +private: + + // + // Data members + // + + /// Parameters structure containing reference and precomputed state. + Params params_; + + /// Byte-level pointer + uint8_t *byte_pointer_; + + /// Array of boolean values to contain steady-state predicates + Mask mask_; + + /// Extent of the matrix tile in columns + Index extent_col_; + + /// Extent of the matrix tile in rows + Index extent_row_; + + /// Extent of the matrix tile in pq + Index extent_pq_; + + /// A thread's starting row position (assuming steady-state predicates have + /// been computed) + Index thread_start_row_; + + /// A thread's starting column position (assuming steady-state predicates have + /// been computed) + Index thread_start_col_; + + /// Internal iteration counter + LongIndex iteration_row_; + LongIndex iteration_col_; + + uint32_t pq_mul_; + + uint32_t pq_shr_; + +private: + + // + // Methods + // + +public: + + // + // Methods + // + + /// Constructor + CUTLASS_DEVICE + InterleavedConvPredicatedTileIterator( + Params const & params, + Element *pointer, + TensorCoord extent, + int thread_idx, + MatrixCoord threadblock_offset + ): + params_(params) { + MatrixCoord thread_offset = ThreadMap::initial_offset(thread_idx) + threadblock_offset; + + extent_col_ = extent.c(); + extent_pq_ = extent.h() * extent.w(); + extent_row_ = extent.n() * extent_pq_; + + find_divisor(pq_mul_, pq_shr_, extent_pq_); + + thread_start_row_ = thread_offset.row(); + thread_start_col_ = thread_offset.column(); + + // Initialize predicates + CUTLASS_PRAGMA_UNROLL + for (int r = 0; r < ThreadMap::Iterations::kRow; ++r) { + mask_.predicates[r] = + ((thread_offset.row() + ThreadMap::Delta::kRow * r) < extent_row_); + } + + // Initialize pointer + byte_pointer_ = reinterpret_cast(pointer) + + ((thread_start_col_ / InterleavedN) * params_.stride_col + + (thread_start_col_ % InterleavedN)) * + sizeof_bits::value / 8; + + // Initialize internal state counter + iteration_row_ = iteration_col_ = 0; + } + + /// Adds a pointer offset in units of Element + CUTLASS_HOST_DEVICE + void add_pointer_offset(LongIndex pointer_offset) { + byte_pointer_ += pointer_offset * sizeof_bits::value / 8; + } + + /// Loads a fragment from memory + CUTLASS_DEVICE + void load(Fragment &frag) { + + int col_offset = iteration_col_ * ThreadMap::Delta::kColumn; + bool col_guard = ((thread_start_col_ + col_offset) < extent_col_); + bool guard = col_guard && mask_.predicates[iteration_row_]; + + int n, pq_rem; + + fast_divmod(n, pq_rem, + thread_start_row_ + iteration_row_ * ThreadMap::Delta::kRow, + extent_pq_, pq_mul_, pq_shr_); + + uint8_t *byte_pointer = + byte_pointer_ + (n * params_.stride_row + pq_rem * InterleavedN) * + sizeof_bits::value / 8; + AccessType *frag_ptr = reinterpret_cast(&frag); + AccessType const *memory_pointer = + reinterpret_cast(byte_pointer); + + cutlass::arch::global_load< + AccessType, + sizeof(AccessType) + >( + *frag_ptr, + (void *)memory_pointer, + guard); + } + + /// Stores a fragment to memory + CUTLASS_DEVICE + void store(Fragment const &frag) { + + int col_offset = iteration_col_ * ThreadMap::Delta::kColumn; + bool col_guard = ((thread_start_col_ + col_offset) < extent_col_); + bool guard = col_guard && mask_.predicates[iteration_row_]; + + int n, pq_rem; + + fast_divmod(n, pq_rem, + thread_start_row_ + iteration_row_ * ThreadMap::Delta::kRow, + extent_pq_, pq_mul_, pq_shr_); + + uint8_t *byte_pointer = + byte_pointer_ + (n * params_.stride_row + pq_rem * InterleavedN) * + sizeof_bits::value / 8; + AccessType const *frag_ptr = reinterpret_cast(&frag); + AccessType *memory_pointer = reinterpret_cast(byte_pointer); + + if (guard) { + *memory_pointer = *frag_ptr; + } + } + + /// Overrides the internal iteration index + CUTLASS_HOST_DEVICE + void set_iteration_index(int iteration) { + iteration_row_ = iteration % ThreadMap::Iterations::kRow; + iteration_col_ = iteration / ThreadMap::Iterations::kRow; + } + + /// Advances to the next position to load or store + CUTLASS_HOST_DEVICE + InterleavedConvPredicatedTileIterator &operator++() { + + ++iteration_row_; + + if (iteration_row_ == ThreadMap::Iterations::kRow) { + + iteration_row_ = 0; + ++iteration_col_; + byte_pointer_ += params_.stride_col; + + if (iteration_col_ == ThreadMap::Iterations::kColumn) { + iteration_col_ = 0; + } + } + + return *this; + } + + ///< Efficiently disables all accesses guarded by mask + CUTLASS_DEVICE void clear_mask() { + mask_.clear(); + } + + ///< Efficiently enables all accesses guarded by mask + CUTLASS_DEVICE void enable_mask() { + mask_.enable(); + } + + ///< Sets the mask + CUTLASS_DEVICE void get_mask(Mask &mask) { + return mask_; + } + + ///< Sets the mask + CUTLASS_DEVICE void set_mask(Mask const &mask) { + mask_ = mask; + } +}; + /////////////////////////////////////////////////////////////////////////////// } // namespace threadblock diff --git a/include/cutlass/epilogue/threadblock/predicated_tile_iterator_params.h b/include/cutlass/epilogue/threadblock/predicated_tile_iterator_params.h new file mode 100644 index 000000000..a08e1e061 --- /dev/null +++ b/include/cutlass/epilogue/threadblock/predicated_tile_iterator_params.h @@ -0,0 +1,227 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief +*/ + +#pragma once + +#include "cutlass/cutlass.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace epilogue { +namespace threadblock { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +struct OutputTileShapeDesc { + + int column; + int row; + int group; + int cluster; + int tile; + + // + // Methods + // + + /// Default ctor + CUTLASS_HOST_DEVICE + OutputTileShapeDesc(): column(0), row(0), group(0), cluster(0), tile(0) { } + + /// Ctor + CUTLASS_HOST_DEVICE + OutputTileShapeDesc( + int column_, + int row_, + int group_, + int cluster_, + int tile_ + ): + column(column_), + row(row_), + group(group_), + cluster(cluster_), + tile(tile_) { } + + /// Total number of points in the 5D space + CUTLASS_HOST_DEVICE + int count() const { + return column * row * group * cluster * tile; + } +}; + +/// Helper template to construct an OutputTileShapeDesc from a OutputTileShape template. +template +CUTLASS_HOST_DEVICE +OutputTileShapeDesc make_OutputTileShapeDesc() { + return OutputTileShapeDesc( + Shape::kColumn, + Shape::kRow, + Shape::kGroup, + Shape::kCluster, + Shape::kTile + ); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Thread map description +struct OutputTileThreadMapDesc { + + int threads; + int elements_per_access; + OutputTileShapeDesc shape; + OutputTileShapeDesc iterations; + OutputTileShapeDesc delta; + OutputTileShapeDesc count; + + // + // Methods + // + + CUTLASS_HOST_DEVICE + OutputTileThreadMapDesc() { } + + CUTLASS_HOST_DEVICE + OutputTileThreadMapDesc( + int threads_, + int elements_per_access_, + OutputTileShapeDesc shape_, + OutputTileShapeDesc iterations_, + OutputTileShapeDesc delta_, + OutputTileShapeDesc count_ + ): + threads(threads_), + elements_per_access(elements_per_access_), + shape(shape_), + iterations(iterations_), + delta(delta_), + count(count_) { } +}; + +/// Helper template to construct an OutputTileShapeDesc from a OutputTileThreadMap template. +template +CUTLASS_HOST_DEVICE +OutputTileThreadMapDesc make_OutputTileThreadMapDesc() { + return OutputTileThreadMapDesc( + ThreadMap::kThreads, + ThreadMap::kElementsPerAccess, + make_OutputTileShapeDesc(), + make_OutputTileShapeDesc(), + make_OutputTileShapeDesc(), + make_OutputTileShapeDesc() + ); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +// +// Parameters struct +// + +struct PredicatedTileIteratorParams { + + using Index = int32_t; + using LongIndex = int64_t; + + // + // Data members + // + + LongIndex stride; ///< stride in bytes between rows + + LongIndex increment_row; ///< increment quantity (in bytes) to advance when moving between rows + LongIndex increment_group; ///< increment quantity (in bytes) to advance when moving to the next group + LongIndex increment_cluster; ///< increment quantity (in bytes) to advance when moving to the next cluster + + LongIndex advance_row; ///< amount to add to move to the next 'row' position + LongIndex advance_group; ///< amount to add to move to the next 'group' position + LongIndex advance_cluster; ///< amount to add to move to the next 'cluster' position + LongIndex advance_tile; ///< amount to add to move to the next 'tile' + + // + // Methods + // + + CUTLASS_HOST_DEVICE + Status initialize(Index stride_, OutputTileThreadMapDesc thread_map) { + + stride = LongIndex(stride_); + + increment_row = stride * thread_map.delta.row; + + increment_group = stride * thread_map.delta.group + - stride * thread_map.delta.row * (thread_map.iterations.row - 1); + + increment_cluster = stride * thread_map.delta.cluster + - stride * thread_map.delta.group * (thread_map.iterations.group - 1) + - stride * thread_map.delta.row * (thread_map.iterations.row - 1); + + advance_row = stride * thread_map.shape.row; + + advance_group = + stride * + (thread_map.shape.group - 1) * thread_map.shape.row * thread_map.count.row; + + advance_cluster = + stride * + thread_map.count.group * + thread_map.shape.group * + thread_map.count.row * + thread_map.shape.row; + + advance_tile = + stride * + thread_map.shape.group * + thread_map.shape.row * + thread_map.shape.cluster * + thread_map.shape.tile; + + return Status::kSuccess; + } + + CUTLASS_HOST_DEVICE + PredicatedTileIteratorParams() { + initialize(0, OutputTileThreadMapDesc()); + } + + CUTLASS_HOST_DEVICE + PredicatedTileIteratorParams(Index stride, OutputTileThreadMapDesc thread_map) { + + initialize(stride, thread_map); + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace threadblock +} // namespace epilogue +} // namespace cutlass + +//////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/epilogue/warp/fragment_iterator_wmma_tensor_op.h b/include/cutlass/epilogue/warp/fragment_iterator_wmma_tensor_op.h index 79106b111..b2a0612ac 100644 --- a/include/cutlass/epilogue/warp/fragment_iterator_wmma_tensor_op.h +++ b/include/cutlass/epilogue/warp/fragment_iterator_wmma_tensor_op.h @@ -37,7 +37,7 @@ #pragma once -#if !defined(__clang__) +#if !(defined(__clang__) && defined(__CUDA__)) #include "cutlass/wmma_array.h" #include "cutlass/layout/matrix.h" @@ -152,5 +152,7 @@ public: //////////////////////////////////////////////////////////////////////////////// +#else +#error (defined(__clang__) && defined(__CUDA__)) #endif // !defined(__clang__) diff --git a/include/cutlass/epilogue/warp/tile_iterator_wmma_tensor_op.h b/include/cutlass/epilogue/warp/tile_iterator_wmma_tensor_op.h index 6017b5c7e..c8eab0ceb 100644 --- a/include/cutlass/epilogue/warp/tile_iterator_wmma_tensor_op.h +++ b/include/cutlass/epilogue/warp/tile_iterator_wmma_tensor_op.h @@ -28,7 +28,7 @@ #pragma once -#if !defined(__clang__) +#if !(defined(__clang__) && defined(__CUDA__)) #include "cutlass/cutlass.h" #include "cutlass/wmma_array.h" diff --git a/include/cutlass/fast_math.h b/include/cutlass/fast_math.h index 978e614b1..4d9503e5f 100644 --- a/include/cutlass/fast_math.h +++ b/include/cutlass/fast_math.h @@ -200,7 +200,7 @@ void fast_divmod(int& quo, int& rem, int src, int div, unsigned int mul, unsigne // Use IMUL.HI if div != 1, else simply copy the source. quo = (div != 1) ? __umulhi(src, mul) >> shr : src; #else - quo = int((div != 1) ? int(src * mul) >> shr : src); + quo = int((div != 1) ? int(((int64_t)src * mul) >> 32) >> shr : src); #endif // The remainder. @@ -215,7 +215,7 @@ void fast_divmod(int& quo, int64_t& rem, int64_t src, int div, unsigned int mul, // Use IMUL.HI if div != 1, else simply copy the source. quo = (div != 1) ? __umulhi(src, mul) >> shr : src; #else - quo = int((div != 1) ? (src * mul) >> shr : src); + quo = int((div != 1) ? ((src * mul) >> 32) >> shr : src); #endif // The remainder. rem = src - (quo * div); diff --git a/include/cutlass/functional.h b/include/cutlass/functional.h index 90cf39494..d20c45df2 100644 --- a/include/cutlass/functional.h +++ b/include/cutlass/functional.h @@ -161,6 +161,42 @@ struct negate { } }; +/// Greater equal +template +struct greater_equal { + CUTLASS_HOST_DEVICE + bool operator()(T const &lhs, T const &rhs) const { + return (lhs >= rhs); + } +}; + +/// Greater +template +struct greater { + CUTLASS_HOST_DEVICE + bool operator()(T const &lhs, T const &rhs) const { + return (lhs > rhs); + } +}; + +/// Less equal +template +struct less_equal { + CUTLASS_HOST_DEVICE + bool operator()(T const &lhs, T const &rhs) const { + return (lhs <= rhs); + } +}; + +/// Less +template +struct less { + CUTLASS_HOST_DEVICE + bool operator()(T const &lhs, T const &rhs) const { + return (lhs < rhs); + } +}; + /// Fused multiply-add template struct multiply_add { @@ -189,6 +225,40 @@ struct xor_add { } }; +template +struct conjugate { + CUTLASS_HOST_DEVICE + T operator()(T const &a) const { + return a; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct conjugate> { + CUTLASS_HOST_DEVICE + complex operator()(complex const &a) const { + return conj(a); + } +}; + +template +struct conjugate > { + CUTLASS_HOST_DEVICE + Array operator()(Array const &a) const { + + conjugate conj_op; + + Array ca; + CUTLASS_PRAGMA_UNROLL + for (int i = 0; i < N; ++i) { + ca[i] = conj_op(a[i]); + } + return ca; + } +}; + ///////////////////////////////////////////////////////////////////////////////////////////////// // // Partial specialization for complex to target four scalar fused multiply-adds. @@ -1499,6 +1569,86 @@ struct multiply_add, Array, Array +CUTLASS_HOST_DEVICE +Array operator+(Array const &lhs, Array const &rhs) { + plus> op; + return op(lhs, rhs); +} + +template +CUTLASS_HOST_DEVICE +Array operator-(Array const &lhs, Array const &rhs) { + minus> op; + return op(lhs, rhs); +} + +template +CUTLASS_HOST_DEVICE +Array operator-(Array const &lhs) { + negate> op; + return op(lhs); +} + +template +CUTLASS_HOST_DEVICE +Array operator*(Array const &lhs, Array const &rhs) { + multiplies> op; + return op(lhs, rhs); +} + +template +CUTLASS_HOST_DEVICE +Array operator*(T lhs, Array const &rhs) { + multiplies> op; + return op(lhs, rhs); +} + +template +CUTLASS_HOST_DEVICE +Array operator*(Array const &lhs, T rhs) { + multiplies> op; + return op(lhs, rhs); +} + +template +CUTLASS_HOST_DEVICE +Array operator/(Array const &lhs, Array const &rhs) { + divides> op; + return op(lhs, rhs); +} + +template +CUTLASS_HOST_DEVICE +Array fma(Array const &a, Array const &b, Array const &c) { + multiply_add> op; + return op(a, b, c); +} + +template +CUTLASS_HOST_DEVICE +Array fma(T a, Array const &b, Array const &c) { + multiply_add> op; + return op(a, b, c); +} + +template +CUTLASS_HOST_DEVICE +Array fma(Array const &a, T b, Array const &c) { + multiply_add> op; + return op(a, b, c); +} + +template +CUTLASS_HOST_DEVICE +Array fma(Array const &a, Array const &b, T c) { + multiply_add> op; + return op(a, b, c); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + } // namespace cutlass ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/gemm/device/gemm_sparse.h b/include/cutlass/gemm/device/gemm_sparse.h index df2a141cd..bfd5606e1 100644 --- a/include/cutlass/gemm/device/gemm_sparse.h +++ b/include/cutlass/gemm/device/gemm_sparse.h @@ -429,6 +429,25 @@ public: args.epilogue, static_cast(workspace) }; + + int smem_size = int(sizeof(typename GemmKernel::SharedStorage)); + if (smem_size >= (48 << 10)) { + cudaError_t result = cudaFuncSetAttribute(Kernel, + cudaFuncAttributeMaxDynamicSharedMemorySize, + smem_size); + + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + result = cudaFuncSetAttribute( + Kernel, + cudaFuncAttributePreferredSharedMemoryCarveout, 100); + + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + } return Status::kSuccess; } @@ -461,30 +480,11 @@ public: dim3 grid = threadblock_swizzle.get_grid_shape(params_.grid_tiled_shape); dim3 block(GemmKernel::kThreadCount, 1, 1); - cudaError_t result; - int smem_size = int(sizeof(typename GemmKernel::SharedStorage)); - if (smem_size >= (48 << 10)) { - result = cudaFuncSetAttribute(Kernel, - cudaFuncAttributeMaxDynamicSharedMemorySize, - smem_size); - - if (result != cudaSuccess) { - return Status::kErrorInternal; - } - - result = cudaFuncSetAttribute( - Kernel, - cudaFuncAttributePreferredSharedMemoryCarveout, 100); - - if (result != cudaSuccess) { - return Status::kErrorInternal; - } - } cutlass::Kernel<<>>(params_); - result = cudaGetLastError(); + cudaError_t result = cudaGetLastError(); return result == cudaSuccess ? Status::kSuccess : Status::kErrorInternal; } diff --git a/include/cutlass/gemm/device/gemm_universal_adapter.h b/include/cutlass/gemm/device/gemm_universal_adapter.h index 12a8a6d7f..a66948354 100644 --- a/include/cutlass/gemm/device/gemm_universal_adapter.h +++ b/include/cutlass/gemm/device/gemm_universal_adapter.h @@ -117,9 +117,16 @@ public: using ThreadblockShape = typename GemmKernel::Mma::Shape; using WarpShape = typename GemmKernel::WarpShape; using InstructionShape = typename GemmKernel::InstructionShape; - - using OperatorClass = typename GemmKernel::OperatorClass; - using ArchTag = typename GemmKernel::ArchTag; + + // warp-level, arch-level (instruction), math operator + using WarpMmaOperator = typename GemmKernel::Mma::Policy::Operator; + using ArchMmaOperator = typename WarpMmaOperator::ArchMmaOperator; + using MathOperator = typename ArchMmaOperator::Operator; + + // Operator class and arch tag extract bottom-up + // set it for top-level gemm device-level template + using OperatorClass = typename WarpMmaOperator::OperatorClass; + using ArchTag = typename WarpMmaOperator::ArchTag; // Type, layout, and complex transform deliberately exchanged with B using MapArguments = detail::MapArguments< diff --git a/include/cutlass/gemm/device/gemm_universal_base.h b/include/cutlass/gemm/device/gemm_universal_base.h index fc52a08d0..9ffc6b041 100644 --- a/include/cutlass/gemm/device/gemm_universal_base.h +++ b/include/cutlass/gemm/device/gemm_universal_base.h @@ -311,6 +311,27 @@ public: gemm_k_size, static_cast(workspace) ); + + // Specify shared memory capacity for kernel. + int smem_size = int(sizeof(typename GemmKernel::SharedStorage)); + + if (smem_size >= (48 << 10)) { + cudaError_t result = cudaFuncSetAttribute(Kernel, + cudaFuncAttributeMaxDynamicSharedMemorySize, + smem_size); + + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + result = cudaFuncSetAttribute( + Kernel, + cudaFuncAttributePreferredSharedMemoryCarveout, 100); + + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + } return Status::kSuccess; } @@ -335,38 +356,31 @@ public: Status run(cudaStream_t stream = nullptr) { CUTLASS_TRACE_HOST("GemmUniversalBase::run()"); + // + // Configure grid and block dimensions + // + ThreadblockSwizzle threadblock_swizzle; dim3 grid = threadblock_swizzle.get_grid_shape(params_.grid_tiled_shape); dim3 block(GemmKernel::kThreadCount, 1, 1); - cudaError_t result; - int smem_size = int(sizeof(typename GemmKernel::SharedStorage)); - if (smem_size >= (48 << 10)) { - result = cudaFuncSetAttribute(Kernel, - cudaFuncAttributeMaxDynamicSharedMemorySize, - smem_size); - if (result != cudaSuccess) { - return Status::kErrorInternal; - } - - result = cudaFuncSetAttribute( - Kernel, - cudaFuncAttributePreferredSharedMemoryCarveout, 100); - - if (result != cudaSuccess) { - return Status::kErrorInternal; - } - } + // + // Launch kernel + // CUTLASS_TRACE_HOST(" grid: (" << grid << "), block: (" << block << "), SMEM: " << smem_size << " bytes"); + // Launch cutlass::Kernel<<>>(params_); - result = cudaGetLastError(); + // + // Query for errors + // + cudaError_t result = cudaGetLastError(); if (result != cudaSuccess) { CUTLASS_TRACE_HOST(" grid launch failed with error " << cudaGetErrorString(result)); diff --git a/include/cutlass/gemm/kernel/default_gemm_complex.h b/include/cutlass/gemm/kernel/default_gemm_complex.h index 15b1430c7..cff06e69d 100644 --- a/include/cutlass/gemm/kernel/default_gemm_complex.h +++ b/include/cutlass/gemm/kernel/default_gemm_complex.h @@ -49,6 +49,7 @@ #include "cutlass/gemm/kernel/gemm_pipelined.h" #include "cutlass/gemm/threadblock/default_mma_core_sm75.h" #include "cutlass/gemm/threadblock/default_mma_core_sm70.h" +#include "cutlass/gemm/threadblock/default_mma_core_simt.h" #include "cutlass/gemm/threadblock/default_multistage_mma_complex_core_sm80.h" #include "cutlass/gemm/threadblock/default_mma.h" #include "cutlass/gemm/threadblock/default_multistage_mma_complex.h" @@ -112,6 +113,101 @@ struct DefaultGemmComplex; //////////////////////////////////////////////////////////////////////////////// +/// Partial specialization for Ampere Architecture +template < + /// Element type for A matrix operand + typename ElementA, + /// Layout type for A matrix operand + typename LayoutA, + /// Element type for B matrix operand + typename ElementB, + /// Layout type for B matrix operand + typename LayoutB, + /// Element type for C and D matrix operands + typename ElementC, + /// Element type for internal accumulation + typename ElementAccumulator, + /// Threadblock-level tile size (concept: GemmShape) + typename ThreadblockShape, + /// Warp-level tile size (concept: GemmShape) + typename WarpShape, + /// Warp-level tile size (concept: GemmShape) + typename InstructionShape, + /// Epilogue output operator + typename EpilogueOutputOp, + /// Threadblock-level swizzling operator + typename ThreadblockSwizzle, + /// Number of stages used in the pipelined mainloop + int Stages, + /// Complex elementwise transformation on A operand + ComplexTransform TransformA, + /// Complex elementwise transformation on B operand + ComplexTransform TransformB, + /// Multiply-add operator + // (arch::OpMultiplyAddComplex, arch::OpMultiplyGaussianComplex) + typename Operator, + /// If true, kernel is configured to support serial reduction in the epilogue + bool SplitKSerial + > +struct DefaultGemmComplex< + ElementA, LayoutA, ElementB, LayoutB, ElementC, + layout::RowMajor, ElementAccumulator, arch::OpClassSimt, + arch::Sm50, ThreadblockShape, WarpShape, InstructionShape, + EpilogueOutputOp, ThreadblockSwizzle, Stages, TransformA, TransformB, Operator, SplitKSerial> { + + /// Define the threadblock-scoped matrix multiply-accumulate + using MmaCore = typename cutlass::gemm::threadblock::DefaultMmaCore< + ThreadblockShape, + WarpShape, + InstructionShape, + ElementA, LayoutA, + ElementB, LayoutB, + ElementAccumulator, layout::RowMajor, + arch::OpClassSimt, + Stages, + Operator, + false, + cutlass::arch::CacheOperation::Global, + cutlass::arch::CacheOperation::Global, + TransformA, + TransformB + >; + + // Define iterators over tiles from the A operand + using IteratorA = + cutlass::transform::threadblock::PredicatedTileIterator< + cutlass::MatrixShape, + ElementA, LayoutA, 1, + typename MmaCore::IteratorThreadMapA>; + + // Define iterators over tiles from the B operand + using IteratorB = + cutlass::transform::threadblock::PredicatedTileIterator< + cutlass::MatrixShape, + ElementB, LayoutB, 0, + typename MmaCore::IteratorThreadMapB>; + + // Define the threadblock-scoped pipelined matrix multiply + using Mma = cutlass::gemm::threadblock::MmaPipelined< + typename MmaCore::Shape, IteratorA, typename MmaCore::SmemIteratorA, + IteratorB, typename MmaCore::SmemIteratorB, ElementAccumulator, + layout::RowMajor, typename MmaCore::MmaPolicy>; + + /// Define the epilogue + using Epilogue = + typename cutlass::epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + typename Mma::Operator, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + /// Define the kernel-level GEMM operator. + using GemmKernel = kernel::Gemm; +}; + +//////////////////////////////////////////////////////////////////////////////// + /// Partial specialization for Ampere Architecture template < /// Element type for A matrix operand @@ -170,6 +266,70 @@ struct DefaultGemmComplex< using GemmKernel = kernel::Gemm; }; + +//////////////////////////////////////////////////////////////////////////////// + +/// Partial specialization for Ampere Architecture +template < + /// Element type for A matrix operand + typename ElementA, + /// Layout type for A matrix operand + typename LayoutA, + /// Element type for B matrix operand + typename ElementB, + /// Layout type for B matrix operand + typename LayoutB, + /// Element type for C and D matrix operands + typename ElementC, + /// Element type for internal accumulation + typename ElementAccumulator, + /// Threadblock-level tile size (concept: GemmShape) + typename ThreadblockShape, + /// Warp-level tile size (concept: GemmShape) + typename WarpShape, + /// Warp-level tile size (concept: GemmShape) + typename InstructionShape, + /// Epilogue output operator + typename EpilogueOutputOp, + /// Threadblock-level swizzling operator + typename ThreadblockSwizzle, + /// Number of stages used in the pipelined mainloop + int Stages, + /// Complex elementwise transformation on A operand + ComplexTransform TransformA, + /// Complex elementwise transformation on B operand + ComplexTransform TransformB, + /// Multiply-add operator + // (arch::OpMultiplyAddComplex, arch::OpMultiplyGaussianComplex) + typename Operator, + /// If true, kernel is configured to support serial reduction in the epilogue + bool SplitKSerial + > +struct DefaultGemmComplex< + ElementA, LayoutA, ElementB, LayoutB, ElementC, + layout::RowMajor, ElementAccumulator, arch::OpClassSimt, + arch::Sm80, ThreadblockShape, WarpShape, InstructionShape, + EpilogueOutputOp, ThreadblockSwizzle, Stages, TransformA, TransformB, Operator, SplitKSerial> { + + /// Define the threadblock-scoped matrix multiply-accumulate + using Mma = typename cutlass::gemm::threadblock::DefaultMultistageMmaComplex< + ElementA, LayoutA, ElementB, LayoutB, ElementAccumulator, + layout::RowMajor, arch::OpClassSimt, arch::Sm80, ThreadblockShape, + WarpShape, InstructionShape, Stages, TransformA, TransformB, Operator>::ThreadblockMma; + + /// Define the epilogue + using Epilogue = + typename cutlass::epilogue::threadblock::DefaultEpilogueSimt< + ThreadblockShape, + typename Mma::Operator, + EpilogueOutputOp, + EpilogueOutputOp::kCount + >::Epilogue; + + /// Define the kernel-level GEMM operator. + using GemmKernel = kernel::Gemm; +}; + //////////////////////////////////////////////////////////////////////////////// } // namespace kernel diff --git a/include/cutlass/gemm/kernel/gemm.h b/include/cutlass/gemm/kernel/gemm.h index fc2daa975..ce61137f3 100644 --- a/include/cutlass/gemm/kernel/gemm.h +++ b/include/cutlass/gemm/kernel/gemm.h @@ -138,8 +138,20 @@ struct Gemm { typename Epilogue::OutputTileIterator::TensorRef ref_C, typename Epilogue::OutputTileIterator::TensorRef ref_D) { - static int const kAlignmentA = Mma::IteratorA::AccessType::kElements; - static int const kAlignmentB = Mma::IteratorB::AccessType::kElements; + static int const kAlignmentA = (platform::is_same>::value) + ? 32 + : (platform::is_same>::value) + ? 64 + : Mma::IteratorA::AccessType::kElements; + static int const kAlignmentB = (platform::is_same>::value) + ? 32 + : (platform::is_same>::value) + ? 64 + : Mma::IteratorB::AccessType::kElements; static int const kAlignmentC = Epilogue::OutputTileIterator::kElementsPerAccess; if (!TensorRef_aligned(ref_A, kAlignmentA)) { @@ -274,7 +286,7 @@ struct Gemm { semaphore.fetch(); // Indicate which position in a serial reduction the output operator is currently updating - output_op.set_k_partition(threadblock_tile_offset.k()); + output_op.set_k_partition(threadblock_tile_offset.k(), params.grid_tiled_shape.k()); } // Tile iterator loading from source tensor. diff --git a/include/cutlass/gemm/kernel/gemm_planar_complex.h b/include/cutlass/gemm/kernel/gemm_planar_complex.h index aede20dae..b9626145f 100644 --- a/include/cutlass/gemm/kernel/gemm_planar_complex.h +++ b/include/cutlass/gemm/kernel/gemm_planar_complex.h @@ -582,7 +582,7 @@ public: semaphore.fetch(); // Indicate which position in a serial reduction the output operator is currently updating - output_op.set_k_partition(threadblock_tile_offset.k()); + output_op.set_k_partition(threadblock_tile_offset.k(), params.grid_tiled_shape.k()); } } else if (params.mode == GemmUniversalMode::kGemmSplitKParallel) { diff --git a/include/cutlass/gemm/kernel/gemm_universal.h b/include/cutlass/gemm/kernel/gemm_universal.h index 99ece2674..bba621716 100644 --- a/include/cutlass/gemm/kernel/gemm_universal.h +++ b/include/cutlass/gemm/kernel/gemm_universal.h @@ -302,8 +302,20 @@ public: CUTLASS_TRACE_HOST("GemmUniversal::can_implement()"); - static int const kAlignmentA = Mma::IteratorA::AccessType::kElements; - static int const kAlignmentB = Mma::IteratorB::AccessType::kElements; + static int const kAlignmentA = (platform::is_same>::value) + ? 32 + : (platform::is_same>::value) + ? 64 + : Mma::IteratorA::AccessType::kElements; + static int const kAlignmentB = (platform::is_same>::value) + ? 32 + : (platform::is_same>::value) + ? 64 + : Mma::IteratorB::AccessType::kElements; static int const kAlignmentC = Epilogue::OutputTileIterator::kElementsPerAccess; if ((problem_size.m() % kAlignmentA) || (problem_size.k() % kAlignmentA) || @@ -468,7 +480,7 @@ public: semaphore.fetch(); // Indicate which position in a serial reduction the output operator is currently updating - output_op.set_k_partition(threadblock_tile_offset.k()); + output_op.set_k_partition(threadblock_tile_offset.k(), params.grid_tiled_shape.k()); } } else if (params.mode == GemmUniversalMode::kGemmSplitKParallel) { diff --git a/include/cutlass/gemm/kernel/sparse_gemm.h b/include/cutlass/gemm/kernel/sparse_gemm.h index 7db469e53..730745fdc 100644 --- a/include/cutlass/gemm/kernel/sparse_gemm.h +++ b/include/cutlass/gemm/kernel/sparse_gemm.h @@ -319,7 +319,7 @@ struct SparseGemm { semaphore.fetch(); // Indicate which position in a serial reduction the output operator is currently updating - output_op.set_k_partition(threadblock_tile_offset.k()); + output_op.set_k_partition(threadblock_tile_offset.k(), params.grid_tiled_shape.k()); } // Tile iterator loading from source tensor. diff --git a/include/cutlass/gemm/thread/mma_sm60.h b/include/cutlass/gemm/thread/mma_sm60.h index 486497cb7..07e2d5562 100644 --- a/include/cutlass/gemm/thread/mma_sm60.h +++ b/include/cutlass/gemm/thread/mma_sm60.h @@ -93,6 +93,9 @@ struct Mma_HFMA2 < /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // @@ -179,6 +182,9 @@ struct Mma_HFMA2< /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // @@ -270,6 +276,9 @@ struct Mma_HFMA2 < /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // @@ -356,6 +365,8 @@ struct Mma_HFMA2< /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; // // Methods // @@ -443,6 +454,9 @@ struct Mma_HFMA2 < /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // @@ -533,6 +547,9 @@ struct Mma_HFMA2 < /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // @@ -623,6 +640,9 @@ struct Mma_HFMA2 < /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // @@ -714,6 +734,9 @@ struct Mma_HFMA2< /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // @@ -800,6 +823,9 @@ struct Mma_HFMA2< /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // @@ -879,6 +905,9 @@ struct Mma_HFMA2< /// C operand storage using FragmentC = Array; + /// Underlying mathematical operator + using Operator = arch::OpMultiplyAdd; + // // Methods // diff --git a/include/cutlass/gemm/threadblock/default_mma_core_simt.h b/include/cutlass/gemm/threadblock/default_mma_core_simt.h index be5014937..ba3a16165 100644 --- a/include/cutlass/gemm/threadblock/default_mma_core_simt.h +++ b/include/cutlass/gemm/threadblock/default_mma_core_simt.h @@ -389,7 +389,7 @@ struct DefaultMmaCore, ElementA_, /// Policy used to define MmaPipelined using MmaPolicy = MmaPolicy< MmaWarpSimt, - MatrixShape, // skew for A matrix to avoid SMEM bank conflicts + MatrixShape, // skew for A matrix to avoid SMEM bank conflicts MatrixShape<0, kPaddingN>, // skew for B matrix to avoid SMEM bank conflicts WarpCount::kK >; diff --git a/include/cutlass/gemm/threadblock/default_multistage_mma_complex.h b/include/cutlass/gemm/threadblock/default_multistage_mma_complex.h index 7f3d534a1..36c5c54ee 100644 --- a/include/cutlass/gemm/threadblock/default_multistage_mma_complex.h +++ b/include/cutlass/gemm/threadblock/default_multistage_mma_complex.h @@ -34,6 +34,7 @@ #include "cutlass/gemm/threadblock/default_mma_core_sm80.h" #include "cutlass/numeric_types.h" #include "cutlass/transform/threadblock/predicated_tile_iterator.h" +#include "cutlass/gemm/threadblock/default_multistage_mma_complex_core_sm80.h" //////////////////////////////////////////////////////////////////////////////// diff --git a/include/cutlass/gemm/threadblock/default_multistage_mma_complex_core_sm80.h b/include/cutlass/gemm/threadblock/default_multistage_mma_complex_core_sm80.h index 230e8d768..697d22bf6 100644 --- a/include/cutlass/gemm/threadblock/default_multistage_mma_complex_core_sm80.h +++ b/include/cutlass/gemm/threadblock/default_multistage_mma_complex_core_sm80.h @@ -1105,6 +1105,676 @@ struct DefaultMultistageMmaComplexCore< //////////////////////////////////////////////////////////////////////////////// +/// Partial specialization for complex double-precision +/// +/// A: column-major +/// B: row-major +/// Operator: arch::OpMultiplyAddComplex or arch::OpMultiplyGaussianComplex +/// +/// This uses the default warp-level operator given tile sizes +template < + /// Shape of threadblock-scoped matrix multiply operator (concept: + /// GemmShape) + typename Shape_, + /// Shape of warp-level matrix multiply operator (concept: GemmShape) + typename WarpShape_, + typename RealA, + typename RealB, + typename RealC, + /// Layout of accumulator + typename LayoutC_, + /// Number of stages + int Stages, + /// Complex transformation on operand A + ComplexTransform TransformA, + /// Complex transformation on operand B + ComplexTransform TransformB, + /// Multiply-add operator (arch::OpMultiplyAddComplex, arch::OpMultiplyGaussianComplex) + typename Operator_, + /// Cache operation of operand A + cutlass::arch::CacheOperation::Kind CacheOpA, + /// Cache operation of operand B + cutlass::arch::CacheOperation::Kind CacheOpB> +struct DefaultMultistageMmaComplexCore< + Shape_, WarpShape_, GemmShape<1, 1, 1>, + complex, layout::ColumnMajor, + complex, layout::ColumnMajor, + complex, LayoutC_, + arch::OpClassSimt, + Stages, + TransformA, TransformB, + Operator_, + CacheOpA, CacheOpB> { + + using Shape = Shape_; + using WarpShape = WarpShape_; + using InstructionShape = GemmShape<1, 1, 1>; + using ElementA = complex; + using LayoutA = layout::ColumnMajor; + using ElementB = complex; + using LayoutB = layout::ColumnMajor; + using ElementC = complex; + using LayoutC = LayoutC_; + static int const kStages = Stages; + static ComplexTransform const kTransformA = TransformA; + static ComplexTransform const kTransformB = TransformB; + using Operator = Operator_; + static cutlass::arch::CacheOperation::Kind const kCacheOpA = cutlass::arch::CacheOperation::Always; + static cutlass::arch::CacheOperation::Kind const kCacheOpB = cutlass::arch::CacheOperation::Always; + + /// Number of warps present + using WarpCount = GemmShape; + + // Divisility requirements + static_assert( + !(Shape::kM % WarpShape::kM) && !(Shape::kN % WarpShape::kN), + "Threadblock-scoped GEMM should be divisible by warp-scoped GEMM size."); + + static_assert(WarpCount::kCount > 1, + "This specialization requires at least two warps."); + + /// Number of threads per warp + static int const kWarpSize = warp::WarpSize::value; + + /// Number of threads total + static int const kThreads = WarpCount::kCount * kWarpSize; + + /// Size of access + static int const kAccessSizeInBits = sizeof_bits::value; + + /// No vectorized accesses + static int const kElementsPerAccess = 1; + + // + // Shared memory layouts + // + + using SmemLayoutA = layout::ColumnMajor; + + using SmemLayoutB = layout::RowMajor; + + // + // Iterators to write to shared memory + // + + /// ThreadMap of iterator A + using IteratorThreadMapA = transform::PitchLinearStripminedThreadMap< + layout::PitchLinearShape, + kThreads, + kElementsPerAccess + >; + + /// Shared memory iterator to A operand + using SmemIteratorA = transform::threadblock::RegularTileAccessIterator< + MatrixShape, ElementA, SmemLayoutA, 0, + IteratorThreadMapA>; + + /// Policy of iterator B + using IteratorThreadMapB = transform::PitchLinearStripminedThreadMap< + layout::PitchLinearShape, + kThreads, + kElementsPerAccess + >; + + /// Transpose the ThreadMap of iterator B + using SmemThreadMapB = transform::TransposePitchLinearThreadMapSimt; + + /// Shared memory iterator to B operand + using SmemIteratorB = transform::threadblock::RegularTileAccessIterator< + MatrixShape, ElementB, SmemLayoutB, 1, + SmemThreadMapB>; + + // + // Warp-level matrix multiply operator + // + + // Define the warp-level op + static const int WarpNumThreadsM = 4; // TODO need to extract these from template data + static const int WarpNumThreadsN = 8; + static_assert(!(WarpShape::kM % WarpNumThreadsM) && !(WarpShape::kN % WarpNumThreadsN), + "WarpShape must be divisible by ThreadTile shape."); + static const int ThreadTileM = WarpShape::kM / WarpNumThreadsM; + static const int ThreadTileN = WarpShape::kN / WarpNumThreadsN; + static const int LaneLayout = ThreadTileM > 4 && ThreadTileN > 4 ? 2 : 1; + static const int numElementsA = 128 / sizeof_bits::value; + static const int numElementsB = 128 / sizeof_bits::value; + static const int LaneM = cutlass::const_min(numElementsA, ThreadTileM); + static const int LaneN = cutlass::const_min(numElementsB, ThreadTileN); + // these should have max of thread tile also + using LaneMmaShape = cutlass::gemm::GemmShape< + LaneM, + LaneN, + 1>; + using Policy = cutlass::gemm::warp::MmaSimtPolicy< + cutlass::MatrixShape, // WarpShape + cutlass::layout::RowMajorInterleaved, // LaneLayout + LaneMmaShape + >; + + using MmaWarpSimt = cutlass::gemm::warp::MmaSimt< + WarpShape, /// Size of the Gemm problem - concept: gemm::GemmShape<> 128, 128, 8 + ElementA, /// Data type of A elements + SmemLayoutA, /// Layout of A matrix (concept: MatrixLayout) + ElementB, /// Data type of B elements + SmemLayoutB, /// Layout of B matrix (concept: MatrixLayout) + ElementC, /// Element type of C matrix + LayoutC, /// Layout of C matrix (concept: MatrixLayout) + Policy /// Policy describing warp-level MmaTensorOp (concept: MmaTensorOp policy) + >; /// Used for partial specialization + + /// Policy used to define MmaPipelined + using MmaPolicy = MmaPolicy< + MmaWarpSimt, + MatrixShape<0, 0>, + MatrixShape<0, Shape::kK / 32>, + WarpCount::kK>; +}; + +/// Partial specialization for complex double-precision +/// +/// A: column-major +/// B: row-major +/// Operator: arch::OpMultiplyAddComplex or arch::OpMultiplyGaussianComplex +/// +/// This uses the default warp-level operator given tile sizes +template < + /// Shape of threadblock-scoped matrix multiply operator (concept: + /// GemmShape) + typename Shape_, + /// Shape of warp-level matrix multiply operator (concept: GemmShape) + typename WarpShape_, + typename RealA, + typename RealB, + typename RealC, + /// Layout of accumulator + typename LayoutC_, + /// Number of stages + int Stages, + /// Complex transformation on operand A + ComplexTransform TransformA, + /// Complex transformation on operand B + ComplexTransform TransformB, + /// Multiply-add operator (arch::OpMultiplyAddComplex, arch::OpMultiplyGaussianComplex) + typename Operator_, + /// Cache operation of operand A + cutlass::arch::CacheOperation::Kind CacheOpA, + /// Cache operation of operand B + cutlass::arch::CacheOperation::Kind CacheOpB> +struct DefaultMultistageMmaComplexCore< + Shape_, WarpShape_, GemmShape<1, 1, 1>, + complex, layout::ColumnMajor, + complex, layout::RowMajor, + complex, LayoutC_, + arch::OpClassSimt, + Stages, + TransformA, TransformB, + Operator_, + CacheOpA, CacheOpB> { + + using Shape = Shape_; + using WarpShape = WarpShape_; + using InstructionShape = GemmShape<1, 1, 1>; + using ElementA = complex; + using LayoutA = layout::ColumnMajor; + using ElementB = complex; + using LayoutB = layout::RowMajor; + using ElementC = complex; + using LayoutC = LayoutC_; + static int const kStages = Stages; + static ComplexTransform const kTransformA = TransformA; + static ComplexTransform const kTransformB = TransformB; + using Operator = Operator_; + static cutlass::arch::CacheOperation::Kind const kCacheOpA = cutlass::arch::CacheOperation::Always; + static cutlass::arch::CacheOperation::Kind const kCacheOpB = cutlass::arch::CacheOperation::Always; + + /// Number of warps present + using WarpCount = GemmShape; + + // Divisility requirements + static_assert( + !(Shape::kM % WarpShape::kM) && !(Shape::kN % WarpShape::kN), + "Threadblock-scoped GEMM should be divisible by warp-scoped GEMM size."); + + static_assert(WarpCount::kCount > 1, + "This specialization requires at least two warps."); + + /// Number of threads per warp + static int const kWarpSize = warp::WarpSize::value; + + /// Number of threads total + static int const kThreads = WarpCount::kCount * kWarpSize; + + /// Size of access + static int const kAccessSizeInBits = sizeof_bits::value; + + /// No vectorized accesses + static int const kElementsPerAccess = 1; + + // + // Shared memory layouts + // + + using SmemLayoutA = layout::ColumnMajor; + + using SmemLayoutB = layout::RowMajor; + + // + // Iterators to write to shared memory + // + + /// ThreadMap of iterator A + using IteratorThreadMapA = transform::PitchLinearStripminedThreadMap< + layout::PitchLinearShape, + kThreads, + kElementsPerAccess + >; + + /// Shared memory iterator to A operand + using SmemIteratorA = transform::threadblock::RegularTileAccessIterator< + MatrixShape, ElementA, SmemLayoutA, 0, + IteratorThreadMapA>; + + /// Policy of iterator B + using IteratorThreadMapB = transform::PitchLinearStripminedThreadMap< + layout::PitchLinearShape, + kThreads, + kElementsPerAccess + >; + + /// Shared memory iterator to B operand + using SmemIteratorB = transform::threadblock::RegularTileAccessIterator< + MatrixShape, ElementB, SmemLayoutB, 1, + IteratorThreadMapB>; + + // + // Warp-level matrix multiply operator + // + + // Define the warp-level op + static const int WarpNumThreadsM = 4; // TODO need to extract these from template data + static const int WarpNumThreadsN = 8; + static_assert(!(WarpShape::kM % WarpNumThreadsM) && !(WarpShape::kN % WarpNumThreadsN), + "WarpShape must be divisible by ThreadTile shape."); + static const int ThreadTileM = WarpShape::kM / WarpNumThreadsM; + static const int ThreadTileN = WarpShape::kN / WarpNumThreadsN; + static const int LaneLayout = ThreadTileM > 4 && ThreadTileN > 4 ? 2 : 1; + static const int numElementsA = 128 / sizeof_bits::value; + static const int numElementsB = 128 / sizeof_bits::value; + static const int LaneM = cutlass::const_min(numElementsA, ThreadTileM); + static const int LaneN = cutlass::const_min(numElementsB, ThreadTileN); + // these should have max of thread tile also + using LaneMmaShape = cutlass::gemm::GemmShape< + LaneM, + LaneN, + 1>; + using Policy = cutlass::gemm::warp::MmaSimtPolicy< + cutlass::MatrixShape, // WarpShape + cutlass::layout::RowMajorInterleaved, // LaneLayout + LaneMmaShape + >; + + using MmaWarpSimt = cutlass::gemm::warp::MmaSimt< + WarpShape, /// Size of the Gemm problem - concept: gemm::GemmShape<> 128, 128, 8 + ElementA, /// Data type of A elements + SmemLayoutA, /// Layout of A matrix (concept: MatrixLayout) + ElementB, /// Data type of B elements + SmemLayoutB, /// Layout of B matrix (concept: MatrixLayout) + ElementC, /// Element type of C matrix + LayoutC, /// Layout of C matrix (concept: MatrixLayout) + Policy /// Policy describing warp-level MmaTensorOp (concept: MmaTensorOp policy) + >; /// Used for partial specialization + + /// Policy used to define MmaPipelined + using MmaPolicy = MmaPolicy< + MmaWarpSimt, + MatrixShape<0, 0>, + MatrixShape<0, 0>, // or Shape::kK / 32 + WarpCount::kK>; +}; + +/// Partial specialization for complex double-precision +/// +/// A: column-major +/// B: row-major +/// Operator: arch::OpMultiplyAddComplex or arch::OpMultiplyGaussianComplex +/// +/// This uses the default warp-level operator given tile sizes +template < + /// Shape of threadblock-scoped matrix multiply operator (concept: + /// GemmShape) + typename Shape_, + /// Shape of warp-level matrix multiply operator (concept: GemmShape) + typename WarpShape_, + typename RealA, + typename RealB, + typename RealC, + /// Layout of accumulator + typename LayoutC_, + /// Number of stages + int Stages, + /// Complex transformation on operand A + ComplexTransform TransformA, + /// Complex transformation on operand B + ComplexTransform TransformB, + /// Multiply-add operator (arch::OpMultiplyAddComplex, arch::OpMultiplyGaussianComplex) + typename Operator_, + /// Cache operation of operand A + cutlass::arch::CacheOperation::Kind CacheOpA, + /// Cache operation of operand B + cutlass::arch::CacheOperation::Kind CacheOpB> +struct DefaultMultistageMmaComplexCore< + Shape_, WarpShape_, GemmShape<1, 1, 1>, + complex, layout::RowMajor, + complex, layout::ColumnMajor, + complex, LayoutC_, + arch::OpClassSimt, + Stages, + TransformA, TransformB, + Operator_, + CacheOpA, CacheOpB> { + + using Shape = Shape_; + using WarpShape = WarpShape_; + using InstructionShape = GemmShape<1, 1, 1>; + using ElementA = complex; + using LayoutA = layout::RowMajor; + using ElementB = complex; + using LayoutB = layout::ColumnMajor; + using ElementC = complex; + using LayoutC = LayoutC_; + static int const kStages = Stages; + static ComplexTransform const kTransformA = TransformA; + static ComplexTransform const kTransformB = TransformB; + using Operator = Operator_; + static cutlass::arch::CacheOperation::Kind const kCacheOpA = cutlass::arch::CacheOperation::Always; + static cutlass::arch::CacheOperation::Kind const kCacheOpB = cutlass::arch::CacheOperation::Always; + + /// Number of warps present + using WarpCount = GemmShape; + + // Divisility requirements + static_assert( + !(Shape::kM % WarpShape::kM) && !(Shape::kN % WarpShape::kN), + "Threadblock-scoped GEMM should be divisible by warp-scoped GEMM size."); + + static_assert(WarpCount::kCount > 1, + "This specialization requires at least two warps."); + + /// Number of threads per warp + static int const kWarpSize = warp::WarpSize::value; + + /// Number of threads total + static int const kThreads = WarpCount::kCount * kWarpSize; + + /// Size of access + static int const kAccessSizeInBits = sizeof_bits::value; + + /// No vectorized accesses + static int const kElementsPerAccess = 1; + + // + // Shared memory layouts + // + + using SmemLayoutA = layout::ColumnMajor; + + using SmemLayoutB = layout::RowMajor; + + // + // Iterators to write to shared memory + // + + /// ThreadMap of iterator A + using IteratorThreadMapA = transform::PitchLinearStripminedThreadMap< + layout::PitchLinearShape, + kThreads, + kElementsPerAccess + >; + + /// Transpose the ThreadMap of iterator A + using SmemThreadMapA = transform::TransposePitchLinearThreadMapSimt; + + /// Shared memory iterator to A operand + using SmemIteratorA = transform::threadblock::RegularTileAccessIterator< + MatrixShape, ElementA, SmemLayoutA, 0, + SmemThreadMapA>; + + /// Policy of iterator B + using IteratorThreadMapB = transform::PitchLinearStripminedThreadMap< + layout::PitchLinearShape, + kThreads, + kElementsPerAccess + >; + + /// Transpose the ThreadMap of iterator B + using SmemThreadMapB = transform::TransposePitchLinearThreadMapSimt; + + /// Shared memory iterator to B operand + using SmemIteratorB = transform::threadblock::RegularTileAccessIterator< + MatrixShape, ElementB, SmemLayoutB, 1, + SmemThreadMapB>; + + // + // Warp-level matrix multiply operator + // + + // Define the warp-level op + static const int WarpNumThreadsM = 4; // TODO need to extract these from template data + static const int WarpNumThreadsN = 8; + static_assert(!(WarpShape::kM % WarpNumThreadsM) && !(WarpShape::kN % WarpNumThreadsN), + "WarpShape must be divisible by ThreadTile shape."); + static const int ThreadTileM = WarpShape::kM / WarpNumThreadsM; + static const int ThreadTileN = WarpShape::kN / WarpNumThreadsN; + static const int LaneLayout = ThreadTileM > 4 && ThreadTileN > 4 ? 2 : 1; + static const int numElementsA = 128 / sizeof_bits::value; + static const int numElementsB = 128 / sizeof_bits::value; + static const int LaneM = cutlass::const_min(numElementsA, ThreadTileM); + static const int LaneN = cutlass::const_min(numElementsB, ThreadTileN); + // these should have max of thread tile also + using LaneMmaShape = cutlass::gemm::GemmShape< + LaneM, + LaneN, + 1>; + using Policy = cutlass::gemm::warp::MmaSimtPolicy< + cutlass::MatrixShape, // WarpShape + cutlass::layout::RowMajorInterleaved, // LaneLayout + LaneMmaShape + >; + + using MmaWarpSimt = cutlass::gemm::warp::MmaSimt< + WarpShape, /// Size of the Gemm problem - concept: gemm::GemmShape<> 128, 128, 8 + ElementA, /// Data type of A elements + SmemLayoutA, /// Layout of A matrix (concept: MatrixLayout) + ElementB, /// Data type of B elements + SmemLayoutB, /// Layout of B matrix (concept: MatrixLayout) + ElementC, /// Element type of C matrix + LayoutC, /// Layout of C matrix (concept: MatrixLayout) + Policy /// Policy describing warp-level MmaTensorOp (concept: MmaTensorOp policy) + >; /// Used for partial specialization + + /// Policy used to define MmaPipelined + using MmaPolicy = MmaPolicy< + MmaWarpSimt, + MatrixShape, + MatrixShape<0, Shape::kK / 32>, + WarpCount::kK>; +}; + +/// Partial specialization for complex double-precision +/// +/// A: column-major +/// B: row-major +/// Operator: arch::OpMultiplyAddComplex or arch::OpMultiplyGaussianComplex +/// +/// This uses the default warp-level operator given tile sizes +template < + /// Shape of threadblock-scoped matrix multiply operator (concept: + /// GemmShape) + typename Shape_, + /// Shape of warp-level matrix multiply operator (concept: GemmShape) + typename WarpShape_, + typename RealA, + typename RealB, + typename RealC, + /// Layout of accumulator + typename LayoutC_, + /// Number of stages + int Stages, + /// Complex transformation on operand A + ComplexTransform TransformA, + /// Complex transformation on operand B + ComplexTransform TransformB, + /// Multiply-add operator (arch::OpMultiplyAddComplex, arch::OpMultiplyGaussianComplex) + typename Operator_, + /// Cache operation of operand A + cutlass::arch::CacheOperation::Kind CacheOpA, + /// Cache operation of operand B + cutlass::arch::CacheOperation::Kind CacheOpB> +struct DefaultMultistageMmaComplexCore< + Shape_, WarpShape_, GemmShape<1, 1, 1>, + complex, layout::RowMajor, + complex, layout::RowMajor, + complex, LayoutC_, + arch::OpClassSimt, + Stages, + TransformA, TransformB, + Operator_, + CacheOpA, CacheOpB> { + + using Shape = Shape_; + using WarpShape = WarpShape_; + using InstructionShape = GemmShape<1, 1, 1>; + using ElementA = complex; + using LayoutA = layout::RowMajor; + using ElementB = complex; + using LayoutB = layout::RowMajor; + using ElementC = complex; + using LayoutC = LayoutC_; + static int const kStages = Stages; + static ComplexTransform const kTransformA = TransformA; + static ComplexTransform const kTransformB = TransformB; + using Operator = Operator_; + static cutlass::arch::CacheOperation::Kind const kCacheOpA = cutlass::arch::CacheOperation::Always; + static cutlass::arch::CacheOperation::Kind const kCacheOpB = cutlass::arch::CacheOperation::Always; + + /// Number of warps present + using WarpCount = GemmShape; + + // Divisility requirements + static_assert( + !(Shape::kM % WarpShape::kM) && !(Shape::kN % WarpShape::kN), + "Threadblock-scoped GEMM should be divisible by warp-scoped GEMM size."); + + static_assert(WarpCount::kCount > 1, + "This specialization requires at least two warps."); + + /// Number of threads per warp + static int const kWarpSize = warp::WarpSize::value; + + /// Number of threads total + static int const kThreads = WarpCount::kCount * kWarpSize; + + /// Size of access + static int const kAccessSizeInBits = sizeof_bits::value; + + /// No vectorized accesses + static int const kElementsPerAccess = 1; + + // + // Shared memory layouts + // + + using SmemLayoutA = layout::ColumnMajor; + + using SmemLayoutB = layout::RowMajor; + + // + // Iterators to write to shared memory + // + + /// ThreadMap of iterator A + using IteratorThreadMapA = transform::PitchLinearStripminedThreadMap< + layout::PitchLinearShape, + kThreads, + kElementsPerAccess + >; + + /// Transpose the ThreadMap of iterator A + using SmemThreadMapA = transform::TransposePitchLinearThreadMapSimt; + + /// Shared memory iterator to A operand + using SmemIteratorA = transform::threadblock::RegularTileAccessIterator< + MatrixShape, ElementA, SmemLayoutA, 0, + SmemThreadMapA>; + + /// Policy of iterator B + using IteratorThreadMapB = transform::PitchLinearStripminedThreadMap< + layout::PitchLinearShape, + kThreads, + kElementsPerAccess + >; + + /// Shared memory iterator to B operand + using SmemIteratorB = transform::threadblock::RegularTileAccessIterator< + MatrixShape, ElementB, SmemLayoutB, 1, + IteratorThreadMapB>; + + // + // Warp-level matrix multiply operator + // + + // Define the warp-level op + static const int WarpNumThreadsM = 4; // TODO need to extract these from template data + static const int WarpNumThreadsN = 8; + static_assert(!(WarpShape::kM % WarpNumThreadsM) && !(WarpShape::kN % WarpNumThreadsN), + "WarpShape must be divisible by ThreadTile shape."); + static const int ThreadTileM = WarpShape::kM / WarpNumThreadsM; + static const int ThreadTileN = WarpShape::kN / WarpNumThreadsN; + static const int LaneLayout = ThreadTileM > 4 && ThreadTileN > 4 ? 2 : 1; + static const int numElementsA = 128 / sizeof_bits::value; + static const int numElementsB = 128 / sizeof_bits::value; + static const int LaneM = cutlass::const_min(numElementsA, ThreadTileM); + static const int LaneN = cutlass::const_min(numElementsB, ThreadTileN); + // these should have max of thread tile also + using LaneMmaShape = cutlass::gemm::GemmShape< + LaneM, + LaneN, + 1>; + using Policy = cutlass::gemm::warp::MmaSimtPolicy< + cutlass::MatrixShape, // WarpShape + cutlass::layout::RowMajorInterleaved, // LaneLayout + LaneMmaShape + >; + + using MmaWarpSimt = cutlass::gemm::warp::MmaSimt< + WarpShape, /// Size of the Gemm problem - concept: gemm::GemmShape<> 128, 128, 8 + ElementA, /// Data type of A elements + SmemLayoutA, /// Layout of A matrix (concept: MatrixLayout) + ElementB, /// Data type of B elements + SmemLayoutB, /// Layout of B matrix (concept: MatrixLayout) + ElementC, /// Element type of C matrix + LayoutC, /// Layout of C matrix (concept: MatrixLayout) + Policy /// Policy describing warp-level MmaTensorOp (concept: MmaTensorOp policy) + >; /// Used for partial specialization + + /// Policy used to define MmaPipelined + using MmaPolicy = MmaPolicy< + MmaWarpSimt, + MatrixShape, + MatrixShape<0, 0>, // or Shape::kK / 32 + WarpCount::kK>; +}; + +//////////////////////////////////////////////////////////////////////////////// + } // namespace threadblock } // namespace gemm diff --git a/include/cutlass/gemm/threadblock/mma_multistage.h b/include/cutlass/gemm/threadblock/mma_multistage.h index 0431c3060..804e3373a 100644 --- a/include/cutlass/gemm/threadblock/mma_multistage.h +++ b/include/cutlass/gemm/threadblock/mma_multistage.h @@ -228,7 +228,7 @@ public: for (int v = 0; v < IteratorA::kAccessesPerVector; ++v) { auto gmem_ptr = iterator_A.get(); - cutlass::arch::cp_async( + cutlass::arch::cp_async_zfill( dst_ptr + v, gmem_ptr, iterator_A.valid()); ++iterator_A; @@ -258,7 +258,7 @@ public: for (int v = 0; v < IteratorB::kAccessesPerVector; ++v) { auto gmem_ptr = iterator_B.get(); - cutlass::arch::cp_async( + cutlass::arch::cp_async_zfill( dst_ptr + v, gmem_ptr, iterator_B.valid()); ++iterator_B; @@ -513,6 +513,11 @@ public: } } + + // commit and drain all pending and predicated LDGSTS pnz from the GEMM mainloop + cutlass::arch::cp_async_fence(); + cutlass::arch::cp_async_wait<0>(); + __syncthreads(); } }; diff --git a/include/cutlass/gemm/threadblock/mma_singlestage.h b/include/cutlass/gemm/threadblock/mma_singlestage.h index 32d4d4ee6..373d985ac 100644 --- a/include/cutlass/gemm/threadblock/mma_singlestage.h +++ b/include/cutlass/gemm/threadblock/mma_singlestage.h @@ -105,6 +105,14 @@ public: /// Warp-level Mma using Operator = typename Policy::Operator; + using ArchTag = arch::Sm70; + + /// Complex transform on A operand + static ComplexTransform const kTransformA = Operator::kTransformA; + + /// Complex transform on B operand + static ComplexTransform const kTransformB = Operator::kTransformB; + // staticaly assert kStages for MmaSingleStage is 1 (single stage mma pipeline) static_assert((Base::kStages==1), "MmaSingleStage requires kStages set to value 1"); private: diff --git a/include/cutlass/gemm/warp/mma_complex_tensor_op.h b/include/cutlass/gemm/warp/mma_complex_tensor_op.h index 2dc72fd33..a34c16df0 100644 --- a/include/cutlass/gemm/warp/mma_complex_tensor_op.h +++ b/include/cutlass/gemm/warp/mma_complex_tensor_op.h @@ -314,8 +314,17 @@ public: /// Shape of the warp in units of thread (concept: MmaLanePolicyTensorOp) using Policy = Policy_; + /// Underlying matrix multiply operator (concept: arch::Mma) + using ArchMmaOperator = typename Policy::Operator; + + /// Architecture tag from underlying instruction + using ArchTag = typename ArchMmaOperator::ArchTag; + + /// Indicates class of matrix operator + using OperatorClass = arch::OpClassTensorOp; + /// Shape of underlying instruction - using InstructionShape = typename Policy::Operator::Shape; + using InstructionShape = typename ArchMmaOperator::Shape; /// Complex transform on A operand static ComplexTransform const kTransformA = TransformA; @@ -323,9 +332,6 @@ public: /// Complex transform on B operand static ComplexTransform const kTransformB = TransformB; - /// Indicates class of matrix operator - using OperatorClass = arch::OpClassTensorOp; - /// Number of threads participating in warp-level matrix product static int const kThreadCount = 32; @@ -337,7 +343,7 @@ public: Operand::kA, ElementA, LayoutA, - MatrixShape, + MatrixShape, Policy::OpDelta::kRow, 32, 1 @@ -355,7 +361,7 @@ public: Operand::kB, ElementB, LayoutB, - MatrixShape, + MatrixShape, Policy::OpDelta::kColumn, 32, 1 @@ -368,14 +374,14 @@ public: using TransformedFragmentB = FragmentB; static_assert( - !(Shape::kM % Policy::Operator::Shape::kM) && - !(Shape::kN % Policy::Operator::Shape::kN), + !(Shape::kM % ArchMmaOperator::Shape::kM) && + !(Shape::kN % ArchMmaOperator::Shape::kN), "Shape of warp-level Mma must be divisible by operator shape."); /// Number of mma operations performed using MmaIterations = MatrixShape< - Shape::kM / Policy::Operator::Shape::kM, - Shape::kN / Policy::Operator::Shape::kN + Shape::kM / ArchMmaOperator::Shape::kM, + Shape::kN / ArchMmaOperator::Shape::kN >; /// Iterates over the C operand in memory @@ -383,7 +389,7 @@ public: MatrixShape, ElementC, LayoutC, - typename Policy::Operator::Shape, + typename ArchMmaOperator::Shape, typename Policy::OpDelta>; /// Storage for C tile, the accumulator. Note, regardless of multiplicand type, this @@ -393,7 +399,7 @@ public: using FragmentC = typename IteratorC::Fragment; static_assert( - FragmentC::kElements == 2 * MmaIterations::kCount * Policy::Operator::FragmentC::kElements, + FragmentC::kElements == 2 * MmaIterations::kCount * ArchMmaOperator::FragmentC::kElements, "Unexpected planar complex fragment length."); private: @@ -403,7 +409,7 @@ private: // /// Underlying real-valued matrix multiply operator (concept: arch::Mma) - typename Policy::Operator mma; + ArchMmaOperator mma; public: @@ -425,9 +431,9 @@ public: ) const { // Alias types for underlying real-valued matrix multiply operator - using MmaOperandA = typename Policy::Operator::FragmentA; - using MmaOperandB = typename Policy::Operator::FragmentB; - using MmaOperandC = typename Policy::Operator::FragmentC; + using MmaOperandA = typename ArchMmaOperator::FragmentA; + using MmaOperandB = typename ArchMmaOperator::FragmentB; + using MmaOperandC = typename ArchMmaOperator::FragmentC; static_assert(MmaOperandA::kElements == 1, "This implementation only supports math instructions in which exactly one element is needed for the A operand." @@ -599,12 +605,18 @@ public: /// Shape of the warp in units of thread (concept: MmaLanePolicySimt) using Policy = Policy_; - + + /// Underlying matrix multiply operator (concept: arch::Mma) + using ArchMmaOperator = typename Policy::Operator; + /// Shape of underlying instruction - using InstructionShape = typename Policy::Operator::Shape; + using InstructionShape = typename ArchMmaOperator::Shape; /// Underlying arch tag - using ArchTag = typename Policy::Operator::ArchTag; + using ArchTag = typename ArchMmaOperator::ArchTag; + + /// Indicates class of matrix operator + using OperatorClass = arch::OpClassTensorOp; /// Complex transform on A operand static ComplexTransform const kTransformA = TransformA; @@ -612,9 +624,6 @@ public: /// Complex transform on B operand static ComplexTransform const kTransformB = TransformB; - /// Indicates class of matrix operator - using OperatorClass = arch::OpClassTensorOp; - /// Number of threads participating in warp-level matrix product static int const kThreadCount = 32; @@ -626,7 +635,7 @@ public: Operand::kA, ElementA, LayoutA, - MatrixShape, + MatrixShape, Policy::OpDelta::kRow, 32, 1 @@ -637,7 +646,7 @@ public: /// Storage for transformed A tile using TransformedFragmentA = - Array; + Array; /// Iterates over the B operand in memory using IteratorB = MmaTensorOpMultiplicandTileIterator< @@ -645,7 +654,7 @@ public: Operand::kB, ElementB, LayoutB, - MatrixShape, + MatrixShape, Policy::OpDelta::kColumn, 32, 1 @@ -656,17 +665,17 @@ public: /// Storage for transformed B tile using TransformedFragmentB = - Array; + Array; static_assert( - !(Shape::kM % Policy::Operator::Shape::kM) && - !(Shape::kN % Policy::Operator::Shape::kN), + !(Shape::kM % ArchMmaOperator::Shape::kM) && + !(Shape::kN % ArchMmaOperator::Shape::kN), "Shape of warp-level Mma must be divisible by operator shape."); /// Number of complex products operations performed (one complex product needs four mma instructions) using MmaIterations = MatrixShape< - Shape::kM / Policy::Operator::Shape::kM, - Shape::kN / Policy::Operator::Shape::kN + Shape::kM / ArchMmaOperator::Shape::kM, + Shape::kN / ArchMmaOperator::Shape::kN >; /// Iterates over the C operand in memory @@ -674,7 +683,7 @@ public: MatrixShape, ElementC, LayoutC, - typename Policy::Operator::Shape, + typename ArchMmaOperator::Shape, typename Policy::OpDelta>; /// Storage for C tile, the accumulator. Note, regardless of multiplicand type, this @@ -690,7 +699,7 @@ private: // /// Underlying real-valued matrix multiply operator (concept: arch::Mma) - typename Policy::Operator mma; + ArchMmaOperator mma; public: @@ -712,11 +721,11 @@ public: ) const { // Alias types for underlying real-valued matrix multiply operator - using InstMmaOperandA = typename Policy::Operator::FragmentA; - using InstMmaOperandB = typename Policy::Operator::FragmentB; - using MmaOperandC = typename Policy::Operator::FragmentC; + using InstMmaOperandA = typename ArchMmaOperator::FragmentA; + using InstMmaOperandB = typename ArchMmaOperator::FragmentB; + using MmaOperandC = typename ArchMmaOperator::FragmentC; - static_assert(platform::is_same, typename Policy::Operator::Shape>::value, + static_assert(platform::is_same, typename ArchMmaOperator::Shape>::value, "This implementation only supports MMA.1688 math instructions."); static_assert(InstMmaOperandA::kElements == 4, @@ -794,8 +803,8 @@ public: void transform(TransformedFragmentA &dst_A, TransformedFragmentB &dst_B, FragmentA const &A, FragmentB const &B) const { // Alias types for underlying real-valued matrix multiply operator - using InstMmaOperandA = typename Policy::Operator::FragmentA; - using InstMmaOperandB = typename Policy::Operator::FragmentB; + using InstMmaOperandA = typename ArchMmaOperator::FragmentA; + using InstMmaOperandB = typename ArchMmaOperator::FragmentB; // // Define conversions from source type to instruction operands' type diff --git a/include/cutlass/gemm/warp/mma_gaussian_complex_tensor_op.h b/include/cutlass/gemm/warp/mma_gaussian_complex_tensor_op.h index bf3d98dfb..4ab139023 100644 --- a/include/cutlass/gemm/warp/mma_gaussian_complex_tensor_op.h +++ b/include/cutlass/gemm/warp/mma_gaussian_complex_tensor_op.h @@ -147,11 +147,17 @@ public: /// Shape of the warp in units of thread (concept: MmaLanePolicySimt) using Policy = Policy_; - /// Shape of underlying instruction - using InstructionShape = typename Policy::Operator::Shape; + /// Underlying matrix multiply operator (concept: arch::Mma) + using ArchMmaOperator = typename Policy::Operator; - /// Underlying architecture tag - using ArchTag = typename Policy::Operator::ArchTag; + /// Shape of underlying instruction + using InstructionShape = typename ArchMmaOperator::Shape; + + /// Underlying arch tag + using ArchTag = typename ArchMmaOperator::ArchTag; + + /// Indicates class of matrix operator + using OperatorClass = arch::OpClassTensorOp; /// Complex transform on A operand static ComplexTransform const kTransformA = TransformA; @@ -159,8 +165,6 @@ public: /// Complex transform on B operand static ComplexTransform const kTransformB = TransformB; - /// Indicates class of matrix operator - using OperatorClass = arch::OpClassTensorOp; /// Number of threads participating in warp-level matrix product static int const kThreadCount = 32; @@ -173,7 +177,7 @@ public: Operand::kA, ElementA, LayoutA, - MatrixShape, + MatrixShape, Policy::OpDelta::kRow, 32, 1 @@ -191,7 +195,7 @@ public: Operand::kB, ElementB, LayoutB, - MatrixShape, + MatrixShape, Policy::OpDelta::kColumn, 32, 1 @@ -204,14 +208,14 @@ public: using TransformedFragmentB = FragmentB; static_assert( - !(Shape::kM % Policy::Operator::Shape::kM) && - !(Shape::kN % Policy::Operator::Shape::kN), + !(Shape::kM % ArchMmaOperator::Shape::kM) && + !(Shape::kN % ArchMmaOperator::Shape::kN), "Shape of warp-level Mma must be divisible by operator shape."); /// Number of mma operations performed using MmaIterations = MatrixShape< - Shape::kM / Policy::Operator::Shape::kM, - Shape::kN / Policy::Operator::Shape::kN + Shape::kM / ArchMmaOperator::Shape::kM, + Shape::kN / ArchMmaOperator::Shape::kN >; /// Iterates over the C operand in memory @@ -219,7 +223,7 @@ public: MatrixShape, ElementC, LayoutC, - typename Policy::Operator::Shape, + typename ArchMmaOperator::Shape, typename Policy::OpDelta>; /// Storage for C tile, the accumulator. Note, regardless of multiplicand type, this @@ -229,7 +233,7 @@ public: using FragmentC = typename IteratorC::Fragment; static_assert( - FragmentC::kElements == 3 * MmaIterations::kCount * Policy::Operator::FragmentC::kElements, + FragmentC::kElements == 3 * MmaIterations::kCount * ArchMmaOperator::FragmentC::kElements, "Unexpected gaussian complex fragment length."); private: @@ -239,7 +243,7 @@ private: // /// Underlying real-valued matrix multiply operator (concept: arch::Mma) - typename Policy::Operator mma; + ArchMmaOperator mma; public: @@ -261,9 +265,9 @@ public: ) const { // Alias types for underlying real-valued matrix multiply operator - using MmaOperandA = typename Policy::Operator::FragmentA; - using MmaOperandB = typename Policy::Operator::FragmentB; - using MmaOperandC = typename Policy::Operator::FragmentC; + using MmaOperandA = typename ArchMmaOperator::FragmentA; + using MmaOperandB = typename ArchMmaOperator::FragmentB; + using MmaOperandC = typename ArchMmaOperator::FragmentC; static_assert(MmaOperandA::kElements == 1, "This implementation only supports math instructions in which exactly one element is needed for the A operand." @@ -346,8 +350,6 @@ public: ///////////////////////////////////////////////////////////////////////////////////////////////// -// TODO - partial specializations of real*complex and complex*real - ///////////////////////////////////////////////////////////////////////////////////////////////// } // namespace warp diff --git a/include/cutlass/gemm/warp/mma_simt.h b/include/cutlass/gemm/warp/mma_simt.h index c90624cee..306a08d17 100644 --- a/include/cutlass/gemm/warp/mma_simt.h +++ b/include/cutlass/gemm/warp/mma_simt.h @@ -68,6 +68,10 @@ template < typename Policy_, /// Number of partitions along K dimension int PartitionsK = 1, + /// Complex transformation on operand A + ComplexTransform TransformA = ComplexTransform::kNone, + /// Complex transformation on operand B + ComplexTransform TransformB = ComplexTransform::kNone, /// Used for partial specialization typename Enable = bool > @@ -104,10 +108,10 @@ public: using ArchTag = arch::Sm50; /// Complex transform on A operand - static ComplexTransform const kTransformA = ComplexTransform::kNone; + static ComplexTransform const kTransformA = TransformA; /// Complex transform on B operand - static ComplexTransform const kTransformB = ComplexTransform::kNone; + static ComplexTransform const kTransformB = TransformB; /// Layout of threads using ThreadLayoutA = typename platform::conditional< platform::is_same< layout::ColumnMajorInterleaved<4>, LayoutA >::value, @@ -215,12 +219,22 @@ public: CUTLASS_DEVICE void operator()( FragmentC &d, - FragmentA const &a, - FragmentB const &b, + FragmentA a, + FragmentB b, FragmentC const &c, int group_idx = 0) const { ThreadMma mma; + if (kTransformA == ComplexTransform::kConjugate) { + conjugate conj_a; + a = conj_a(a); + } + + if (kTransformB == ComplexTransform::kConjugate) { + conjugate conj_b; + b = conj_b(b); + } + mma(d, a, b, c); } diff --git a/include/cutlass/gemm/warp/mma_sparse_tensor_op.h b/include/cutlass/gemm/warp/mma_sparse_tensor_op.h index 8b7312baa..ba86e0858 100644 --- a/include/cutlass/gemm/warp/mma_sparse_tensor_op.h +++ b/include/cutlass/gemm/warp/mma_sparse_tensor_op.h @@ -111,17 +111,28 @@ public: /// Shape of the warp in units of thread (concept: MmaLanePolicySimt) using Policy = Policy_; + /// Equivalant base dense mma + using Base = MmaTensorOp; + + /// Underlying matrix multiply operator (concept: arch::Mma) + using ArchMmaOperator = typename Base::ArchMmaOperator; + /// Architecture tag from underlying instruction - using ArchTag = typename Policy::Operator::ArchTag; + using ArchTag = typename Base::ArchTag; /// Indicates class of matrix operator - using OperatorClass = arch::OpClassTensorOp; + using OperatorClass = typename Base::OperatorClass; + + /// Shape of underlying instruction + using InstructionShape = typename Base::InstructionShape; /// Complex transform on A operand - static ComplexTransform const kTransformA = ComplexTransform::kNone; + static ComplexTransform const kTransformA = Base::kTransformA; /// Complex transform on B operand - static ComplexTransform const kTransformB = ComplexTransform::kNone; + static ComplexTransform const kTransformB = Base::kTransformB; /// Number of threads participating in warp-level matrix product static int const kThreadCount = 32; @@ -171,25 +182,19 @@ public: Array; /// Iterates over the B operand in memory - using IteratorB = MmaTensorOpMultiplicandTileIterator< - MatrixShape, Operand::kB, ElementB, LayoutB, - MatrixShape, - Policy::OpDelta::kRow, kThreadCount, kPartitionsK>; + using IteratorB = typename Base::IteratorB; /// Storage for B tile - using FragmentB = typename IteratorB::Fragment; + using FragmentB = typename Base::FragmentB; /// Storage for transformed B tile - using TransformedFragmentB = - Array; + using TransformedFragmentB = typename Base::TransformedFragmentB; /// Iterates over the C operand in memory - using IteratorC = MmaTensorOpAccumulatorTileIterator< - MatrixShape, ElementC, LayoutC, - typename Policy::Operator::Shape, typename Policy::OpDelta>; + using IteratorC = typename Base::IteratorC; /// Storage for C tile - using FragmentC = typename IteratorC::Fragment; + using FragmentC = typename Base::FragmentC; /// Iterates over the E operand in memory using IteratorE = SparseMmaTensorOpMetaTileIterator< @@ -204,23 +209,13 @@ public: /// Storage for E tile using FragmentE = typename IteratorE::Fragment; -private: - - static_assert( - !(Shape::kM % Policy::Operator::Shape::kM) && - !(Shape::kN % Policy::Operator::Shape::kN), - "Shape of warp-level Mma must be divisible by operator shape."); - - /// Number of mma operations performed - using MmaIterations = MatrixShape< - Shape::kM / Policy::Operator::Shape::kM, - Shape::kN / Policy::Operator::Shape::kN - >; + /// Number of mma operations performed + using MmaIterations = typename Base::MmaIterations; public: /// Underlying matrix multiply operator (concept: arch::Mma) - typename Policy::Operator mma; + ArchMmaOperator mma; public: @@ -299,21 +294,21 @@ public: // Define conversions from source type to instruction type // FloatRoundStyle const kRoundA = - PreferredRoundingMode::kRound; FloatRoundStyle const kRoundB = - PreferredRoundingMode::kRound; - detail::ConvertAndPack convert_A; - NumericArrayConverter convert_B; Array const *ptr_A = reinterpret_cast const *>(&A); - Array * - ptr_dst_A = reinterpret_cast * + ptr_dst_A = reinterpret_cast *>(&dst_A); dst_B = convert_B(B); diff --git a/include/cutlass/gemm/warp/mma_tensor_op.h b/include/cutlass/gemm/warp/mma_tensor_op.h index 1a10c7e4f..a60a86020 100644 --- a/include/cutlass/gemm/warp/mma_tensor_op.h +++ b/include/cutlass/gemm/warp/mma_tensor_op.h @@ -244,8 +244,6 @@ public: /// Storage for C tile using FragmentC = typename IteratorC::Fragment; -private: - /// Number of mma operations performed using MmaIterations = MatrixShape< (Shape::kM + ArchMmaOperator::Shape::kM - 1) / ArchMmaOperator::Shape::kM, diff --git a/include/cutlass/gemm/warp/mma_tensor_op_tile_iterator.h b/include/cutlass/gemm/warp/mma_tensor_op_tile_iterator.h index 1fe04e92a..59f68a42a 100644 --- a/include/cutlass/gemm/warp/mma_tensor_op_tile_iterator.h +++ b/include/cutlass/gemm/warp/mma_tensor_op_tile_iterator.h @@ -1518,6 +1518,7 @@ class MmaTensorOpMultiplicandTileIterator< } else if (Layout::kFactor == 2) { // Super Matrix multiply kBlock = 32 if (Policy::LdsmShape::kStrided == Policy::LdsmShape::kCount) { + // Matrix multiply 1688 A/B // (Q stands for 1 8x128bit block). // Q0 // Q1 @@ -3191,10 +3192,430 @@ public: int idx = mma_m + mma_n * Policy::MmaIterations::kRow; - AccessType* access_ptr = reinterpret_cast(offset_ref.data() + - offset_ref.offset(TensorCoord(accum_m, accum_n))); + AccessType* access_ptr = reinterpret_cast(offset_ref.data() + + offset_ref.offset(TensorCoord(accum_m, accum_n))); - access_ptr[0] = frag_ptr[idx]; + access_ptr[0] = frag_ptr[idx]; + } + } + } + + /// Stores a fragment to memory with additional pointer offset + CUTLASS_DEVICE + void store_with_byte_offset( + Fragment const &frag, ///< fragment to store from the tensor + Index byte_offset) const { ///< store a tile with a linear offset + + store_with_pointer_offset(byte_offset / sizeof(Element)); + } + + /// Stores a fragment to memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void store( + Fragment &frag, ///< fragment to store to the tensor + TensorCoord const &tile_offset) const { ///< stores a tile with a logical offset in units of whole tiles + + store(frag, tile_offset, 0); + } + + /// Stores a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void store( + /// fragment to store to the tensor + Fragment const &frag, + /// stores a tile with a logical offset in units of whole tiles + TensorCoord const &tile_offset, + /// stores a tile with a logical offset AND a pointer offset + Index pointer_offset) const { + store_with_pointer_offset(frag, ref_.offset(tile_offset) + pointer_offset); + } +}; + +//////////////////////////////////////////////////////////////////////////////// + +/// This tile iterator is specialized for 32-thread TensorOps. It is used to load or store +/// accumulators from memory and is agnostic to layout. It could be faster if it assumed row-major +/// accumulator layout. +/// +/// Satisfies: +/// ReadableRandomAccessContiguousTileIteratorConcept | +/// WriteableRandomAccessContiguousTileIteratorConcept +/// + +template < + /// Size of the matrix to load (concept: MatrixShape) + typename Shape_, + /// Element typ + typename Element_, + /// Shape of one matrix product operation (concept: MatrixShape) + typename InstructionShape_, + /// Interval between adjacent *MMA instructions (in units of MMA + /// instructions, concept: MatrixShape) + typename OpDelta_, + /// Interleaved N + int InterleavedN> +class MmaTensorOpAccumulatorTileIterator< + Shape_, Element_, cutlass::layout::TensorNCxHWx, + InstructionShape_, OpDelta_> { + public: + + /// Shape of tile to load (concept: MatrixShape) + using Shape = Shape_; + + /// Operand tag + static Operand const kOperand = Operand::kC; + + /// Element type + using Element = int8_t; + + /// Layout of source tile + using Layout = cutlass::layout::TensorNCxHWx; + + /// Shape of one matrix product operation (concept: MatrixShape) + using InstructionShape = InstructionShape_; + + /// Delta between *MMA operations (in units of *MMA operations, concept: MatrixShape) + using OpDelta = OpDelta_; + + /// Number of participating threads + static int const kThreads = 32; + + /// TensorRef type for loading element from a tensor + using TensorRef = TensorRef; + + /// Index type + using Index = typename TensorRef::Index; + + /// Long Index type + using LongIndex = typename TensorRef::LongIndex; + + /// Coordinate for an element in the tensor + using TensorCoord = typename TensorRef::TensorCoord; + + /// Internal structure of iterator - made public to enable introspection + struct Policy { + static_assert( + !(Shape::kRow % InstructionShape::kM) && + !(Shape::kColumn % InstructionShape::kN), + "Shape of warp-level Mma must be divisible by operator shape."); + + /// Number of elements in strided dimension that each STG writes + static int const kStridedPerSTG = 8; + + /// Factor to calculate reorder index to pack accumulator. + static int const kPackedFactor = Shape::kColumn / 32; + + /// Number of mma operations performed + using MmaIterations = MatrixShape; + }; + +private: + + static int const kElementsPerAccess = InterleavedN / 4; + +public: + + // + // Derived quantities + // + + struct alignas((kElementsPerAccess * sizeof_bits::value / 8)) AccessType { + Array storage; + }; + + /// Fragment object holding a thread's part of a tile + using Fragment = Array; + +private: + + /// Reference to output tensor + TensorRef ref_; + + /// Row offset index globally + LongIndex global_offset_row_; + + /// Column offset index globally + LongIndex global_offset_col_; + + /// Output tensor size + TensorCoord extent_; + + /// Alpha + float alpha_; + + /// Beta + float beta_; + +public: + + /// Default ctor constructs null iterator + CUTLASS_HOST_DEVICE + MmaTensorOpAccumulatorTileIterator() { } + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaTensorOpAccumulatorTileIterator( + TensorRef const &ref, + int const lane_id, + TensorCoord extent, + float alpha = 1.0f, + float beta = 0.0f + ): + ref_(ref), + extent_(extent), + alpha_(alpha), + beta_(beta) { + + int quad = (lane_id >> 2); + int lane_in_quad = (lane_id & 3); + + global_offset_row_ = quad; + + global_offset_col_ = lane_in_quad * kElementsPerAccess; + } + + /// Adds a pointer offset to internal pointer(s) to advance through memory + CUTLASS_HOST_DEVICE + MmaTensorOpAccumulatorTileIterator &add_pointer_offset(LongIndex offset) { + ref_.add_pointer_offset(offset); + return *this; + } + + /// Advances an iterator along logical dimensions of matrix in units of whole tiles + CUTLASS_HOST_DEVICE + MmaTensorOpAccumulatorTileIterator &add_tile_offset(MatrixCoord const &tile_offset) { + + global_offset_row_ += tile_offset.row() * Shape::kRow; + + global_offset_col_ += tile_offset.column() * Shape::kColumn; + + return *this; + } + + /// Advances the iterator along the advance dimension + CUTLASS_HOST_DEVICE + MmaTensorOpAccumulatorTileIterator & operator++() { + // deliberate no-op + return *this; + } + + /// Advances the iterator along the advance dimension + CUTLASS_HOST_DEVICE + MmaTensorOpAccumulatorTileIterator & operator--() { + // deliberate no-op + return *this; + } + + ///< advances in units of whole tiles along the logical coordinate space of the tensor + CUTLASS_DEVICE + MmaTensorOpAccumulatorTileIterator & operator+=(TensorCoord const &tile_offset) { + add_tile_offset(tile_offset); + return *this; + } + + ///< advances in units of whole tiles along the logical coordinate space of the tensor + CUTLASS_DEVICE + MmaTensorOpAccumulatorTileIterator & operator-=(TensorCoord const &tile_offset) { + add_tile_offset(-tile_offset); + return *this; + } + + /// Loads a fragment from memory at the location pointed to by the iterator. + CUTLASS_HOST_DEVICE + void load(Fragment &frag) const { + load_with_pointer_offset(frag); + } + + /// Loads a fragment from memory with additional logical offset + CUTLASS_DEVICE + void load_with_pointer_offset( + Fragment &frag, ///< fragment to load from the tensor + Index pointer_offset) const { ///< loads a tile with a linear offset + + TensorRef offset_ref(ref_); + offset_ref.add_pointer_offset(pointer_offset); + + AccessType* frag_ptr = reinterpret_cast(&frag); + + CUTLASS_PRAGMA_UNROLL + for (int mma_n = 0; mma_n < Policy::MmaIterations::kN; ++mma_n) { + CUTLASS_PRAGMA_UNROLL + for (int mma_m = 0; mma_m < Policy::MmaIterations::kM; ++mma_m) { + int accum_m = mma_m * InstructionShape::kM; + int accum_n = mma_n * InstructionShape::kN; + + int idx = mma_m + mma_n * Policy::MmaIterations::kM; + + AccessType* access_ptr = reinterpret_cast(offset_ref.data() + + accum_m * offset_ref.stride(0) + accum_n); + + frag_ptr[idx] = access_ptr[0]; + } + } + } + + /// Loads a fragment from memory with additional logical offset + CUTLASS_DEVICE + void load_with_byte_offset( + Fragment &frag, ///< fragment to load from the tensor + Index byte_offset) const { ///< loads a tile with a linear offset + + load_with_pointer_offset(byte_offset / sizeof(Element)); + } + + /// Loads a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void load( + Fragment &frag, ///< fragment to load from the tensor + TensorCoord const &tile_offset) const { ///< loads a tile with a logical offset in units of whole tiles + + load(frag, tile_offset, 0); + } + + /// Loads a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void load( + Fragment &frag, ///< fragment to load from the tensor + TensorCoord const &tile_offset, ///< loads a tile with a logical offset in units of whole tiles + Index pointer_offset) const { ///< loads a tile with a logical offset AND a pointer offset + + load_with_pointer_offset(frag, ref_.offset(tile_offset) + pointer_offset); + } + + /// Stores a fragment to memory + CUTLASS_HOST_DEVICE + void store(Fragment const &frag) const { + store_with_pointer_offset(frag, 0); + } + + /// Stores a fragment to memory with additional pointer offset + CUTLASS_DEVICE + void store_with_pointer_offset( + Fragment const &frag, ///< fragment to store from the tensor + Index pointer_offset) const { ///< store a tile with a linear offset + + TensorRef offset_ref(ref_); + offset_ref.add_pointer_offset(pointer_offset); + + Array output_frag_f; + Array output_frag; + + LongIndex pq = extent_.h() * extent_.w(); + + LongIndex extent_row = extent_.n() * pq; + LongIndex extent_col = extent_.c(); + + LongIndex k_major = (global_offset_col_ / InterleavedN) * pq; + Index k_minor = global_offset_col_ % InterleavedN; + LongIndex k_offset = k_major * InterleavedN + k_minor; + LongIndex k_offset_delta = pq * InterleavedN; + + LongIndex stride_n = pq * extent_.c(); + + Index n; + LongIndex pq_rem; + + unsigned int pq_mul, pq_shr; + find_divisor(pq_mul, pq_shr, pq); + + if(beta_ == 0.0f) { + CUTLASS_PRAGMA_UNROLL + for(int i = 0; i < frag.size(); ++i) { + output_frag_f[i] = frag[i]; + } + + if(InstructionShape::kM == Policy::kStridedPerSTG) { + CUTLASS_PRAGMA_UNROLL + for(int i = 0; i < frag.size(); ++i) { + output_frag[i] = (Element)(output_frag_f[i] * alpha_); + } + } else { + CUTLASS_PRAGMA_UNROLL + for(int i = 0; i < frag.size(); ++i) { + int map_i = (i / (16 * Policy::kPackedFactor)) * (16 * Policy::kPackedFactor) + + (i % (8 * Policy::kPackedFactor)) / 2 * 4 + + (i % (8 * Policy::kPackedFactor)) % 2 + + (i / (8 * Policy::kPackedFactor)) % 2 * 2; + output_frag[i] = (Element)(output_frag_f[map_i] * alpha_); + } + } + + AccessType const *frag_ptr = reinterpret_cast(&output_frag); + + CUTLASS_PRAGMA_UNROLL + for (int mma_m = 0; mma_m < Policy::MmaIterations::kRow; ++mma_m) { + int accum_m = mma_m * Policy::kStridedPerSTG; + + fast_divmod(n, pq_rem, global_offset_row_ + accum_m, pq, pq_mul, pq_shr); + LongIndex offset_m = n * stride_n + k_offset + pq_rem * InterleavedN; + + CUTLASS_PRAGMA_UNROLL + for (int mma_n = 0; mma_n < Policy::MmaIterations::kColumn; ++mma_n) { + + int accum_n = mma_n * InterleavedN; + + int idx = mma_n + mma_m * Policy::MmaIterations::kColumn; + + if((global_offset_row_ + accum_m < extent_row) && (global_offset_col_ + accum_n < extent_col)) { + AccessType* access_ptr = reinterpret_cast(offset_ref.data() + + offset_m + mma_n * k_offset_delta); + + access_ptr[0] = frag_ptr[idx]; + } + } + } + } else { + if(InstructionShape::kM == Policy::kStridedPerSTG) { + CUTLASS_PRAGMA_UNROLL + for(int i = 0; i < frag.size(); ++i) { + output_frag_f[i] = frag[i]; + } + } else { + CUTLASS_PRAGMA_UNROLL + for(int i = 0; i < frag.size(); ++i) { + int map_i = (i / (16 * Policy::kPackedFactor)) * (16 * Policy::kPackedFactor) + + (i % (8 * Policy::kPackedFactor)) / 2 * 4 + + (i % (8 * Policy::kPackedFactor)) % 2 + + (i / (8 * Policy::kPackedFactor)) % 2 * 2; + output_frag_f[i] = frag[map_i]; + } + } + + AccessType const *frag_ptr = reinterpret_cast(&output_frag); + + Array ref_frag; + AccessType *ref_frag_ptr = reinterpret_cast(&ref_frag); + + CUTLASS_PRAGMA_UNROLL + for (int mma_m = 0; mma_m < Policy::MmaIterations::kRow; ++mma_m) { + int accum_m = mma_m * Policy::kStridedPerSTG; + + fast_divmod(n, pq_rem, global_offset_row_ + accum_m, pq, pq_mul, pq_shr); + LongIndex offset_m = n * stride_n + k_offset + pq_rem * InterleavedN; + + CUTLASS_PRAGMA_UNROLL + for (int mma_n = 0; mma_n < Policy::MmaIterations::kColumn; ++mma_n) { + + int accum_n = mma_n * InterleavedN; + + int idx = mma_n + mma_m * Policy::MmaIterations::kColumn; + + if((global_offset_row_ + accum_m < extent_row) && (global_offset_col_ + accum_n < extent_col)) { + AccessType* access_ptr = reinterpret_cast(offset_ref.data() + + offset_m + mma_n * k_offset_delta); + + ref_frag_ptr[0] = access_ptr[0]; + + CUTLASS_PRAGMA_UNROLL + for(int i = 0; i < kElementsPerAccess; ++i) { + output_frag[idx * kElementsPerAccess + i] = Element(alpha_ * output_frag_f[idx * kElementsPerAccess + i] + + beta_ * ref_frag[i]); + } + + access_ptr[0] = frag_ptr[idx]; + } + } } } } diff --git a/include/cutlass/gemm/warp/mma_tensor_op_tile_iterator_sm70.h b/include/cutlass/gemm/warp/mma_tensor_op_tile_iterator_sm70.h index ed6384f05..c57cc6a8d 100644 --- a/include/cutlass/gemm/warp/mma_tensor_op_tile_iterator_sm70.h +++ b/include/cutlass/gemm/warp/mma_tensor_op_tile_iterator_sm70.h @@ -2243,6 +2243,847 @@ class MmaVoltaTensorOpMultiplicandTileIterator< } }; +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Tile iterator specialized for 'TN' arrangement +template < + /// Size of the matrix to load (concept: MatrixShape) + typename Shape_, + /// Operand identity + Operand Operand_, + /// Data type of A elements + typename Element_, + /// Layout of matrix operand + typename Layout_, + /// Shape of one matrix production operation (concept: MatrixShape) + typename InstructionShape_, + /// Delta between *MMA operations (in units of *MMA operations, concept: + /// MatrixShape) + int OpDelta_, + /// Number of threads participating in one matrix operation + int Threads = 32, + /// Number of partitions along K dimension + int PartitionsK_ = 1> +class MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner { + public: + + /// Shape of tile to load (concept: MatrixShape) + using Shape = Shape_; + + /// Operand tag + static Operand const kOperand = Operand_; + + /// Basic check + static_assert(kOperand == Operand::kA || kOperand== Operand::kB, + "MmaVoltaTensorOpMultiplicandIterator may only be instantiated for A or B operands to warp-level Mma."); + + /// Element type + using Element = Element_; + + /// Layout of source tile + using Layout = Layout_; + + /// Shape of one matrix product operation (concept: MatrixShape) + using InstructionShape = InstructionShape_; + + /// Delta between *MMA operations (in units of *MMA operations, concept: MatrixShape) + static int const kOpDelta = OpDelta_; + + /// Number of participating threads + static int const kThreads = 32; + + /// TensorRef type for loading element from a tensor + using TensorRef = TensorRef; + + /// Index type + using Index = typename TensorRef::Index; + + /// Long Index type + using LongIndex = typename TensorRef::LongIndex; + + /// Coordinate for an element in the tensor + using TensorCoord = typename TensorRef::TensorCoord; + + /// Number of elements accessed per Shared Memory load + static int const kElementsPerAccess = 4; + +private: + + static int const kInterleavedTileRows = 32; + static int const kInterleavedTileColumns = 32; + static int const kInstructionsPerTile = 2; + + /// Rounded up instruction counts + using TileCount = MatrixShape< + Shape::kRow / kInterleavedTileRows, + Shape::kColumn / kInterleavedTileColumns + >; + + using FragmentCount = MatrixShape< + TileCount::kRow * kInstructionsPerTile, + TileCount::kColumn * kInstructionsPerTile + >; + +public: + + // + // Derived quantities + // + + /// Fragment object holding a thread's part of a tile + using Fragment = Array< + Element, + (kOperand == Operand::kA ? FragmentCount::kRow : FragmentCount::kColumn) * kElementsPerAccess + >; + + /// Memory access type + using AccessType = AlignedArray; + +private: + + /// Underlying tensor reference + TensorRef ref_; + + /// Extent of tensor + MatrixCoord extent_; + + /// Origin + MatrixCoord origin_; + + /// Used to conditionally enable extents checking + bool divisible_; + +public: + + /// Default ctor constructs null iterator + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner(): divisible_(true) { } + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner( + TensorRef const &ref, + int lane_id + ): + ref_(ref), extent_(Shape::kRow, Shape::kColumn), divisible_(true) { + + int quad_id = lane_id / 4; + int lane_in_quad = (lane_id % 4); + + if (kOperand == Operand::kA) { + + int row_idx = ((quad_id & 1) + ((quad_id & 4) / 2)) * 4 * kInstructionsPerTile + lane_in_quad; + int col_idx = 0; + + origin_ = MatrixCoord(row_idx, col_idx); + } + else { + + int row_idx = 0; + int col_idx = (quad_id / 2) * 4 * kInstructionsPerTile + lane_in_quad; + + origin_ = MatrixCoord(row_idx, col_idx); + } + + ref_.add_coord_offset(origin_); + } + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner( + TensorRef const &ref, + TensorCoord extent, + int lane_id + ): ref_(ref), extent_(extent), divisible_(false) { + + int quad_id = lane_id / 4; + int lane_in_quad = (lane_id % 4); + + if (kOperand == Operand::kA) { + + int row_idx = ((quad_id & 1) + ((quad_id & 4) / 2)) * 4 * kInstructionsPerTile + lane_in_quad; + int col_idx = 0; + + origin_ = MatrixCoord(row_idx, col_idx); + } + else { + + int row_idx = 0; + int col_idx = (quad_id / 2) * 4 * kInstructionsPerTile + lane_in_quad; + + origin_ = MatrixCoord(row_idx, col_idx); + } + + #if defined(__CUDA_ARCH__) + __syncthreads(); + #endif + + ref_.add_coord_offset(origin_); + } + + /// Adds a pointer offset to internal pointer(s) to advance through memory + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner &add_pointer_offset(LongIndex offset) { + + ref_.add_pointer_offset(offset); + + return *this; + } + + /// Advances an iterator along logical dimensions of matrix in units of whole tiles + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner &add_tile_offset(TensorCoord const &tile_offset) { + + TensorCoord coord_offset(tile_offset.row() * Shape::kRow, tile_offset.column() * Shape::kColumn); + origin_ += coord_offset; + + ref_.add_coord_offset(coord_offset); + + return *this; + } + + /// Advances the iterator along the advance dimension + CUTLASS_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner & operator++() { + + if (kOperand == Operand::kA) { + add_tile_offset({0, 1}); + } + else { + add_tile_offset({1, 0}); + } + + return *this; + } + + /// Advances the iterator along the advance dimension + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner & operator--() { + + if (kOperand == Operand::kA) { + add_tile_offset({0, -1}); + } + else { + add_tile_offset({-1, 0}); + } + + return *this; + } + + ///< advances in units of whole tiles along the logical coordinate space of the tensor + CUTLASS_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner & operator+=(TensorCoord const &tile_offset) { + add_tile_offset(tile_offset); + return *this; + } + + ///< advances in units of whole tiles along the logical coordinate space of the tensor + CUTLASS_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner & operator-=(TensorCoord const &tile_offset) { + add_tile_offset(-tile_offset); + return *this; + } + + /// Loads a fragment from memory at the location pointed to by the iterator. + CUTLASS_HOST_DEVICE + void load(Fragment &frag) const { + + load_with_pointer_offset(frag, 0); + } + + /// Loads a fragment from memory with additional logical offset + CUTLASS_DEVICE + void load_with_pointer_offset( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a linear offset + Index pointer_offset) const { + + AccessType *frag_ptr = reinterpret_cast(&frag); + AccessType const *access_ptr = reinterpret_cast(ref_.data()); + int ldm = ref_.stride()[0]; + + if (kOperand == Operand::kA) { + + CUTLASS_PRAGMA_UNROLL + for (int idx = 0; idx < FragmentCount::kRow; ++idx) { + + int tile_idx = idx / 2; + int quad_idx = idx % 2; + + int row_offset = tile_idx * kInterleavedTileRows + quad_idx * 4; + frag_ptr[idx] = access_ptr[row_offset * ldm / kElementsPerAccess]; + } + } + else { + CUTLASS_PRAGMA_UNROLL + for (int idx = 0; idx < FragmentCount::kColumn; ++idx) { + + int tile_idx = idx / 2; + int quad_idx = idx % 2; + + int col_offset = tile_idx * kInterleavedTileColumns + quad_idx * 4; + frag_ptr[idx] = access_ptr[col_offset * ldm / kElementsPerAccess]; + } + } + } + + /// Loads a fragment from memory with additional logical offset + CUTLASS_DEVICE + void load_with_byte_offset( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a linear offset + Index byte_offset) const { + + load_with_pointer_offset(frag, byte_offset * 8 / sizeof_bits::value); + } + + /// Loads a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void load( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a logical offset in units of whole tiles + TensorCoord const &tile_offset) const { + + TensorCoord coord_offset(tile_offset.row() * Shape::kRow, tile_offset.column() * Shape::kColumn); + + load_with_pointer_offset(frag, ref_.offset(coord_offset)); + } + + /// Loads a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void load( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a logical offset in units of whole tiles + TensorCoord const &tile_offset, + /// loads a tile with a logical offset AND a pointer offset + Index pointer_offset) const { + + TensorCoord coord_offset(tile_offset.row() * Shape::kRow, tile_offset.column() * Shape::kColumn); + + load_with_pointer_offset(frag, ref_.offset(coord_offset) + pointer_offset); + } + + /// Loads a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void load_with_byte_offset( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a logical offset in units of whole tiles + TensorCoord const &tile_offset, + /// loads a tile with a logical offset AND a pointer offset + Index byte_offset) const { + + TensorCoord coord_offset(tile_offset.row() * Shape::kRow, tile_offset.column() * Shape::kColumn); + + load_with_pointer_offset(frag, ref_.offset(coord_offset) + byte_offset * 8 / sizeof_bits::value); + } + + /// Notify the iterator which k-group it is currently pointing to. + /// + /// This does not advance the iterator. Rather, it overrides its internal + /// tracking with constant-valued k-group index to enable the compiler to + /// fold constants and achieve more efficient code. + /// + /// This is used by some nontrivial permuted layouts. + CUTLASS_DEVICE + void set_kgroup_index(int k_group) { + // no operation + } +}; + + +/// Tile iterator specialized for 'NT' arrangement +template < + /// Size of the matrix to load (concept: MatrixShape) + typename Shape_, + /// Operand identity + Operand Operand_, + /// Data type of A elements + typename Element_, + /// Layout of matrix operand + typename Layout_, + /// Shape of one matrix production operation (concept: MatrixShape) + typename InstructionShape_, + /// Delta between *MMA operations (in units of *MMA operations, concept: + /// MatrixShape) + int OpDelta_, + /// Number of threads participating in one matrix operation + int Threads = 32, + /// Number of partitions along K dimension + int PartitionsK_ = 1> +class MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter { + public: + + /// Shape of tile to load (concept: MatrixShape) + using Shape = Shape_; + + /// Operand tag + static Operand const kOperand = Operand_; + + /// Basic check + static_assert(kOperand == Operand::kA || kOperand== Operand::kB, + "MmaVoltaTensorOpMultiplicandIterator may only be instantiated for A or B operands to warp-level Mma."); + + /// Element type + using Element = Element_; + + /// Layout of source tile + using Layout = Layout_; + + /// Shape of one matrix product operation (concept: MatrixShape) + using InstructionShape = InstructionShape_; + + /// Delta between *MMA operations (in units of *MMA operations, concept: MatrixShape) + static int const kOpDelta = OpDelta_; + + /// Number of participating threads + static int const kThreads = 32; + + /// TensorRef type for loading element from a tensor + using TensorRef = TensorRef; + + /// Index type + using Index = typename TensorRef::Index; + + /// Long Index type + using LongIndex = typename TensorRef::LongIndex; + + /// Coordinate for an element in the tensor + using TensorCoord = typename TensorRef::TensorCoord; + + /// Number of elements accessed per Shared Memory load + static int const kElementsPerAccess = 4; + +private: + + static int const kInterleavedTileRows = 32; + static int const kInterleavedTileColumns = 32; + static int const kInstructionsPerTile = 2; + + /// Rounded up instruction counts + using TileCount = MatrixShape< + Shape::kRow / kInterleavedTileRows, + Shape::kColumn / kInterleavedTileColumns + >; + + using FragmentCount = MatrixShape< + TileCount::kRow * kInstructionsPerTile, + TileCount::kColumn * kInstructionsPerTile + >; + +public: + + // + // Derived quantities + // + + /// Fragment object holding a thread's part of a tile + using Fragment = Array< + Element, + (kOperand == Operand::kA ? FragmentCount::kRow : FragmentCount::kColumn) * kElementsPerAccess + >; + + /// Memory access type + using AccessType = AlignedArray; + +private: + + /// Underlying tensor reference + TensorRef ref_; + + /// Extent of tensor + MatrixCoord extent_; + + /// Origin + MatrixCoord origin_; + + /// Used to conditionally enable extents checking + bool divisible_; + +public: + + /// Default ctor constructs null iterator + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter(): divisible_(true) { } + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter( + TensorRef const &ref, + int lane_id + ): + ref_(ref), extent_(Shape::kRow, Shape::kColumn), divisible_(true) { + + int quad_id = lane_id / 4; + int lane_in_quad = (lane_id % 4); + + if (kOperand == Operand::kA) { + + int row_idx = ((quad_id & 1) + ((quad_id & 4) / 2)) * 4 * kInstructionsPerTile; + int col_idx = lane_in_quad; + + origin_ = MatrixCoord(row_idx, col_idx); + } + else { + + int row_idx = lane_in_quad; + int col_idx = (quad_id / 2) * 4 * kInstructionsPerTile; + + origin_ = MatrixCoord(row_idx, col_idx); + } + + ref_.add_coord_offset(origin_); + } + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter( + TensorRef const &ref, + TensorCoord extent, + int lane_id + ): ref_(ref), extent_(extent), divisible_(false) { + + int quad_id = lane_id / 4; + int lane_in_quad = (lane_id % 4); + + if (kOperand == Operand::kA) { + + int row_idx = ((quad_id & 1) + ((quad_id & 4) / 2)) * 4 * kInstructionsPerTile; + int col_idx = lane_in_quad; + + origin_ = MatrixCoord(row_idx, col_idx); + } + else { + + int row_idx = lane_in_quad; + int col_idx = (quad_id / 2) * 4 * kInstructionsPerTile; + + origin_ = MatrixCoord(row_idx, col_idx); + } + + #if defined(__CUDA_ARCH__) + __syncthreads(); + #endif + + ref_.add_coord_offset(origin_); + } + + /// Adds a pointer offset to internal pointer(s) to advance through memory + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter &add_pointer_offset(LongIndex offset) { + + ref_.add_pointer_offset(offset); + + return *this; + } + + /// Advances an iterator along logical dimensions of matrix in units of whole tiles + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter &add_tile_offset(TensorCoord const &tile_offset) { + + TensorCoord coord_offset(tile_offset.row() * Shape::kRow, tile_offset.column() * Shape::kColumn); + origin_ += coord_offset; + + ref_.add_coord_offset(coord_offset); + + return *this; + } + + /// Advances the iterator along the advance dimension + CUTLASS_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter & operator++() { + + if (kOperand == Operand::kA) { + add_tile_offset({0, 1}); + } + else { + add_tile_offset({1, 0}); + } + + return *this; + } + + /// Advances the iterator along the advance dimension + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter & operator--() { + + if (kOperand == Operand::kA) { + add_tile_offset({0, -1}); + } + else { + add_tile_offset({-1, 0}); + } + + return *this; + } + + ///< advances in units of whole tiles along the logical coordinate space of the tensor + CUTLASS_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter & operator+=(TensorCoord const &tile_offset) { + add_tile_offset(tile_offset); + return *this; + } + + ///< advances in units of whole tiles along the logical coordinate space of the tensor + CUTLASS_DEVICE + MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter & operator-=(TensorCoord const &tile_offset) { + add_tile_offset(-tile_offset); + return *this; + } + + /// Loads a fragment from memory at the location pointed to by the iterator. + CUTLASS_HOST_DEVICE + void load(Fragment &frag) const { + + load_with_pointer_offset(frag, 0); + } + + /// Loads a fragment from memory with additional logical offset + CUTLASS_DEVICE + void load_with_pointer_offset( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a linear offset + Index pointer_offset) const { + + AccessType *frag_ptr = reinterpret_cast(&frag); + AccessType const *access_ptr = reinterpret_cast(ref_.data()); + int ldm = ref_.stride()[0]; + + if (kOperand == Operand::kA) { + + CUTLASS_PRAGMA_UNROLL + for (int idx = 0; idx < FragmentCount::kRow; ++idx) { + + int tile_idx = idx / 2; + int quad_idx = idx % 2; + + int row_offset = tile_idx * kInterleavedTileRows; + frag_ptr[idx] = access_ptr[row_offset / kElementsPerAccess + quad_idx]; + } + } + else { + CUTLASS_PRAGMA_UNROLL + for (int idx = 0; idx < FragmentCount::kColumn; ++idx) { + + int tile_idx = idx / 2; + int quad_idx = idx % 2; + + int col_offset = tile_idx * kInterleavedTileColumns; + frag_ptr[idx] = access_ptr[col_offset / kElementsPerAccess + quad_idx]; + } + } + } + + /// Loads a fragment from memory with additional logical offset + CUTLASS_DEVICE + void load_with_byte_offset( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a linear offset + Index byte_offset) const { + + load_with_pointer_offset(frag, byte_offset * 8 / sizeof_bits::value); + } + + /// Loads a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void load( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a logical offset in units of whole tiles + TensorCoord const &tile_offset) const { + + TensorCoord coord_offset(tile_offset.row() * Shape::kRow, tile_offset.column() * Shape::kColumn); + + load_with_pointer_offset(frag, ref_.offset(coord_offset)); + } + + /// Loads a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void load( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a logical offset in units of whole tiles + TensorCoord const &tile_offset, + /// loads a tile with a logical offset AND a pointer offset + Index pointer_offset) const { + + TensorCoord coord_offset(tile_offset.row() * Shape::kRow, tile_offset.column() * Shape::kColumn); + + load_with_pointer_offset(frag, ref_.offset(coord_offset) + pointer_offset); + } + + /// Loads a fragment from memory with logical offset in units of whole tiles. + CUTLASS_DEVICE + void load_with_byte_offset( + /// fragment to load from the tensor + Fragment &frag, + /// loads a tile with a logical offset in units of whole tiles + TensorCoord const &tile_offset, + /// loads a tile with a logical offset AND a pointer offset + Index byte_offset) const { + + TensorCoord coord_offset(tile_offset.row() * Shape::kRow, tile_offset.column() * Shape::kColumn); + + load_with_pointer_offset(frag, ref_.offset(coord_offset) + byte_offset * 8 / sizeof_bits::value); + } + + /// Notify the iterator which k-group it is currently pointing to. + /// + /// This does not advance the iterator. Rather, it overrides its internal + /// tracking with constant-valued k-group index to enable the compiler to + /// fold constants and achieve more efficient code. + /// + /// This is used by some nontrivial permuted layouts. + CUTLASS_DEVICE + void set_kgroup_index(int k_group) { + // no operation + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +template < + /// Size of the matrix to load (concept: MatrixShape) + typename Shape_, + /// Data type of elements + typename Element_, + /// Shape of one matrix product operation (concept: MatrixShape) + typename InstructionShape_, + /// Interval between adjacent *MMA instructions (in units of MMA + /// instructions) + int OpDelta_> +class MmaVoltaTensorOpMultiplicandTileIterator< + Shape_, + Operand::kA, + Element_, + cutlass::layout::RowMajor, + InstructionShape_, + OpDelta_, + 32 +> : public MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner< + Shape_, Operand::kA, Element_, cutlass::layout::RowMajor, InstructionShape_, OpDelta_> { + +public: + using Base = MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner< + Shape_, Operand::kA, Element_, cutlass::layout::RowMajor, InstructionShape_, OpDelta_> ; + + using TensorRef = typename Base::TensorRef; + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIterator( + TensorRef const &ref, + int lane_id + ): Base(ref, lane_id) { } + +}; + +template < + /// Size of the matrix to load (concept: MatrixShape) + typename Shape_, + /// Data type of elements + typename Element_, + /// Shape of one matrix product operation (concept: MatrixShape) + typename InstructionShape_, + /// Interval between adjacent *MMA instructions (in units of MMA + /// instructions) + int OpDelta_> +class MmaVoltaTensorOpMultiplicandTileIterator< + Shape_, + Operand::kA, + Element_, + cutlass::layout::ColumnMajor, + InstructionShape_, + OpDelta_, + 32 +> : public MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter< + Shape_, Operand::kA, Element_, cutlass::layout::ColumnMajor, InstructionShape_, OpDelta_> { + +public: + using Base = MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter< + Shape_, Operand::kA, Element_, cutlass::layout::ColumnMajor, InstructionShape_, OpDelta_> ; + + using TensorRef = typename Base::TensorRef; + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIterator( + TensorRef const &ref, + int lane_id + ): Base(ref, lane_id) { } + +}; + +template < + /// Size of the matrix to load (concept: MatrixShape) + typename Shape_, + /// Data type of elements + typename Element_, + /// Shape of one matrix product operation (concept: MatrixShape) + typename InstructionShape_, + /// Interval between adjacent *MMA instructions (in units of MMA + /// instructions) + int OpDelta_> +class MmaVoltaTensorOpMultiplicandTileIterator< + Shape_, Operand::kB, Element_, + cutlass::layout::ColumnMajor, + InstructionShape_, OpDelta_, 32 +> : public MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner< + Shape_, Operand::kB, Element_, cutlass::layout::ColumnMajor, InstructionShape_, OpDelta_> { + +public: + using Base = MmaVoltaTensorOpMultiplicandTileIteratorCanonicalInner< + Shape_, Operand::kB, Element_, cutlass::layout::ColumnMajor, InstructionShape_, OpDelta_>; + + using TensorRef = typename Base::TensorRef; + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIterator( + TensorRef const &ref, + int lane_id + ): Base(ref, lane_id) { } +}; + +template < + /// Size of the matrix to load (concept: MatrixShape) + typename Shape_, + /// Data type of elements + typename Element_, + /// Shape of one matrix product operation (concept: MatrixShape) + typename InstructionShape_, + /// Interval between adjacent *MMA instructions (in units of MMA + /// instructions) + int OpDelta_> +class MmaVoltaTensorOpMultiplicandTileIterator< + Shape_, Operand::kB, Element_, + cutlass::layout::RowMajor, + InstructionShape_, OpDelta_, 32 +> : public MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter< + Shape_, Operand::kB, Element_, cutlass::layout::RowMajor, InstructionShape_, OpDelta_> { + +public: + using Base = MmaVoltaTensorOpMultiplicandTileIteratorCanonicalOuter< + Shape_, Operand::kB, Element_, cutlass::layout::RowMajor, InstructionShape_, OpDelta_>; + + using TensorRef = typename Base::TensorRef; + + /// Constructor from TensorRef + CUTLASS_HOST_DEVICE + MmaVoltaTensorOpMultiplicandTileIterator( + TensorRef const &ref, + int lane_id + ): Base(ref, lane_id) { } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + } // namespace warp } // namespace gemm } // namespace cutlass diff --git a/include/cutlass/layout/tensor.h b/include/cutlass/layout/tensor.h index f3d5a12bf..7f608dcf7 100644 --- a/include/cutlass/layout/tensor.h +++ b/include/cutlass/layout/tensor.h @@ -40,6 +40,7 @@ #endif #include "cutlass/cutlass.h" #include "cutlass/fast_math.h" +#include "cutlass/layout/pitch_linear.h" #include "cutlass/layout/matrix.h" #include "cutlass/coord.h" #include "cutlass/tensor_coord.h" @@ -120,6 +121,12 @@ public: LongIndex(stride_[1] * coord.h()) + LongIndex(stride_[2] * coord.n()); } + + /// Returns the offset of a pitchlinear coordinate in linear memory. + CUTLASS_HOST_DEVICE + LongIndex operator()(PitchLinearCoord coord) const { + return coord.contiguous() + LongIndex(coord.strided() * stride_[2]); + } /// Returns the logical coordinate (n, h, w, c) from a given offset in linear memory. CUTLASS_HOST_DEVICE @@ -182,7 +189,6 @@ public: } }; - ///////////////////////////////////////////////////////////////////////////////////////////////// /// Mapping function for 4-D NCHW tensors. @@ -424,6 +430,14 @@ public: LongIndex(stride_[2] * c_major); } + /// Returns the offset of a pitchlinear coordinate in linear memory. + CUTLASS_HOST_DEVICE + LongIndex operator()(PitchLinearCoord const &coord) const { + return (coord.contiguous() % kInterleave) + + LongIndex((coord.contiguous() / kInterleave) * stride_[2]) + + LongIndex(coord.strided() * kInterleave); + } + /// Returns the stride of the layout CUTLASS_HOST_DEVICE Stride stride() const { diff --git a/include/cutlass/transform/pitch_linear_thread_map.h b/include/cutlass/transform/pitch_linear_thread_map.h index de21ede4e..c19f79cbb 100644 --- a/include/cutlass/transform/pitch_linear_thread_map.h +++ b/include/cutlass/transform/pitch_linear_thread_map.h @@ -340,6 +340,134 @@ struct PitchLinearWarpRakedThreadMap { //////////////////////////////////////////////////////////////////////////////// +/// Policy defining a warp-raked arrangement in which a shape is partitioned into contiguous +/// elements. Warps are arranged based on a stride. +/// +/// This ThreadMap is used by tensor core kernels for NCxHWx layout. +template < + typename Shape_, + int Threads, + typename WarpThreadArrangement_, + int ElementsPerAccess = 1 +> +struct PitchLinearStridedWarpRakedThreadMap { + + /// Tensor coordinate + using TensorCoord = layout::PitchLinearCoord; + + /// Tile shape + using Shape = Shape_; + + /// Number of threads total + static int const kThreads = Threads; + + using WarpThreadArrangement = WarpThreadArrangement_; + + /// Extract vector length from Layout + static int const kElementsPerAccess = ElementsPerAccess; + + /// Base ThreadMap + using BaseThreadMap = PitchLinearWarpRakedThreadMap< + Shape, + kThreads, + WarpThreadArrangement, + kElementsPerAccess + >; + + /// Shape of access by each thread + using ThreadAccessShape = typename BaseThreadMap::ThreadAccessShape; + + + struct Detail { + + using WarpThreadArrangement = WarpThreadArrangement_; + + using WarpAccessIterations = typename BaseThreadMap::Detail::WarpAccessIterations; + + static int const kWarpSize = BaseThreadMap::Detail::kWarpSize; + + static int const kWarpCount = BaseThreadMap::Detail::kWarpCount; + + using ShapeInAccesses = typename BaseThreadMap::Detail::ShapeInAccesses; + + // Divide it into the number of warps, first partitioning the contiguous dimension then the + // stride. + static int const kWarpsContiguous = + (WarpAccessIterations::kContiguous >= kWarpCount + ? kWarpCount + : WarpAccessIterations::kContiguous); + + static int const kWarpsStrided = + (kWarpCount > WarpAccessIterations::kContiguous + ? kWarpCount / kWarpsContiguous + : 1); + + /// Arrangement of warps within a threadblock-scoped tile + using WarpArrangement = layout::PitchLinearShape< + kWarpsContiguous, kWarpsStrided + >; + + }; + + ///< Iterations along each dimension (concept: PitchLinearShape) + using Iterations = layout::PitchLinearShape< + Detail::WarpAccessIterations::kContiguous / Detail::kWarpsContiguous, + Detail::WarpAccessIterations::kStrided / Detail::kWarpsStrided + >; + + static_assert(Iterations::kCount, + "Number of iterations must be non-zero"); + + ///< Delta betweeen accesses (units of elements, concept: PitchLinearShape) + using Delta = typename BaseThreadMap::Delta; + + /// Maps thread ID to a coordinate offset within the tensor's logical coordinate space + CUTLASS_HOST_DEVICE + static TensorCoord initial_offset(int thread_id) { + + int warp_id = (thread_id / Detail::kWarpSize); + int lane_id = (thread_id % Detail::kWarpSize); + + // + // compute warp-level offset + // + + // This is the shape of the entire area covered by a warp's memory access (in units of vectors) + layout::PitchLinearCoord warp_footprint{ + Detail::WarpThreadArrangement::kContiguous * Iterations::kContiguous, + Detail::WarpThreadArrangement::kStrided * Iterations::kStrided + }; + + // This is the offset of a specific warp (in units of vectors) + layout::PitchLinearCoord warp_offset{ + (warp_id % Detail::kWarpsContiguous), + (warp_id / Detail::kWarpsContiguous) + }; + + // This is the offset of a specific thread within a warp (units of vectors) + layout::PitchLinearCoord thread_offset_in_warp{ + lane_id % Detail::WarpThreadArrangement::kContiguous, + lane_id / Detail::WarpThreadArrangement::kContiguous + }; + + // This is the offset of a thread within a threadblock tile (units of vectors) + layout::PitchLinearCoord thread_offset_in_threadblock_tile_vec = + warp_footprint * warp_offset + thread_offset_in_warp; + + // This is the offset of a thread within a threadblock tile (units of elements) + layout::PitchLinearCoord thread_offset_in_threadblock_tile_base{ + thread_offset_in_threadblock_tile_vec.contiguous() * kElementsPerAccess, + thread_offset_in_threadblock_tile_vec.strided() + }; + + return thread_offset_in_threadblock_tile_base; + } + + +}; + +//////////////////////////////////////////////////////////////////////////////// + /// Transpose the existing ThreadMap. For example, interleaved layout is like /// congruous in the global memory and crosswise in the shared memory. We need /// to transpose the coordinates between two. diff --git a/include/cutlass/transform/threadblock/predicated_tile_access_iterator.h b/include/cutlass/transform/threadblock/predicated_tile_access_iterator.h index 7e34b546b..7dce3228e 100644 --- a/include/cutlass/transform/threadblock/predicated_tile_access_iterator.h +++ b/include/cutlass/transform/threadblock/predicated_tile_access_iterator.h @@ -500,7 +500,7 @@ class PredicatedTileAccessIterator -class RegularTileAccessIterator< - Shape_, Element_, - layout::TensorOpMultiplicandRowMajorInterleaved::value, - InterleavedK>, - AdvanceRank, ThreadMap_, Alignment> { - public: - static_assert( - AdvanceRank == 0 || AdvanceRank == 1, - "Specialization for pitch-linear iterator may along advance along the " - "contiguous(rank=0) or strided(rank=1) dimension."); - - using Shape = Shape_; - using Element = Element_; - using Layout = - layout::TensorOpMultiplicandRowMajorInterleaved::value, - InterleavedK>; - static int const kAdvanceRank = AdvanceRank; - static int const kAlignment = Alignment; - - using Index = typename Layout::Index; - using LongIndex = typename Layout::LongIndex; - - using TensorRef = TensorRef; - using TensorCoord = typename Layout::TensorCoord; - - using ThreadMap = ThreadMap_; - - /// Internal details made public to facilitate introspection - struct Detail { - /// This iterator is specialized for an access size that is 128 bits in - /// length. - static int const kAccessSizeInBits = 128; - - static_assert(sizeof_bits::value * ThreadMap::kElementsPerAccess == - kAccessSizeInBits, - "This iterator requires a policy whose access size is 128bs"); - }; - - private: - - /// Element type per access - using AccessType = Array; - - private: - // - // Data members - // - - /// Internal pointer to first access of tile - AccessType *pointer_; - - /// Internal byte offset - Index byte_offset_; - - /// Iteration in the contiguous dimension - int iteration_contiguous_; - - /// Iteration in the strided dimension - int iteration_strided_; - - public: - /// Construct a TileIterator with zero threadblock offset - CUTLASS_HOST_DEVICE - RegularTileAccessIterator(TensorRef ref, ///< Pointer to start of tensor - int thread_id ///< ID of each participating thread - ) - : byte_offset_(0) { - layout::PitchLinearCoord thread_offset_base = - ThreadMap::initial_offset(thread_id); - - // initialize pointer - pointer_ = reinterpret_cast( - ref.data() + ref.offset(thread_offset_base)); - - set_iteration_index(0); - } - - /// Overrides the internal iteration index - CUTLASS_HOST_DEVICE - void set_iteration_index(int index) { - iteration_contiguous_ = index % ThreadMap::Iterations::kContiguous; - iteration_strided_ = index / ThreadMap::Iterations::kContiguous; - } - - /// Adds a pointer offset in units of Element - CUTLASS_HOST_DEVICE - void add_pointer_offset(LongIndex pointer_offset) { - byte_offset_ += pointer_offset * sizeof(Element); - } - - /// Returns a pointer - CUTLASS_HOST_DEVICE - AccessType *get() const { - AccessType *access_ptr = pointer_; - - int access_offset = - (iteration_strided_ * ThreadMap::Delta::kStrided * Layout::kInterleavedK + - iteration_contiguous_ * ThreadMap::Delta::kContiguous) / ThreadMap::kElementsPerAccess; - - char *access_byte_ptr = - reinterpret_cast(access_ptr + access_offset); - - return reinterpret_cast(access_byte_ptr + byte_offset_); - } - - /// Advances to the next tile in memory. - CUTLASS_HOST_DEVICE - RegularTileAccessIterator &operator++() { - ++iteration_contiguous_; - - if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) - return *this; - - // Enter here only if (iteration_contiguous_ == - // ThreadMap::Iteration::kContiguous) - iteration_contiguous_ = 0; - ++iteration_strided_; - - if (iteration_strided_ < ThreadMap::Iterations::kStrided) { - return *this; - } - - // Enter here only if (iteration_strided_ == ThreadMap::Iteration::kStrided) - // which means we enter the next tile. - iteration_strided_ = 0; - - return *this; - } - - /// Advances to the next tile in memory. - CUTLASS_HOST_DEVICE - RegularTileAccessIterator operator++(int) { - RegularTileAccessIterator prev(*this); - this->operator++(); - - return prev; - } - - /// Adds a tile offset - CUTLASS_DEVICE - void add_tile_offset(TensorCoord const &coord) { - add_pointer_offset(coord.contiguous() * Shape::kCount); - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -/// Tile iterator specialized for k interleaved arrangements for TensorOps -/// -/// -/// Satisfies: ForwardTileIteratorConcept | -/// ReadableContiguousTileIteratorConcept | -/// WriteableContiguousTileIteratorConcept -/// - -template -class RegularTileAccessIterator< - Shape_, Element_, - layout::TensorOpMultiplicandColumnMajorInterleaved::value, - InterleavedK>, - AdvanceRank, ThreadMap_, Alignment> { - - public: - static_assert( - AdvanceRank == 0 || AdvanceRank == 1, - "Specialization for pitch-linear iterator may along advance along the " - "contiguous(rank=0) or strided(rank=1) dimension."); - - using Shape = Shape_; - using Element = Element_; - using Layout = - layout::TensorOpMultiplicandColumnMajorInterleaved::value, - InterleavedK>; - static int const kAdvanceRank = AdvanceRank; - static int const kAlignment = Alignment; - - using Index = typename Layout::Index; - using LongIndex = typename Layout::LongIndex; - - using TensorRef = TensorRef; - using TensorCoord = typename Layout::TensorCoord; - - using ThreadMap = ThreadMap_; - - /// Underlying iterator type - using UnderlyingIterator = RegularTileAccessIterator< - cutlass::MatrixShape, - Element, - layout::TensorOpMultiplicandRowMajorInterleaved::value, InterleavedK>, - (kAdvanceRank == 1 ? 0 : 1), - ThreadMap - >; - - private: - - /// Element type per access - using AccessType = Array; - - private: - - /// Underlying iterator - UnderlyingIterator iterator_; - - public: - /// Construct a TileIterator with zero threadblock offset - CUTLASS_HOST_DEVICE - RegularTileAccessIterator(TensorRef ref, ///< Pointer to start of tensor - int thread_id ///< ID of each participating thread - ) - : iterator_({ref.data(), ref.stride()}, thread_id) {} - - /// Overrides the internal iteration index - CUTLASS_HOST_DEVICE - void set_iteration_index(int index) { - iterator_.set_iteration_index(index); - } - - /// Adds a pointer offset in units of Element - CUTLASS_HOST_DEVICE - void add_pointer_offset(LongIndex pointer_offset) { - iterator_.add_pointer_offset(pointer_offset); - } - - /// Returns a pointer - CUTLASS_HOST_DEVICE - AccessType *get() const { - return iterator_.get(); - } - - /// Advances to the next tile in memory. - CUTLASS_HOST_DEVICE - RegularTileAccessIterator &operator++() { - ++iterator_; - return *this; - } - - /// Advances to the next tile in memory. - CUTLASS_HOST_DEVICE - RegularTileAccessIterator operator++(int) { - RegularTileAccessIterator prev(*this); - ++iterator_; - - return prev; - } - - /// Adds a tile offset - CUTLASS_DEVICE - void add_tile_offset(TensorCoord const &coord) { - iterator_.add_tile_offset({coord.strided(), coord.contiguous()}); - } -}; - -//////////////////////////////////////////////////////////////////////////////// - } // namespace threadblock } // namespace transform } // namespace cutlass diff --git a/media/docs/functionality.md b/media/docs/functionality.md index 3c416b3e9..77f1ba142 100644 --- a/media/docs/functionality.md +++ b/media/docs/functionality.md @@ -44,6 +44,28 @@ Hyperlinks to relevant unit tests demonstrate how specific template instances ma | **SpTensorOp** | 80 | 11.1+ | `s4 * s4 + s32 => {s4, s32}` | {N,T} x {N,T} => {N,T} | [example](/test/unit/gemm/device/gemm_s4t_s4n_s32t_tensor_op_s32_sparse_sm80.cu) | +## Device-level Implicit GEMM convolution + +The following table summarizes device-level implicit GEMM convolution kernels in CUTLASS, organized by opcode class, data type, and layout. +Hyperlinks to relevant conv2d fprop unit tests demonstrate how specific template instances may be defined. +One can find and/or create equivalent dgrad and wgrad convolutional operators. + +|**Opcode Class** | **Compute Capability** | **CUDA Toolkit** | **Data Type** | **Layouts** | **Unit Test** | +|-----------------|------------------------|------------------|--------------------------------|------------------|------------------| +| **Simt** | 50,60,61,70,75 | 9.2+ | `f32 * f32 + f32 => f32` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm50.cu) | +| **Simt** | 50,60,61,70,75 | 9.2+ | `cf32 * cf32 + cf32 => cf32` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu) | +| **TensorOp** | 70 | 10.1+ | `f16 * f16 + f32 => {f16, f32}`| NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu) | +| **TensorOp** | 75 | 10.2+ | `f16 * f16 + f32 => {f16, f32}`| NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu) | +| **TensorOp** | 75 | 10.2+ | `s8 * s8 + s32 => {s32, s8}` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm75.cu) | +| **Simt** | 80 | 11.0+ | `f32 * f32 + f32 => f32` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu) | +| **Simt** | 80 | 11.0+ | `cf32 * cf32 + cf32 => cf32` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu) | +| **TensorOp** | 80 | 11.0+ | `f16 * f16 + f32 => {f16, f32}`| NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu) | +| **TensorOp** | 80 | 11.0+ | `f16 * f16 + f16 => f16` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu) | +| **TensorOp** | 80 | 11.0+ | `tf32 * tf32 + f32 => f32` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu) | +| **TensorOp** | 80 | 11.0+ | `s8 * s8 + s32 => {s32, s8}` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm80.cu) | +| **TensorOp** | 80 | 11.0+ | `s4 * s4 + s32 => {s32, s4}` | NHWC | [example](/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm80.cu) | + + ## Warp-level Matrix Multiply with Tensor Cores diff --git a/media/docs/implicit_gemm_convolution.md b/media/docs/implicit_gemm_convolution.md new file mode 100644 index 000000000..34102918d --- /dev/null +++ b/media/docs/implicit_gemm_convolution.md @@ -0,0 +1,779 @@ +![ALT](/media/images/gemm-hierarchy-with-epilogue-no-labels.png "CUTLASS Implicit GEMM API") + +[README](/README.md#documentation) > **Implicit GEMM Convolution** + +# CUTLASS Convolution + +Implicit GEMM is the formulation of a convolution operation as a GEMM (generalized matrix-matrix +product). Convolution takes an activation tensor and applies a sliding filter on it to produce an +output tensor. + +## Introduction + +This release of CUTLASS contains several artifacts related to convolution. + +- [**Implicit GEMM Algorithm**](implicit_gemm_convolution.md#implicit-gemm-algorithm) +- [**CUTLASS Convolution Implementation**](implicit_gemm_convolution.md#cutlass-convolution-implementation) +- [**Convolution Examples**](implicit_gemm_convolution.md#convolution-example) + + +# Implicit GEMM Algorithm + +2-D convolution may be mapped to matrix multiply by forming a _convolution matrix_ containing +elements of the activations tensor then multiplying this by a matrix formed from the filters tensor. +The earliest form of this algorithm construct the convolution matrix explicitly via an operation +conventionally referred to as `im2col`. The resulting matrix replicates each activation element by a factor +equal to the filter size, consuming additional storage capacity and memory bandwidth. + +The _implicit GEMM_ algorithm is a variation on the blocked, hierarchical GEMM computation in CUDA +that instead forms tiles of the convolution matrix on the fly as data is loaded from global memory +into Shared Memory by carefully updating pointers and predicates. Once the convolution matrix is +formed in Shared Memory, the existing components computing warp-level GEMM accumulate the result of +convolution and update the output tensor. + +This section describes the structure of an efficient Implicit GEMM Convolution CUDA kernel +for Turing Tensor Cores. + +## Mapping Convolution to GEMM + +The forward convolutional layer computes an output tensor _y = conv(x, w)_ where x(NHWC), w(KRSC), and y(NPQK) +are 4-D tensors. + +This computation may be described by the following analytic function. + +``` +y[n, p, q, k] = sum_c(sum_r(sum_s( x[n, f(p, r), g(q, s), c] * w[k, r, s, c] ))) +``` +where functions _f_ and _g_ are defined as follows. + +``` +f(p, r) = p * stride_h + R - r - 1 + pad_h +g(q, s) = h * stride_w + S - s - 1 + pad_w +``` + +A [host](/tools/util/include/reference/host/convolution.h) and [device](/tools/util/include/reference/device/convolution.h) +reference implementation are provided in the CUTLASS Utilities. + +This computation may be mapped to the elements of a matrix product as follows. + +``` +C = gemm(A, B) +``` +where +- A is a row-major matrix of extent _NHW_-by-_RSC_ containing activations +- B is a column-major matrix of extent _RSC_-by-_K_ containing filters +- C is a row-major matrix of extent _NPQ_-by-_K_ containing the output + +Each element of the output matrix _Cij_ corresponds to an element in the output tensor y[n, p, q, k] according to +the following relation. +``` +y[n, p, q, k] = Cij +``` +where +``` +i = q + Q * (p + P * n) +j = k +``` + +These relations may be inverted as follows. +``` +k = j + +n = i / (PQ) +residual = i % (PQ) + +p = residual / Q +q = residual % Q +``` + +The triple loop nest iterating over CRS to accumulate the result may also be linearized and mapped to the inner +GEMM _K_ dimension (not to be confused with the filter tensor dimension _K_) by the following relations. + +``` +gemm_k = s + S * (r + R * c) +``` +and inverse +``` +c = gemm_k / (RS) +residual = gemm_k % (RS) + +r = residual / S +s = residual % S +``` + +Given these equations, a GEMM triple loop nest could be augmented with tensor indexing as follows. +```c++ +int GEMM_M = N * P * Q; +int GEMM_N = K; +int GEMM_K = C * R * S; + +for (int gemm_i = 0; gemm_i < GEMM_M; ++gemm_i) { + for (int gemm_j = 0; gemm_j < GEMM_N; ++gemm_j) { + + int n = gemm_i / (PQ); + int npq_residual = gemm_i % (PQ); + + int p = npq_residual / Q; + int q = npq_residual % Q; + + Accumulator accum = 0; + + for (int gemm_k = 0; gemm_k < GEMM_K; ++gemm_k) { + + int k = gemm_j; + + int c = gemm_k / (RS); + int crs_residual = gemm_k % (RS); + + int r = crs_residual / S; + int s = crs_residual % S; + + int h = f(p, r); + int w = g(q, s); + + ElementA a = tensor_A.at({n, h, w, c}); + ElementB b = tensor_B.at({k, r, s, c}); + + accum += a * b; + } + + C[gemm_i * K + gemm_j] = accum; + } +} +``` +The [CUTLASS GEMM implementation](/media/docs/efficient_gemm.md) explicitly iterates over tiles. Consequently, +a tile iterator could be implemented to compute these functions analytically and load the appropriate +elements. However, the resulting modulo arithmetic would be computationally intensive, and overhead would +limit performance of a GEMM kernel targeting Turing Tensor Cores. + +The following section describes how an efficient implementation may be implemented within the structure of +a hierarchical GEMM kernel targeting Tensor Cores. + + +# CUTLASS Convolution Implementation + +The CUTLASS Implicit GEMM implementation makes several assumptions. + +- All tensors are 128-bit aligned NHWC tensors +- Channel count (C) is a multiple of 32 elements +- Filter count (K) is a multiple of 32 elements + +This enables 128-bit vector memory acceses which lead to efficient CUDA kernels. + +# CUTLASS Device-level Convolution Operator + +CUTLASS defines CUDA C++ templates accepting numerous template arguments to specialize the resulting +kernel by operation, data type, tile configuration, math instruction, and fused output operation. + +In [09_turing_tensorop_conv2dfprop.cu](/examples/09_turing_tensorop_conv2dfprop/09_turing_tensorop_conv2dfprop.cu), a convolution +operation is defined as follows. + +```c++ +/// Define an Implicit GEMM convolution forward propagation (fprop) kernel +using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementInputA, // data type of element a (mapped to activation for fprop) + LayoutInputA, // layout of element a (mapped to activation for fprop) + ElementInputB, // data type of element b (mapped to filters for fprop) + LayoutInputB, // layout of element b (mapped to filters for fprop) + ElementC, // data type of element c (mapped to output for fprop) + LayoutC, // layout of element c (mapped to output for fprop) + ElementAccumulator, // data type of internal accumulation + MMAOp, // opcode class tag + SmArch, // target SM architecture + ThreadblockShape, // shape of threadblock tile + WarpShape, // shape of warp-level GEMM tile + InstructionShape, // shape of target math instruction + EpilogueOp, // epilogue operator + SwizzleThreadBlock, // optional function to reorder threadblocks for locality + NumStages, // number of pipeline stages in threadblock-scoped GEMM + cutlass::arch::OpMultiplyAddSaturate, // math operation on data of element a and b + cutlass::conv::IteratorAlgorithm::kAnalytic // globabl memory iterator algorithm +>::Kernel +``` + +This template is intended to be generic and cover all feasible configurations. The example specifies +the following concrete data types, layouts, and tile sizes. + +```c++ +/// Define an Implicit GEMM convolution forward propagation (fprop) kernel +using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + cutlass::int4b_t, // data type of element a (mapped to activation for fprop) + cutlass::layout::TensorNHWC, // layout of element a (mapped to activation for fprop) + cutlass::int4b_t, // data type of element b (mapped to filters for fprop) + cutlass::layout::TensorNHWC, // layout of element b (mapped to filters for fprop) + int32_t, // data type of element c (mapped to output for fprop) + cutlass::layout::TensorNHWC, // layout of element c (mapped to output for fprop) + int32_t, // data type of internal accumulation + cutlass::arch::OpClassTensorOp, // opcode class tag + cutlass::arch::Sm75, // target SM architecture + cutlass::gemm::GemmShape<128, 128, 128>, // shape of threadblock tile + cutlass::gemm::GemmShape<64, 64, 128>, // shape of warp-level GEMM tile + cutlass::gemm::GemmShape<8, 8, 32>, // shape of target math instruction + cutlass::epilogue::thread::LinearCombinationClamp< + int32_t, // data type of output matrix + 8, // The number of elements per vectorized + // memory access. This becomes the vector width of + // math instructions in the epilogue too. + int32_t, // Data type of accumulator + float>; , // epilogue operator + SwizzleThreadBlock, // optional function to reorder threadblocks for locality + 2, // number of pipeline stages in threadblock-scoped GEMM + cutlass::arch::OpMultiplyAddSaturate, // math operation on data of element a and b + cutlass::conv::IteratorAlgorithm::kAnalytic // globabl memory iterator algorithm +>::Kernel +``` + +That is, this computes 2D convolutional forward propagation with 4-bit integer inputs and outputs (`cutlass::int4b_t`). +Internal accumulation is performed using 32-bit integers (`int32_t`), and an elementwise linear combination operation +is performed on the output in single-precision floating point (`float`). + +The threadblock and warp-level tile sizes refer to the hierarhically blocked GEMM computation +[described here](/media/docs/gemm_api.md). Larger tiles achieve greater reuse of data loaded through shared memory +but launch fewer CTAs and may not fully occupy the GPU for small problem sizes. Smaller tile configurations achieve +lower peak utilizations but may better match the number of SMs within the GPU for real-world workloads. + + +## Launching the convolution + +The following code collects the arguments for an implicit GEMM operation into a structure. + +```c++ +// +// Define arguments for CUTLASS Convolution +// + +// mode (kCrossCorrelation or kConvolution) +cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation; + +// Split K dimension into 1 partitions +int split_k_slices = 1; + +cutlass::conv::Conv2dProblemSize problem_size( + options.input_size, + options.filter_size, + options.padding, + options.conv_stride, + options.dilation, + options.output_size(), + mode, + split_k_slices); + +typename ImplicitGemm::Arguments arguments{ + problem_size, + tensor_a.device_ref(), + tensor_b.device_ref(), + tensor_c.device_ref(), + tensor_c.device_ref(), + {options.alpha, options.beta}, +}; +``` + +The `mode` flag indicates whether to compute cross correlation or convolution. The arguments +`input_size`, `filter_size`, `padding`, `conv_stride`, and `dilation` specify the dimensions of the +input and output tensors and characterize the problem size. + +The arguments `tensor_a.device_ref()`, `tensor_b.device_ref()`, and `tensor_c.device_ref()` are +CUTLASS `TensorRef<>` objects containing a pointer to the tensor data in GPU device memory and stride values. + +The following code initializes and launches the Implicit GEMM operation on the device. After initializing +the arguments structure, it is used to query device-side workspace requirements and allocate them +in device memory if needed. + +Then, the Implicit GEMM object is initialized with the `arguments` structure and the workspace in +device memory. This initialization step precomputes internal lookup tables used by the convolution kernel +and may also clear the device-side workspace if needed. + +Finally, the initialized Implicit GEMM object is called, launching a kernel on the device. `tensor_c` now +contains the result of the implicit GEMM. + +```c++ +ImplicitGemm implicit_gemm_op; + +// Query workspace size +size_t workspace_size = implicit_gemm_op.get_workspace_size(arguments); + +// Allocate workspace memory +cutlass::device_memory::allocation workspace(workspace_size); + +// Initialize the Implicit GEMM object +cutlass::Status status = implicit_gemm_op.initialize(arguments, workspace.get()); + +if (status != cutlass::Status::kSuccess) { + /* error */ +} + +// +// Launch initialized CUTLASS kernel +// + +status = implicit_gemm_op(); + +if (status != cutlass::Status::kSuccess) { + /* error */ +} +``` + +The example demonstrates how the input and output tensors may be written to a file as CSV using +`cutlass::HostTensor<>` defined in the [CUTLASS Utilities](/media/docs/utilities.md). + +```c++ + std::ofstream output_workspace(ss.str()); + + output_workspace + << "Input = \n" << tensor_a.host_view() << "\n\n" + << "Filters = \n" << tensor_b.host_view() << "\n\n"; + + // Copy device memory to host backing store + tensor_c.sync_host(); + + output_workspace << "Computed = \n" << tensor_c.host_view() << std::endl; +``` + + +## CUTLASS Components + +CUTLASS defines the following CUDA C++ templates to implement Implicit GEMM Convolution which are described in greater detail in subsequent sections. + +**Activations tile iterators** load the activations tile into registers. Two implementations are provided: +- [conv2d_fprop_activation_tile_access_iterator_analytic.h](/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h) computes pointer deltas and masks analytically +- [conv2d_fprop_activation_tile_access_iterator_optimized.h](/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_optimized.h) optimizes iterating over global memory and +creating GEMM-A tile in shared memory. + +**Filter tile iterators** load filters into registers. Similarly, two implementations are provided: +- [conv2d_fprop_filter_tile_access_iterator_analytic.h](/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_analytic.h) computes pointer deltas and masks analytically +- [conv2d_fprop_filter_tile_access_iterator_optimized.h](/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_optimized.h) optimizes iterating over global memory and +creating GEMM-B tile in shared memory. + +The improvements covered by optimized iterators are: +- (a) Precomputing kernel-invariant pointer deltas on the host +- (b) Computing cta-invariant mask predicates on device-side iterator ctors +- (c) Use of [fast divmod](include/cutlass/fast_math.h) to map GEMM dimenstions to convolution tensors. +For example, _optimized_ activation iterator uses fast divmod to map GEMM _M_ to NPQ +for activation iterator + + +**Pipelined mainloop** loads threadblock-scoped tiles from global memory into shared memory and then applies +CUTLASS warp-level GEMM operations to load from Shared Memory and issue instructions to Turing Tensor Cores. +- [mma_pipelined.h](/include/cutlass/conv/threadblock/implicit_gemm_pipelined.h) + +Operations for storing to shared memory and performing warp-wide matrix multiply operations using +Turing Tensor Cores are applied directly from the CUTLASS GEMM components. These include the +following components. + +**Regular Tile Iterator** implemented in +[transform::threadblock::RegularTileIterator](/include/cutlass/transform/threadblock/regular_tile_iterator.h) +stores register-backed fragments to Shared Memory in permuted layouts. + +**Warp-level GEMM** defined in [cutlass::gemm::warp::MmaTensorOp](/include/cutlass/gemm/warp/mma_tensor_op.h) +defines tile iterators to load from Shared Memory and issue math instructions to Turing Tensor Cores. +Further details are [described in here](/media/docs/gemm_api.md#warp-level-matrix-multiply-api). + +**Epilogue** reorders accumulator elements among threads within a threadblock to efficiently update +the output tensor. It is implemented in [epilogue::threadblock::Epilogue](/include/cutlass/epilogue/threadblock/epilogue.h). + +### Loading Activations and Filters + +The Implicit GEMM Convolution algorithm partitions the GEMM _K_ dimension (of extent _CRS_) into +threadblock tiles and assigning each threadblock tile to one filter position and an interval +of channels. After iterating over all filter positions, the convolution algorithm advances to the +next interval of channels and proceeds from filter `r=0, s=0`. + +The matrix product of one threadblock tile is computed per iteration of +the mainloop as described in the [CUTLASS GEMM implementation](/media/docs/efficient_gemm.md). To +summarize, the threadblock tile of activations and filters are loaded from tensors in global memory +and stored to shared memory. Each thread within the threadblock loads one or more vectors and +collectively span the entire tile. + +The following figure illustrates one particular iteration of the Implicit GEMM mainloop. Each +thread within the threadblock is mapped to several vectors of elements in the Activations and +Filters tensors. Each index in the GEMM _M_ dimension corresponds to a unique _(N,P,Q)_ +index of the output tensor, and pointers may be computed based on this as well as +filter position _(r,s)_. + +![ALT](/media/images/conv2d-fprop-int4.png "Convolution Forward Propagation on INT4 data.") + +The CUTLASS component that embodies this functionality is [Conv2dFpropFilterTileAccessIteratorAnalytic](/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h). +Its constructor computes the mapping of GEMM _M_ to _(N, P, Q)_, the `at()` method maps the linear offset into the Activations +tensor for each memory access the thread is to perform. Additionally, the method `valid()` computes the valided of the access +for each filter position and for each memory access to indicate whether the memory access will be within the bounds of the +tensor or out of bounds. + +`operator++()` iterates over memory accesses performed by a thread in both contiguous and strided dimension. + +```c++ +// cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h + +// Update iterator to thread's next contiguous, strided memory access +Conv2dFpropActivationTileAccessIteratorAnalytic &operator++() { + ++iteration_contiguous_; + if (iteration_contiguous_ < ThreadMap::Iterations::kContiguous) { + return *this; + } + iteration_contiguous_ = 0; + + ++iteration_strided_; + if (iteration_strided_ < ThreadMap::Iterations::kStrided) { + return *this; + } + iteration_strided_ = 0; + + return *this; +} +``` + +After all accesses have been visited for the current threadblock tile, `advance()` updates the pointers to next tile. +Offsets added to each pointer follows the traversal of filter positions, performing one of the +following: +- advance from filter position _(r, s, c)_ to filter position _(r, s+1, c)_ +- advance from filter position _(r, S-1, c)_ to filter position _(r+1, 0, c)_ +- advance from filter position _(R-1, S-1, c)_ to filter position _(0, 0, c+32)_ + +This logic within method `advance()`'s body computes the above three updates for the activation GEMM-A tile. + +```c++ +// cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_analytic.h + +// Advance to the next access +void advance() { + // moves to the next tile + ++filter_s_; + if (filter_s_ < problem_size_.S) { + return; + } + filter_s_ = 0; + + ++filter_r_; + if (filter_r_ < problem_size_.R) { + return; + } + filter_r_ = 0; + + filter_c_ += Shape::kRow * problem_size_.split_k_slices; +} +``` + +Similar logic holds for [Conv2dFpropFilterTileAccessIteratorAnalytic](/include/cutlass/conv/threadblock/conv2d_fprop_filter_tile_access_iterator_analytic.h). + +To reduce computational overhead in the mainloop body, the pointer offsets may be precomputed +in host code and provided to the CUDA kernel as a lookup table in its `Params` structure. +As shown in [Conv2dFpropFilterTileAccessIteratorOptimized](/include/cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_optimized.h), +the logic to compute offsets from filter position has been extracted to the `Params` constructor. + +```c++ +// cutlass/conv/threadblock/conv2d_params.h +struct Conv2dFpropActivationIteratorOptimizedParams { + ... +// next S +inc_next[0] = conv_sign * (int64_t(layout.stride()[0]) * problem_size.dilation_w) * element_size_bits / 8; + +// next R +inc_next[1] = conv_sign * ( + int64_t(layout.stride()[1]) * problem_size.dilation_h + - (problem_size.S - 1) * layout.stride()[0] * problem_size.dilation_w + ) * element_size_bits / 8; + +// next C +inc_next[2] = ( + threadblock_shape.column() * problem_size.split_k_slices + - conv_sign * int64_t(problem_size.R - 1) * layout.stride()[1] * problem_size.dilation_h + - conv_sign * int64_t(problem_size.S - 1) * layout.stride()[0] * problem_size.dilation_w + ) * element_size_bits / 8; + + ... +} +``` + +This allows only a simple lookup from the _delta table_ performed in device code in `Conv2dFpropActivationTileAccessIteratorOptimized::advance()` + +```c++ +// cutlass/conv/threadblock/conv2d_fprop_activation_tile_access_iterator_optimized.h +CUTLASS_HOST_DEVICE +void advance() { + + int next_idx = 0; + + // moves to the next tile + ++filter_s_; + if (filter_s_ == problem_size_.S) { + filter_s_ = 0; + ++filter_r_; + + if (filter_r_ < problem_size_.R) { + next_idx = 1; + } + else { + filter_r_ = 0; + next_idx = 2; + } + } + + add_byte_offset_(params_.inc_next[next_idx]); // in addition to Conv2dFpropActivationTileAccessIteratorAnalytic::advance() + + if (next_idx == 2) { + filter_c_ += params_.filter_c_delta; + } +} + +``` + +### Utilizing Tensor Cores + +Turing Tensor Cores compute matrix multiply-accumulate operations efficiently by sharing data among all +threads within a warp. The following operations are supported. + +|**Shape**|**A**|**B**|**C**| +|---------|-----|-----|-----| +| 8x8x32 | int4b_t | int4b_t | int32_t | +| 8x8x16 | int8b_t | int8b_t | int32_t | +| 16x8x8 | half | half | half | +| 16x8x8 | half | half | float | + +Functionally, the Turing 8x8x32 matrix multiply operation distributes the _A_, _B_, and _C_ matrix across 32 +threads within a warp according to the following illustration. + +![ALT](/media/images/mma-8x8x32.png "Turing Tensor Op") + +This Tensor Core operation is accessible to the CUDA programmer via the PTX instruction +[`mma.sync`](https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#warp-level-matrix-fragment-mma-8832). +CUTLASS wraps inline PTX with device-side intrinsics defined in [`cutlass/arch/mma_sm75.h`](/include/cutlass/arch/mma_sm75.h) +as in the following example. + +```c++ +unsigned A; // eight packed 4-bit integer elements +unsigned B; // eight packed 4-bit integer elements + +int C[2]; // two 32-bit integer elements +int D[2]; // two 32-bit integer elements + +asm volatile( + "mma.sync.aligned.m8n8k32.row.col.s32.s4.s4.s32 {%0,%1}, {%2}, {%3}, {%4,%5};\n" + : "=r"(D[0]), "=r"(D[1]) + : "r"(A), "r"(B), "r"(C[0]), "r"(C[1])); +``` + +To efficiently load data from Shared Memory into registers with the distribution among +warps matching the above, the Turing GPU architecture introduces +[`ldmatrix`](https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#warp-level-matrix-instructions-ldmatrix). +`ldmatrix` is the ultimate warp-cooperative instruction, as all threads contribute addresses to up to 32 row vectors of +size 128-bits in length. These rows are fetched from Shared Memory and then distributed among groups of four threads +per row. + +The arrangement of SMEM pointers and destination registers within threads is illustrated as follows. Thread 0 is highlighted +in the illustration to emphasize the mapping. + +![ALT](/media/images/ldmatrix-8x128bx4.png "Turing ldmatrix PTX instruction") + +The size of the Turing Tensor Core operation computing matrix multiply-accumulate on INT4 data is 8-by-8-by-32 +elements. `ldmatrix` fetches up to 32 rows (or columns) per operation. Sixteen Tensor Core operations may be issued +to implement a 32-by-32-by-32 matrix product and perfectly consume all data loaded by two `ldmatrix` instructions +as shown in the following figure. Larger tiles are possible by increasing the number of memory instructions +and issuing more Tensor Core operations, up to warp-level matrix operations of size 64-by-64-by-32. The limit is +the number of registers to hold the accumulator elements. + +![ALT](/media/images/ldmatrix-tensorop-32x32x32.png "Turing ldmatrix PTX instruction feeding Tensor Core operations") + +### Shared Memory Layouts + +In the previous two sections, we have described how data may be loaded from activations and filters tensors +in global memory to compute convolution, and we have described a composition of `ldmatrix` and `mma.sync` +to fetch data from Shared Memory and issue Tensor Core operations. + +To ensure this data movement is efficient, care must be taken to ensure bank conflicts are avoided. CUTLASS +uses a permuted Shared Memory layout to avoid bank conflicts when storing to Shared Memory and to efficiently +load from Shared Memory using `ldmatrix`. The following figure illustrates the thread mapping used for +the loading the activations and filters threadblock tiles from global memory and the permuted layout in +Shared Memory. + +![ALT](/media/images/tensor-op-permuted-smem-layout-TN.png "Shared Memory layout used for Turing Tensor Cores") + +In the illustration, one warp-wide memory access is highlighted in blue, with individual threads +loading one 128-bit vector. The tile in global memory could correspond either to the activations +or filters and is assumed to be 'strip-mined' with four threads loading consecutive channels. + +Shared Memory is visualized as a 'row-major' matrix with eight columns representing +the eight 128-bit banks. +As described in the CUTLASS GTC 2019 presentation [slides](https://developer.download.nvidia.com/video/gputechconf/gtc/2019/presentation/s9593-cutensor-high-performance-tensor-operations-in-cuda-v2.pdf), +[recording](https://developer.nvidia.com/gtc/2019/video/S9593), an access to Shared Memory will be conflict-free if +the following conditions are satisfied across each warp: +- {T0, T1, .., T7} do not access the same 128-bit bank +- {T8, T9, .., T16} do not access the same 128-bit bank +- {T16, T17, .., T23} do not access the same 128-bit bank +- {T24, T25, .., T31} do not access the same 128-bit bank + +To achieve conflict-free stores, the Shared Memory layout remaps the strip-mined arrangement to transpose +the vectors and applies an XOR operation on the column index of each thread's pointer. Specifically, + +```c++ + int store_column = (lane_id % 8) ^ (lane_id / 8); +``` + +This transformation on the layout will be instrumental in reading slices of data from Shared Memory +to compute the warp-level matrix multiply using Tensor Cores. + +The following figure shows how the first sixteen threads participating in an `ldmatrix` instruction +logically map to the c=0..31 slice of a matrix in Shared Memory. This slice is known as a "k-group" +within the code because it corresponds to the same K-index of a warp-level matrix multiply. + +![ALT](/media/images/tensor-op-permuted-smem-layout-TN-k0.png "Load kgroup=0 from Shared Memory using ldmatrix") + +The lower half of the figure shows the physical arrangement in Shared Memory, with threads offset by row and column +according to the XOR function. By inspection, we can observe there are no bank conflicts, as _T0 ... T7_ each access unique +banks, as do _T8 ... T15_. and beyond. + +To advance to the next "k-group" within Shared Memory, pointers are updated using an XOR operation according to +the following sequence: +- **^1** advances from _k=0_ to _k=1_ +- **^3** advances from _k=1_ to _k=2_ +- **^1** advances from _k=2_ to _k=3_ +- **^3** advances from _k=3_ to _k=0_ + +The first of these transitions is shown below. +![ALT](/media/images/tensor-op-permuted-smem-layout-TN-k1.png "Advance to kgroup=1 from Shared Memory using ldmatrix") + +The [CUTLASS warp-level GEMM API](/media/docs/gemm_api.md#warp-level-matrix-multiply-api) defines templates for +loading slices of data from permuted Shared Memory and issuing operations to Tensor Cores. + +### Updating the Output Tensor + +After the mainloop terminates, the accumulator tile of the warp-level GEMM stores a warp's contribution to the output +tensor. However, the distribution of data among threads within the threadblock is specialized for efficient matrix multiply-accumulate +operations using Tensor Cores and is not conducive to efficient, coalesced operations to Global Memory. A data rearrangement is +needed. + +The **Epilogue** is the component for exchanging accumulator elements through Shared Memory, loading slices of the output +matrix or tensor, applying an elementwise operation such as linear scaling or bias, and storing the result to the output tensor. +CUTLASS structures this as several components: +- [cutlass::epilogue::threadblock::Epilogue](/include/cutlass/epilogue/threadblock/epilogue.h) - the top-level component for looping over the entire threadblock tile +- [cutlass::epilogue::warp::TileIteratorTensorOp](/include/cutlass/epilogue/warp/tile_iterator_tensor_op.h) - a specialized component for storing accumulators for Tensor Core to Shared Memory +- [cutlass::epilogue::threadblock::SharedLoadIterator](/include/cutlass/epilogue/threadblock/shared_load_iterator.h) - a component for loading elements from a row-major arrangement in Shared Memory +- [cutlass::epilogue::threadblock::PredicatedTileIterator](/include/cutlass/epilogue/threadblock/predicated_tile_iterator.h) - a component for loading or storing matrix fragments to Global Memory (with bounds checks) +- [cutlass::epilogue::thread::LinearCombination](/include/cutlass/epilogue/thread/linear_combination.h) - an element-wise function computing `alpha * AB + beta * C` to compute the final output + +## Unit Tests + +Unit tests verify the functional behavior of each of the above components in a standalone CUDA kernel. This provides a +convenient environment to (a.) inspect the template definition, (b.) showcase instantiation of use of these templates +in device code, and (c.) assert functional correctness. + +**Convolution unit tests** +- Device-wide convolution operator: [conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm75.cu](/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm75.cu) + +**GEMM unit tests** +- Warp-scoped matrix multiply for Turing Tensor Cores: [gemm_sm75.cu](/test/unit/gemm/warp/gemm_sm75.cu) + +**Epilogue unit tests** +- Epilogue for Turing Tensor Cores: [epilogue_tensor_op.cu](/test/unit/epilogue/threadblock/epilogue_tensor_op.cu) + + +# Convolution Example + +This section describes the provided convolution example and is intended to orient the reader to the CUTLASS implementation +of Implicit GEMM Convolution. + +## Building and Running the Example + +Example `09_turing_tensorop_conv2dfprop` computes a forward convolutional layer in which inputs and +outputs are 4-b integers. The example source is visible in +[examples/09_turing_tensorop_conv2dfprop/turing_tensorop_conv2dfprop.cu](/examples/09_turing_tensorop_conv2dfprop/turing_tensorop_conv2dfprop.cu). + + +Before building the example, first perform the prerequisite steps for building any CUTLASS component [described here](/media/docs/quickstart.md). +Compute capability 7.5 refers to the Turing architecture, and this work requires CUDA 10.2 Toolkit or later to target +Turing Tensor Cores using the native `mma` [PTX instruction](https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#warp-level-matrix-fragment-mma-8832). + +```bash +$ mkdir build && cd build + +$ cmake .. -DCUTLASS_NVCC_ARCHS=75 +``` + +To build the example, execute `make 09_turing_tensorop_conv2dfprop` from the build directory. +```bash +$ make 09_turing_tensorop_conv2dfprop + +$ ls examples/09_turing_tensorop_conv2dfprop +examples/09_turing_tensorop_conv2dfprop + +``` + +This example provides a simple command line interface to specify the extents of 4D tensors of 4-bit integer elements (`cutlass::int4b_t`), +initialize them to random values, and compute the result of a convolutional layer. Optionally, the input and output +tensors may be saved to .csv files, and the CUTLASS host-side reference check may be executed to verify correctness. + +The complete usage statement is visible by running with `--help`: +```bash +$ ./examples/09_turing_tensorop_conv2dfprop/09_turing_tensorop_conv2dfprop --help +09_turing_tensorop_conv2dfprop example + + This example uses Turing's Tensor Core operators on int4 data types to compute + forward convolution on tensors of layout NHWC. + +Options: + + --help If specified, displays this usage statement. + + --n Input tensor extent N + --h Input tensor extent H + --w Input tensor extent W + --c Input tensor extent C + --k Filter extent K + --r Filter extent R + --s Filter extent S + + --alpha Epilogue scalar alpha + --beta Epilogue scalar beta + + --ref-check If set (true), reference check on the host is computed + --perf-check If set (true), performance is measured. + --benchmark If set (true), performance benchmarking on several layers and batch-size. + --iterations Number of profiling iterations to perform. + --save-workspace If set, workspace is written to a text file. + --tag String to replicate across the first column in the results table + + + +Examples: + +$ ./examples/09_turing_tensorop_conv2dfprop/09_turing_tensorop_conv2dfprop --n=32 --h=224 --w=224 --c=128 --k=256 --r=1 --s=1 + +$ ./examples/09_turing_tensorop_conv2dfprop/09_turing_tensorop_conv2dfprop --n=1 --h=224 --w=224 --c=32 --k=32 --r=3 --s=3 --ref-check +``` + +*Note*, this example assumes all tensors are 128b aligned and in format _NHWC_. Consequently, dimension +_C_ must be divisible by 32 for activations, filters, and output. + +If the option `--benchmark` is passed, several layers from ResNet50 are profiled for various batch sizes. +This sample output was computed on an NVIDIA RTX 2080 compiled with CUDA 10.2. + +```bash +build$ ./examples/09_turing_tensorop_conv2dfprop/09_turing_tensorop_conv2dfprop --benchmark +``` + +Convolution can also be run by the CUTLASS Profiler. + + +# Copyright + +Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + +``` + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +``` diff --git a/media/docs/profiler.md b/media/docs/profiler.md index dd1f62a7c..032848c6f 100644 --- a/media/docs/profiler.md +++ b/media/docs/profiler.md @@ -109,16 +109,29 @@ About: Operations: --operation= Specifies a particular operation to run or print the usage statement. - gemm General matrix-matrix product. D = alpha * A*B + beta * C + gemm General matrix-matrix product. D = alpha * A*B + beta * C + spgemm Structured sparse GEMM. D = alpha * A*B + beta * C + conv2d Conv2d operation. Output(Tensor4D) = alpha * Input(Tensor4D) * Filter(Tensor4D) + beta * Input(Tensor4D) + conv3d Conv3d operation. Output(Tensor5D) = alpha * Input(Tensor5D) * Filter(Tensor5D) + beta * Input(Tensor5D) For more details about a particular operation, specify the operation name with --help. Example: - $ ./tools/profiler/cutlass_profiler --operation=Gemm --help + $ cutlass_profiler --operation=Gemm --help + + $ cutlass_profiler --operation=Conv3d --help + + $ cutlass_profiler --operation=Conv2d --help + + $ cutlass_profiler --operation=SparseGemm --help ``` +# GEMM + +The CUTLASS Profiler is capable of executing each GEMM kernel. + ## GEMM Arguments The complete set of arguments available to each operation may be viewed by specifying the operation name @@ -189,7 +202,7 @@ Test your changes to gemm kernels with a quick functional test and save results --providers=cutlass --output=functional-test.csv ``` -## Example SGEMM +## Example CUDA Core GEMM Operation (SGEMM) Example command line for profiling SGEMM kernels is as follows: ```bash @@ -226,7 +239,7 @@ $ ./tools/profiler/cutlass_profiler --kernels=sgemm --m=3456 --n=4096 --k=4096 Note, the arguments which appear in the output may be used as command line parameters for subsequent invocations. -## Example Tensor Core Operations +## Example Tensor Core GEMM Operations (S16816GEMM) To execute kernels targeting Tensor Core operations, supply the flag `--op_class=tensorop` in the command line. @@ -293,6 +306,158 @@ $ ./tools/profiler/cutlass_profiler --kernels=cutlass_simt_sgemm_128x128_nn --tags=cutlass:2.2,date:2020-06-08 ``` +# Convolution + +The CUTLASS Profiler is capable of executing 2-D and 3-D convolution problems for forwards and backwards +oeprator variants. + +The CUTLASS Profiler can be built with cuDNN enabled to use as a reference implementation. If CMake detects +the cuDNN library available in the system, it is included as a dependency. This may be explicitly overridden +with CMake flag `CUTLASS_ENABLE_CUDNN`. + +```bash +$ cmake .. -DCUTLASS_LIBRARY_OPERATIONS=conv2d -DCUTLASS_ENABLE_CUDNN=OFF +... +$ make -j16 cutlass_profiler +``` + + +## Convolution Arguments + +```bash +$ ./tools/profiler/cutlass_profiler --help --operation=Conv2d + +Conv2d + + [enum] --conv_kind Convolutional operator (fprop, dgrad, wgrad) + [int] --n,--input_n Input N dimension of the Conv2d problem space + [int] --h,--input_h Input H dimension of the Conv2d problem space + [int] --w,--input_w Input W dimension of the Conv2d problem space + [int] --c,--input_c Input C dimension of the Conv2d problem space + [int] --k,--filter_k Filter K dimension of the Conv2d problem space + [int] --r,--filter_r Filter R dimension of the Conv2d problem space + [int] --s,--filter_s Filter S dimension of the Conv2d problem space + [int] --p,--output_p Output P dimension of the Conv2d problem space + [int] --q,--output_q Output Q dimension of the Conv2d problem space + [int] --pad_h Padding in H direction + [int] --pad_w Padding in W direction + [int] --stride_h Stride in H direction + [int] --stride_w Stride in W direction + [int] --dilation_h Dilation in H direction + [int] --dilation_w Dilation in W direction + [tensor] --Activation Tensor storing the Activation operand + [tensor] --Filter Tensor storing the Filter operand + [tensor] --Output Tensor storing the Output operand + [enum] --conv_mode Convolution filter mode (conv, cross) + [enum] --iterator_algorithm,--iterator_algo Convolution iterator algorithm (analytic, optimized) + [scalar] --alpha,--epilogue::alpha Epilogue scalar alpha + [scalar] --beta,--epilogue::beta Epilogue scalar beta + [enum] --split_k_mode,--split-k-mode SplitK mode for serial or parallel reduction (serial, parallel) + [int] --split_k_slices,--split-k-slices Number of partitions of K dimension + [enum] --eq_gemm_provider,--eq-gemm-provider Enable profiling equivalent gemm by the following providers (cutlass) + [enum] --op_class,--opcode-class Class of math instruction (simt, tensorop, wmmatensorop, wmma) + [enum] --accum,--accumulator-type Math instruction accumulator data type + [int] --cta_m,--threadblock-shape::m Threadblock shape in the M dimension + [int] --cta_n,--threadblock-shape::n Threadblock shape in the N dimension + [int] --cta_k,--threadblock-shape::k Threadblock shape in the K dimension + [int] --stages,--threadblock-stages Number of stages of threadblock-scoped matrix multiply + [int] --warps_m,--warp-count::m Number of warps within threadblock along the M dimension + [int] --warps_n,--warp-count::n Number of warps within threadblock along the N dimension + [int] --warps_k,--warp-count::k Number of warps within threadblock along the K dimension + [int] --inst_m,--instruction-shape::m Math instruction shape in the M dimension + [int] --inst_n,--instruction-shape::n Math instruction shape in the N dimension + [int] --inst_k,--instruction-shape::k Math instruction shape in the K dimension + [int] --min_cc,--minimum-compute-capability Minimum device compute capability + [int] --max_cc,--maximum-compute-capability Maximum device compute capability + +Examples: + +Profile a particular convolution (specify all the convolution parameters): + + $ cutlass_profiler --operation=Conv2d --Activation=f16:nhwc \ + --Filter=f16:nhwc --Output=f16 --accumulator-type=f32 \ + --n=32 --h=14 --w=14 --c=8 --k=64 --r=3 --s=3 \ + --pad_h=1 --pad_w=1 \ + --stride::h=1 --stride::w=1 --dilation::h=1 --dilation::w=1 + +``` + +## Example CUDA Core Convolution Operation (SFPROP) + +Example command line for profiling Convolution kernels is as follows: + +```bash +$ ./tools/profiler/cutlass_profiler --kernels=cutlass_simt_sfprop_optimized_128x128_8x2_nhwc --verification-providers=device --n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 + + +============================= + Problem ID: 1 + + Provider: CUTLASS + OperationKind: conv2d + Operation: cutlass_simt_sfprop_optimized_128x128_8x2_nhwc + + Status: Success + Verification: ON + Disposition: Passed + +reference_device: Passed + + Arguments: --conv_kind=fprop --n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 --p=224 --q=224 --pad_h=1 --pad_w=1 \ + --stride_h=1 --stride_w=1 --dilation_h=1 --dilation_w=1 --Activation=f32:nhwc --Filter=f32:nhwc --Output=f32:nhwc \ + --conv_mode=cross --iterator_algorithm=optimized --alpha=1 --beta=0 --split_k_mode=serial --split_k_slices=1 \ + --eq_gemm_provider=none --op_class=simt --accum=f32 --cta_m=128 --cta_n=128 --cta_k=8 --stages=2 --warps_m=4 \ + --warps_n=2 --warps_k=1 --inst_m=1 --inst_n=1 --inst_k=1 --min_cc=50 --max_cc=1024 + + Bytes: 2055798784 bytes + FLOPs: 118482796544 flops + + Runtime: 8.13237 ms + Memory: 235.431 GiB/s + + Math: 14569.3 GFLOP/s + +``` + +## Example Tensor Core Convolution Operation (S16816FPROP) + +Example command line for profiling Convolution kernels is as follows: + +```bash +$ ./tools/profiler/cutlass_profiler --kernels=cutlass_tensorop_s16816fprop_optimized_f16_128x128_64x4_nhwc --verification-providers=device --n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 + + + +============================= + Problem ID: 1 + + Provider: CUTLASS + OperationKind: conv2d + Operation: cutlass_tensorop_s16816fprop_optimized_f16_128x128_64x4_nhwc + + Status: Success + Verification: ON + Disposition: Passed + +reference_device: Passed + + Arguments: --conv_kind=fprop --n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 --p=224 --q=224 --pad_h=1 --pad_w=1 \ + --stride_h=1 --stride_w=1 --dilation_h=1 --dilation_w=1 --Activation=f16:nhwc --Filter=f16:nhwc --Output=f32:nhwc \ + --conv_mode=cross --iterator_algorithm=optimized --alpha=1 --beta=0 --split_k_mode=serial --split_k_slices=1 \ + --eq_gemm_provider=none --op_class=tensorop --accum=f32 --cta_m=128 --cta_n=128 --cta_k=64 --stages=4 \ + --warps_m=2 --warps_n=2 --warps_k=1 --inst_m=16 --inst_n=8 --inst_k=16 --min_cc=80 --max_cc=1024 + + Bytes: 1130659840 bytes + FLOPs: 118482796544 flops + + Runtime: 0.945071 ms + Memory: 1114.21 GiB/s + + Math: 125369 GFLOP/s + + +``` + # Copyright Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. diff --git a/media/docs/quickstart.md b/media/docs/quickstart.md index 427fe13c6..425d92700 100644 --- a/media/docs/quickstart.md +++ b/media/docs/quickstart.md @@ -7,11 +7,15 @@ ## Prerequisites CUTLASS requires: -- NVIDIA CUDA Toolkit (9.2 or later required, [11.0](https://developer.nvidia.com/cuda-toolkit) recommended) +- NVIDIA CUDA Toolkit (9.2 or later required, [11.1](https://developer.nvidia.com/cuda-toolkit) recommended) - CMake 3.12+ - host compiler supporting C++11 or greater (g++ 7.3.0 or Microsoft Visual Studio 2015 recommended) - Python 3.6+ +CUTLASS may be optionally compiled and linked with +- cuBLAS +- cuDNN v7.6 or later + ## Initial build steps Construct a build directory and run CMake. @@ -31,6 +35,23 @@ $ cmake .. -DCUTLASS_NVCC_ARCHS=80 -DCUTLASS_ENABLE_TESTS=OFF -DCUTLASS_UNITY_BU This reduces overall compilation time by excluding unit tests and enabling the unit build. +You may reduce build times by compiling only certain operations by setting the `CUTLASS_LIBRARY_OPERATIONS` flag as shown below, +executed from an empty `build/` directory. This only compiles 2-D convolution kernels. + +```bash +$ cmake .. -DCUTLASS_NVCC_ARCHS=80 -DCUTLASS_LIBRARY_OPERATIONS=conv2d +``` + +You may also filter kernels by name by supplying a filter string with flag `CUTLASS_LIBRARY_KERNELS`. + +```bash +$ cmake .. -DCUTLASS_NVCC_ARCHS=80 -DCUTLASS_LIBRARY_KERNELS=s16816gemm,s16816fprop*128x128 +``` + +You may explicitly exclude cuBLAS and cuDNN as dependencies with the following CMake flags. +- `-DCUTLASS_ENABLE_CUBLAS=OFF` +- `-DCUTLASS_ENABLE_CUDNN=OFF` + ## Build and run the CUTLASS Profiler @@ -39,7 +60,7 @@ From the `build/` directory created above, compile the the CUTLASS Profiler. $ make cutlass_profiler -j12 ``` -Then execute the CUTLASS Profiler for a set of problem sizes. +Then execute the CUTLASS Profiler computing GEMM, execute the following command. ```bash $ ./tools/profiler/cutlass_profiler --kernels=sgemm --m=4352 --n=4096 --k=4096 @@ -66,6 +87,45 @@ $ ./tools/profiler/cutlass_profiler --kernels=sgemm --m=4352 --n=4096 --k=4096 Math: 13854.9 GFLOP/s ``` +To execute the CUTLASS Profiler for Convolution, run the following example. +```bash +$ ./tools/profiler/cutlass_profiler --kernels=s1688fprop --n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 --pad_h=1 --pad_w=1 +``` + +To execute all CUTLASS 2-D convolution operators, execute the following. +```bash +$ ./tools/profiler/cutlass_profiler --operation=conv2d--n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 + + +============================= + Problem ID: 1 + + Provider: CUTLASS + OperationKind: conv2d + Operation: cutlass_simt_sfprop_optimized_128x128_8x2_nhwc + + Status: Success + Verification: ON + Disposition: Passed + +reference_device: Passed + + Arguments: --conv_kind=fprop --n=8 --h=224 --w=224 --c=128 --k=128 --r=3 --s=3 --p=224 --q=224 --pad_h=1 --pad_w=1 \ + --stride_h=1 --stride_w=1 --dilation_h=1 --dilation_w=1 --Activation=f32:nhwc --Filter=f32:nhwc --Output=f32:nhwc \ + --conv_mode=cross --iterator_algorithm=optimized --alpha=1 --beta=0 --split_k_mode=serial --split_k_slices=1 \ + --eq_gemm_provider=none --op_class=simt --accum=f32 --cta_m=128 --cta_n=128 --cta_k=8 --stages=2 --warps_m=4 \ + --warps_n=2 --warps_k=1 --inst_m=1 --inst_n=1 --inst_k=1 --min_cc=50 --max_cc=1024 + + Bytes: 2055798784 bytes + FLOPs: 118482796544 flops + + Runtime: 8.13237 ms + Memory: 235.431 GiB/s + + Math: 14569.3 GFLOP/s + +``` + See [documentation for the CUTLASS Profiler](profiler.md) for more details. ## Build and run CUTLASS Unit Tests diff --git a/media/images/conv2d-fprop-int4.png b/media/images/conv2d-fprop-int4.png new file mode 100644 index 0000000000000000000000000000000000000000..375c0d752fb4d4994cf31ec45d82e701fa7d63bb GIT binary patch literal 391882 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%0DXOo3o+IaYz+Oe#z3HKCL@Wqw2- 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 D|V>UR@>O& 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 literal 0 HcmV?d00001 diff --git a/media/images/ldmatrix-8x128bx4.png b/media/images/ldmatrix-8x128bx4.png new file mode 100644 index 0000000000000000000000000000000000000000..44d50d9ae89d7c23be086a6480280e138286dd01 GIT binary patch literal 560084 zcmaHS2{@GP+rC})>^p^_tjW%xHze6gVI&NbB*R#;8(S&6B9b)`*=Hh>WyYSu6v_VB#wixsm0=bQTiP2_&}EBTr)VSU)ZIkdXEy(sD9+VJ0;9uGv0y z=U{N({TFa&DWQW_)dG!Sd`(CfD8UvU7S@hxJsv zWev!r#le#hkx%PCxPlD^@%zAov%fd0f+9b`aCOcV+?=kmv3U(DV~wk(EX@Otjq^3~ zh4T{saWuX!VVjg-R%ROHN+pnCu{sgdBkk?mTkLdTh(gSKr;=?Lc@Z~3DFZwOHWIzgqL#8K}#mZJ7ZWsS`IWwPZu#g(K`Fn2tSr&LA&-(Vr*X0R<>N8t0=fbg&T4H5US2kk6c)K)gl8na`)K=5v*vw1 zy=Kn`zv$VA@-dxEc~Q%p@+O1oo?89pQ* zPe~hu{_`F;zE$&Jb3#syqMy?i;aGwL$}W)rn7#Kark#PDo_If|l3^p|YIGJ`jJB7y zTBDuSnW+}Pxu#&Vfb>qG%b&&Z^MbwS|8b4%#_iCz7Wm$j(>-O7g68P=|k{a696Xpp*#T7B{Xd0sE{7e zdFpoa!NFi7 zFH}Wr^~h6xPkH|{{(9SCSrA@ci(eP#{sQ;1WWZQ!7^WQqQBRqqS|vV8TmI`vJ@51p zK$J9K_OX}m$edT9SLP2p5uDq6aQXSE(m1XHcwM&;-p4#Ej+r6Dm<4#_hVs8nmil*)$k1|6l z{S_hwRf*0AF^~+bla(^g(oR_$S{JOnEws(DEf!+6uudP%P%tyMqdGT*#$O`@`GWV* zi^i(RdPPn~q5ffSe#CeUi&f|F5QcF}OXbt96@w7d$|iYB2MLLiAf3F`G)9OJousct zMsLw8GbyJQK6KQLdD#GNR&L#yGsof^id6`K^9QHSqHQ}DA3<40jG4a|{22H+p_b z!DDRf@>HF5ifSS6VZY=xeGl|IIOf!$ z*oCGt?5+r76o1$YkN#b{9J)_nSZh`xd8*xGfT^orCm2m()h87@*xmW+F;JFvd~_8B zSI|=*i|w{d{;DB?Wwab2Bqe^0gt?>w9#!lLcj1v3)}q#ctv#m@TTlGi+z!G(9ME$q#D8lrcWFeWwd6ytUxbyu!^%v-(&y5O} z44AsLyo99bK;7p=jY<)-@mr{{Rz_rkB=l*zW)c0M^6-?2`yVX@n-X=DdrnuKX? z`+tXvtDfmS#qa#@j=r%}@YyBE&2=T>mnI^@ViKA!zPH=MJj<&U!TyD3 z1z6NJ(9n&**a}(M+)1<&^1V&S)$D5g zbUAclR~{4MZhueuOSn}%_x-K-M10NdZBTK&$Y53f+;aK z8|aL?PS7`Kv~RiKpk%iTjilkDf1G$ny77(q$#S!oHaSZZ7{+>Yg4@F>oz4JlrSPUF zfJk`B(&9iC&_J|0(Qyg1D~C~KIw=LCoSMyJdjosKd<^G~k~1o2wMDYL@SS|z;)Zz1 znosv!slxY3^hUV?*ukZV!c!=r^G%EAV0@9#UBa~&&O0AwL!uvvpiRzMx5lcNb>Jqx**tZtsP5jW z4#za>uBge#jQFiE6aDOP()2$c*x~*yl>Ys(g^SrQ4GYutzmNme%)P^`?CKuV9jg(m z73(BO%(v6YxfIE>4Nf4d(iJd9wRIVhlsTqj?N?IwIdh;SK8LgbMF*$*Qp!%jCWKrM zW$rsHPzI~7r%gWVqqEVgnUh&j(e#82`{6o#H7MbSjz&|fPMYwkF!n=}KBAqTfaOx! zzEqCs;VEKE1XuOu1>3DA284FVW?I1MoK)d!9;)5$=*%S2>J~MY16h`8iI6*~s^N-a z)~#F$v1JIs92SUeD{o&Uii$mgtLDg23>grr+g@PHF9xjrxrr)7qjm#aF5Q**Z zFVslx-)9Mt=a*h4K~D4XR!*M99&G=X|NU=3J1wnzr_BaIYO@~(WOe#5%*V^ZAVEHF zwI1%al#1tmoxrClGSFg^C_9i17+3smk87?T{UHhR0Dw$txEX7JSo(Gzl+YI*+3XoN z(Bt^iS=93IC^+X5M=lF6);_B>L$Ci^GgrUr8+=#hUkdL14fF`b3vzEVZlImoF_qck z(Js;~(dI#lWy6mEF8y-DMri;O*95>p!b5r``c{vDELTqy54}00cH#jueHGH6X3EgWYi zGdXiw_d_UE5t;xPwy~PVY$2J5-(veZ%501FtA>qOP5=R%G;_3fKHb`+Tia#iD7z`< z^uI#T-3uh?&*6F z!P6R5$t|UNMe~#J=uo6P=Rgj^e7e5)Zl)DXcHnP&(TG za3pH0eez5Zzid&fH(USA=Qga~#UC-E9OkqLR`&kF5vo{PHaafz;z`M+nom21efkg^McQ;d(%0U)TEy!N=q?&lRnDR_?~oAF})3-)d5G zc&5H(;SJ{8oXp(CIfJs=w(%<0?y9;%E8Wgolp`|bCC-CiK|6%# z#_c?@yi%afttnZJ4x#r4Z2MVk(16{$6K(_5`r8Z9*hq!9xoqKE?)4jKpbs+&NTzx} zu!O@6m@3q6{R=2z=16vOh6g(`ftLca5CEyUQS-mgyCPBv8lTT~BeO6anR zh+-?A*uN!9<($hKAELqF<;m;2xMQ?}MU2rpj6Fv)l5a=wwlotFosQ>ODn?8{D#T}? z74P+jNs{W?m@FT-4o<}A5Vr30T%UUg1yntAjI(tYeB6+iq~hw&?5{^8pAM98a5*`W zfcJ{=A~BJm5n>wlVD={Mb-HHKA9pb80m|O9k82Tc48G_ z!$X28oR*SnPT8To5D&I1RV?tzMe-ZV(Q~)Gil0`W`X6Vm>~i&K9ag!ev}mdkzq15o zBi{G#ofc4+i0KG!jgYK9bjfK!ys>mXh=w=#Ytc0~KE<7(4lxl{|idoH_?RGFe*HsM^pOj+d z?o*V>@x7t!uJD6ud=3>qm{DMqQp2aoLt!`7n)9n+_kJaB0Owx$(g4l|nP6h_KAH~r zGWuF|s-ndzt9A(og+?@RU2@SHt$NplJnQ?K&9Ht*Hu!8v}H+$g<&pR(=d%d-P_Xm0{JBe}% z$qohkDM4e-{nEP4u5@O3S+*BCihSc#{X!uBYQGadsiXkU`129qTVXn&9(r|0F89ZK zISeHsFpJSx>N~y=Ky=K;%tNNWG75v8MsI*xG23wMBDg(*3)PCtE#QflZS6z({FC z#HMT*%5Oo)Z*{7iu2`uOc1pqRw{O0{{TR9Jno)`}xRe3@qv7=So6#*OxR(LGWKjfX zuD-r$KR@I{N)+j!{e#*b(cz>TV*D+um20cd0x1_3x$-%N<-M{ zJ^Qse@)rda%jGZLm;5VSx=Ct|m*#9*(b`zKP6ysBAW3^$@Qd{6)vl`E$H&n;mMjkx zTn-1E%+wZW3p&h@-peO=^Y#<}%o(eZx@p9X*IOM2JBg{j!yIkvjRumS+OWf5+S)a@ zjP`Y-pP~13{ErVZ-&9{MBEK4?xLq{>N5+lD%+jloh>kfic2IK)c5i*eq%@dCdvR@?%CyB=7F9}{Mwt$B=OV8 zmb3EVAzFky#CN06XGHzOr#4YOy8YKp1{%_6Aod@ZZ0K5%GJP(TGv%wI7? zs z-p^i|=%{5q6yN^-g4OUd&GZ`n&9DfpwQOy!?gcQ${FPMuGFeWmXTRt}7>8}K_%@IX z?k~`rK?un1YcF~nkp-y^1GrB$n-et7yHhKH1fZ+g{`?-IXK_k#)kk+b0lf%gFs?e2 zj?>TZvMAc3D#Dz!g6l~PRqOiU72&SL6q6t7FF|3|D71gbXCL6d*GZxYh z`V%MWdniOe0hTQ1@0mnSqD6)L(ApT#o9F|U6`yUaGuk5Q_piEGyPq zbn=C!s=^)eL;E#_f#|G0i~D$bTfx+7P6NG+;u{tM{tbI!IT(kAp)Q9?&R4mJn0h{gp^LBAKH*9z3&XWC(kd04>8{^_Q~?y00n*pla*j8`!aNfQxyY7OrPO}06yTDCiB{PZ96jDU49_;DKk!JpxhMwgxc#Kb=ofI7v7oTT z(4vC%kj>u)T-=S2n=;CZ#V}7AG`;woEXoY!4LgaRt4sE1dF4Mcdv~&WaybapJAK7Y zb#l9AFKo7>`JohwD@@&M3i$x5HChq}*Y5W_6E+sp@Zet8>VT$EajeVehKVklLZ25K z^?JdzVJJYI*oFHyz2|sm0)CF!5!IsgrSBN_@m7wz?&z&B8mN2c&?Ofn5(zLzY ziq0R@tNVe9xd{>hv4Mm{GG;Cm#H*wq3WdyeWD#A^?gAlDOZpTKoYNvA;A1FKeWv4J zQMQrNbsd64jk9A(ft=buzaJb#2#Qxnzqi;4&U43h-TeyLD(>(pJdY*e&q8Z{x7=es zHzFfOmZA%LbU>8~E86Y9zf4|XcIfM%u5@=89M^RhxevGaTxnns_`^Crzw;?>i%z;T zc`uCP@b3!7XHsF(3??x^a$8*4o%n%;l*($v9fdq7E=oYOWz{0}>}4KZDP5W{;(9W5Kz9y^1qYBUG)GwAoGV9Q=zxvdo*!W6O?#1O(CaT(<+h;K=&a%rl* zKJrtuM$BFC9we(qtewJ-#Ekw(sSKcm=E%YK$-(^VnN{?chNcsM6Xs-yIA2aQ}{mNHKH zdG+&c&ernVT$YngeBzF;a!b-)VIQZnMmFao#za%@)c)$fMkO9Tkbp5#`-C2l__rTsuD*8` zIRu6j-*;I^#|J|>m)Hp)%_0eya){9scO*|*TG((m)(0N3g?i}@Q07%H`?7^GlHJ}i zF-%hdPd$+5r=0v&*}PuPjOba9D0+RO{=puBx*?kZ8GjP4k_>mOO9x~hz#Z=$8D2;^ zMzL0XWD&^#ywK*0R5AW`dgaceP{{b)O~h7qZo;Fs^%W=VzUk+?gjRAXc0cN61GN=v z_#+6pMSR5@@Hg7#3~8n(8IU-;qs3GEqKk(T($rLEV9uF+LH!;zX*2o90{*^nA%DEo zUH@E$D1#eQCUK<&aKFCI(znk5TON_%r-|eu24c_3+sIi4)zum8u1sH(BX96gT=Cma zGI27#-exr;pOrx6;bT)-hZYx+S4@B73w4t}P5h#oCz0yCG(#Q*vCe^O*0#2gSzBb# z?#<_@636gw4TYl=6Xq$5hqCso#v97i+6zL6{6RAu#staMT@sRhUT-r(-ax&PWc{1% zafaG@*#=_)@tDsG-&OToa}u_}3AYJ6uAzVG1xz=3s=u*W)Gz~d2=W-X8BCO~7;0xX zpTX7_bg0>2Lve~)X-&W^*Ox()HSSsV)fd!da)2>Yl7-s&h9%LqCyNxjIO2H9{g}Ww z;vXY!x-h@>AugpbYIcJ9CUfB!^g6={Ynp7NJ`QHh78ox_AH<@rM*(FTt$XEtVRm-Y zU?r{cWSz!d`8zdRjr{pPE^vy2jOp{0HEREgY(P{ckDs;?a~e#lz7i!f?+>L%Dl)ZNB^X#uL*ln$E6zFt(zo6-^?D0div#alF{c>*-@ zD?+em_Hz~XLtmtTagI1bylVy&`0+pjHb3q_H1F#Fd4KSs>zo(Xdb6!Q*cL{$eCaQt zVEX$2$#*>PAXK4TN_nSQ(8XMrD9-mg+~zf^IA?nN)XBO8?D>m0?M@>N`x7Z$9uoPv z-D;>~+F{j!_IKa0^qPRhH-#u;gaJW2Wye>=?GNIwz7na` zqz`?b@8Q(s4U)0AQTq%?(y5>-W_k(tW!@g{a?nuK=k1%)KOY`qqLA}7w_z<8(}`!(aBU4?T`N)3u!q!$SlpJs)IJEKY{KNqr2yf0AmGpGy-Z zAhUN@NErD$hMGV3TY_b&cUIE25gmOaj(*gPERssef`zKWxp3zu0 z@Yr%y6AN()L4d4v^2Jl;2ru=+i4E9~p~)y`o^59^rKkTJj%kjwi^F_nhQfMs!2=ai zr2L!~e+0Ds)~)YJj5OP{?1Rcx(dCG6^o)7xKmEBR-WhrD&vZ3N&ODU zHFq2r2lx%RxXRfn@3YAykz{=(ydcowq`rBmJPgp{aJ8s?@RzauF2Qup8C_UL64#pi zv(r2ZISy0WX}aaM=8ZS|s`jM-n0p6?6+QJ4CsJ&G3TdSgW**6;w6Pv>UQA1Wm zh9kcWJa=n!^o(tH37t0iTXq`{_GjOSyu{yc7^Ce5%l$UYwW4c!d!rv8T*f){#Vh`y zC%@zYIS{D5f*|(3Mw{0gQY*Li*GGR1G<=wiM%iB=2IUDvuF;|__6^WXXr%gLxX_$z zkBZQNro+Bk_MWWA$0FjVzpyn+6YcNrsrR!U&FLYOhprZFOcgQxw0?MpG1z^;LxW$+ zb}&aVJVZu&#i3Un_z0l*wuv`KZfp?cm`2nW=6(SP5Ah+u^4Efak31ldSsCUn`V`^& z#?{|~eQ-@K2|ITM`D0%3k2j^Rs@?lO2EzFt>l>Tr(|)Jc9q0V?x?iCBl5J6;cs0vL zTDJD&7ptPe#2NFe`;#b!n&qCqx$u$7ylmhUZVfw~qddOT5UZk?Sj+!!36NQ`_tT{b zKV@}ofkn=mkDg8rov8j@k+ET1)e6|YUF}(wNn=XfScq#=ko3? zgNYP>k6sPUiY{7eb9HREN6}0By%NGSj>y9X4AHAag3QOBKo;e_>}Ih}3RpIAssWS8 z%o6DRN1?;NdZJSpP-llg6Gmv&VI$l9%{|w6ib3z`IY+GZlH%+mCAwyh0pG&A0nh@Y z;P{DCH8O>!}Pk3*g$SNR+J^Vec0oX^-!uUI|(Mp4c0{mxY_X1%{tm&u_V z^zN`x1*EtCOQ5uNv&`M|;Cw!kfVX!g?694AI==Q@gR#SezY*aPF=3WUMHTpFutvLG zP93^6cK72Av>M_8TXCs|f|8a=E8wr*8qRs^AFtwTHP6=Kg9!zB{TW|5%U(Y(tNnem z>7H%Dz!yt@tMg`j>!$dfP`=-yeAmFN#FRkC(}t}2n-#KNuGvNeVbXnE!h zivOwvIGC~cgk%y@3#fuF##-Lrxb`GGwMUW8FY_IF9<*<*=H2Gvn*>;KG&BP8MH>6% zyxyn>7b6A6-Yk=I82uQz%kp}yjX5M3_$s3byhC+PbMv+CP+q1nH)ipnmp!hSDs(CsfFoZ7;GyW=zpv9atPfDDYQ z4Qb~=$Y?v!sJ_dAlALvwXi{;sIJ5z1Tjbgl=V?B(W5})O^{yhK~6hqB5Qwfk-$hO2r=BKUvBE zEh5SmpASd7l}y{48hmF1Eq_p!>f__e=&$OROi}6D(|He2<32=EkDLgR zD>4hXEO^p@W#3c6Br^%RB$<^@-{$11E4j6YJ@CoyV2lFx@7-gp&?hO=5pqj6YC230 zNe>ls=w{d2)~dzrhTEsO5-kJo@PQg0Q-oyOUZbcf2R1eTawV|t+*bQpD1>J(~-pgI6PlZo%GtM(Ys##cHo1BuRil# zCA4hFP~EEKZW_f~TNw!De-6>yQ5uitcV2cex^D>e+`d?)+wr9K0>xtsg_RX96 zBGDPkZkB(E9$t*0b4}y0rjaeOR-Jsp+}_)VSLe>Ww}0(&TKtiB*;w_kO@C(OR+kX- zCt-27i1tp(Vw_p*0LWuW`*FR?u>sr1JZRFL=Dp6Is_!7r(Px&i2N!>9Tz4A3>Vl>R zB~&U_4cN~I*L<3^ejH=T*M$ITlT7*OsWJ5YN6>qkGkFiB`e3)NV-}2<&4_T+pV<0p7mK?hgzW`~s~R(z~c! zIlavT4go|9Wxb;-bM$kfD<^&g26=EmU95`0kvl=;X*Qp)_E&cZZZ^!6t2#H7a~pPo zY+gh{$QQIb{UKh|aAfkFvuWdoQ*CoCcBw2Bp(ryBPEi8(k%afer^Io)SR9nG#tt@N zF+EK;VRs8YC;hk>?!0$hf|0$L`dhP7JoSny>ou) zPI3&)vD31skd;K5bwm^^vke)zZ+(!-yAd3sACfM47&%AF`ZE}XdKDG+$xfhOe#^aMni|_Dv>Z_^3FXdzrtgyH>3y;6ccxL6Cu?E zLt^rq5g2SY_Nb;%B{A*m&?B;BKR5+9gwE_Q>f6lv@aQa-A;FS%*K;hgErCWNS~oGn zdz;UMP~onGJ-cork{TV)_u1l@Usn0_L3*SUBN~Ya0O~+B5rW!|7N&V%R{~3*ibo_5 z^|2i$F|i4vaAPI7Zj_qA-q@}jGB3C%M#Q&uGj)T(jV9Lb-k^-2Icl&7|3Em zmX5BF6G~MvIy=T1>NvBn?)+~}HeTG|HK83VQ6c#gN#SczcTTlVjIXx9vQ*TUS1&nJ zxq&b}yvPIWQsTwI)$w~g{z}>o@AaY=GAqQLXLj6A7Axu9)UeXnyYTwrDu;)^`(V3J z4McuSJ$U>ejmTl0wJq&;w7u3#iVv~5Rnq|L2fv0 zE|PU-1u7vfMfUg|z0OS=Gqf$&{e!|;5hANYd06&`mbfiGiZanxBd(W&IPN96(EoOm z*~p?}JP4TcI+DvlbacHsbtmoyD6oEf+y#rh$2;Y25$oz^Rvn+w!>0kExZXspyNKh2vqqocH#QsT)@5ijRqGOuzc?`x%#o~i3!7F5ldj^2wQtPDlj)d=ye38h5dw~RY&*L!hx&ZDuZ_KLYr{R z@U-%r-yD=+WYLakJJ2~0>Qb80NAn<2^HVlZ_>>Y>f^3rLMpv(B>A^AQVm@s+Sb-$n zV!c6)o~|#%Q#EHw4#Y_Xt{@mVS&!T6`jj_#BB7^-$PVt6$XtM6iE zgQaQChS`N5d*okfx>H;81Y)sVB4T5OMJ1YwB#{wmEmx1j(uoFo;URK4R{VRDV~G4J zbN6Z$VXfRuFSP)VBSWIpgKU+Rlzj$#uHVpa_T`GD36C}u1m|#<&!%c=B6ncPdE^9h z6W4S<9dc_IN>-ueL4r2<_KxM$I)03S-XxTEM>ulN@!YJE%%t9|_hR{bMw%qE^7`{7 zC&XGq37&f9VtT-1Sl-6zFh5%GYKG{n3M*9(#q~ifGH2DZ17^m&2O4PF)6wV`$63oy zA>)ZYU^af^K0nSURb~#)fgJuerp8)x;(AkVT-1BNM$7VF+|2$l(BOiV6R*z@Mku~F zlT0-}Uvfpy{G=5fap#skyeV~+sag4Q*g4Vsk0OQHh} z{d({ph^jG9vWjDG9mi#|;a^DhHgmm=17DpRvj^L{3-Y&{_8xz#8E9yTEarDMYbtWt z>A(A+ouvGtl)Nu9Y4qXJNfAmPj>|=C3AEi^3gT#@o~Pm0PpG&YUN{;L)v*W6~c+Ub16&4 zZffI^%Ia`IC+O`z_@b<^F=AJ_M+ITuE!3sh9SC|ucm*0+AN)*dfEr@k-!UTe;GQiS zf7Pf@EsJ_cq^W=+nVQ~B?In3c@E>yJoWTy{6#}Qy0FQB2)9vZsv?V_#25z?Z({i2484P_7c?#42q-hmDn77uBZRQ!@I&S>i4>z&QVjG9S~xb(TBx$C zR=~`PC00LyZ@mp^;qPu2>^UQoE|}Q*Sy$0~s;~eU`EJyY=HV>;l!5|(g0B@BVv?2# z?2z**I_O|qGnyQ~DOan2=!5MUk;%@p17L=Qzx%a17W~U1&1~{ZlD*GMtoQ6)OV^${ zPs^y4yLN_Ia!vtbI4N|qs@|9X*re(ArHQv}j=v+*J|_FKvQB<1-nOow(Jl%(KhnMA z0@&P?gb5WlGrj7Wv@Hc3?FSl4k@m0JJMMw2&w8nIqv9ttm62~}-r5vNf(k!;4-ZOU zfOG!-kZ9yq5ysr8E>KT*+Q;R@!qap5v;q28=@V=AtLmFOz7;rH<4e|#(pr%{A|s-y zw|MDyOM$Q2UyJMs{J- zI>B_NvmIOi;&_~auZ-V_tj-;uN>}}cJJ*HNFzZvRJ~8wcrmWxky_cs$D;pa$L$4#K zS7;CH;3Qb+;eUlES-yrR?4nZshO4)47|3DL`&SCW$9HsczKvhwCBJC5rth%TL;W>* zHk?S1?+N8V+;}1~WucMfrNg`#bc|_rx%SB{ofJ0U<_R;zE`0Hvb^GGs1yzMl^zXYt zT?-xEFL>?}PSwy2ykP2g>|S|vuRYZH$1a)+&|~BuDeBxd=i!Cw%mKF2ZCfsEy7&6w z-N!GOg~e2eA+B{Ay-#+!8dQ-CdGN%6wzzRI#S|?2g6?!u$b;k`sFs}N$E$m*v)o7v;I;si$dUfZC|A9 zvi*qUXK|m8XT4gz3^slu#@?9=B)0PcFq4J_YJgQzBrn|9ykk5xBeCf~O(@#MIP^Fw zj~I#SNv&0LeGP~4W<*SNGapZ3y-7U`zK-4(DO+*%LIhcwqc%paVb1r;V_Z|MU6n>J zq78WAco*f%|LIdqc9pUF;e)WmHyl^BWy70bk%M(Z_YiMo%HlQ zOL55CZ)(13P=Tb;Rvo@#+t!4lTY@VxQwu4TO}7Rb*4_8CZuT2@`rFf*V6hIpZOH@+!xb+L?L10T@DkI`tvk+Xoe^}@BwMJBxz6Cvw~y4tm8 zxSy9lxOa368oxr&u-!d3*&lLP4FNu_oqgzb?5{r=G`v{p=zOg+|DDUjWx-0Db9%n) z{txWq?rL&X=Ln9Z7pqt-hU0gX`KQ0m?c;l=*eEGn_n#0f76+P1dKg1NaXOkBLUi!B zYDOpU^t>Q4lv&7o8+#KJxCwqJOu4q|<8azsDMAp-Rqc9oAm49SZl0TUO5nX*lfP|h zI}!u>Tpx=wZPLm0Wv*Ev1nK(+$9JIOW~?~%o@rVnR2C#!7kQU)IGdiSSDSZaZDY`_ zyCgmIUdVyI>3K6UKd(}VL^AF|JuRa^NRB zd$)BxsLA<53~uRdL4>0r6@Xr)vLdAjN2f>D{Rj0Ee6m?h_WnQ6^)Z0;J&BIeFl z8lknQRCqszU=%1g7WLF)uN2eAr+QO_zTgpHI{QZ2oi2Izqs#ps_0gv%Oqom8_=?Cq_UGjmCt@?@&sXUVn7lSmSzK2ICZa*@Gqc|ky2^wnK z1E%DPZ5jXi2HV-7JHpYPo1u{h-u-)@9Siz1`do3hih32vS|iNRSI8l?McZ>n+@GF4 z`;v`~2b{O+mwy?yYjsk<#k(%Kv0^{5G-t_Ka1$!*Nh+tThexA=1 zyF(Hdzq51$&5tGLou={i{XS27jJEEHKAcSm4`EsLQ+Au#qWt*Pen43?8?>bn0exOUC8#l3M8evdnat$C>>L4ep z^&`(xWO)9jr__fRpVD=&olt#|WlthpWvrPSLlyw<@75B=ha+OU5szzZY>V_$KO)~R zBG_N-r}ox4n&`YMVh*|Iukfy4ETtG5EalBlD*+!UhBoEh!hcNL>F0>Ch%B<~1KWFw zhqE~c13z5fRlaNKAQ5lR&K-Wr8R;@PT8~WreAbz!eiP`juj!P=4J=gC=oWO9T(hhi zO{lUwapjMeiP|d<*Rq2lTSZEiCJbWF>rMGSxkr`CO|Wmq3B^Qx$ZAWn4`UOxpp*sv zy+m~3!M0rG3 z#ds);$SG@2NnyLPJe`^Hn{k!+=f%9PZIQ2a5C?Ms*n%g9$Ved^Lv*T&yl|Gz2%ZC7 zB1$}X=q~uPSp{j$Mv`s1A7G!u9BtkagoW*FpEhMtBx?aSKnaWm}ZK4I? z_VYeL>$e~7JVMz;C>^WK+i#9{I~?TSw$>f#+DyWFY0W+P5eK$7H@oH?>PU05x%35b z_Lbgu8EfJvT-vGaXAq^MeuH1${=Lt}vCj8_zrX>s?yCZND)rf=d2`@N7 zLXI|V8u-xRvW(sp@}A0TOmLOzURjvVAQ!`us(I}mZj33n?#*Bsz+ec*UURPWs^5bT|P+`GHt95U>w}`gU z1vZ0@eMA7ISB7+?pHmhUnS>0j@>52tHO2p$!7dCqdK70|@vVC@(?6N@Q4WKFY^5y9 zES_7lCK$QmyvX#>8|@tj3lEjuV??wm?dP_aue*#CM@v_>2bY=2>^2SxqHRTGyc2!GNC zc?VDL;rl}6=S{);cLlv<&0{zbJyZypjS(`?Ne2%fU^1~Xjn&`-p}kv%l7xF6F*s7J z0&={al>}Aeu3@y2H#$q?$7&6ViY|t6ShjHiKG((DJJ^Pk_X5D@y^2FRVn!_5d`cAg zyhv^F%XwOSku&l#Y`$^X`aHhjilwQE_s2;d=hyC3P^CSgFs+Jqu_MRo^bZ}Q)CT4$ z+^{!ltt$G!V5iYJ8+QX+_WhfB;qAX9vI<2!GS{3ZXq|rJ+!iHS+Zdgvcqplx*B9@? zj1rtSJ;V~PVGrDGa51#EH5**GLcY;PW29@zyTy%-o*Uh6X77q&9DCw;NYhWf3?%|ajvLk4X2hJaxpq?{#f~!7Jy{a>F3uE8vfOMW!n0^ z!|$_Q{q~JtmfzTrXvO1i`+cz4cjwaMgn|~X9f|qI1CGMUZWrdlBh7$b7*lnfsgc9} zO_htcFl;vYYP_z4b;{y;0Y74gloCsojn76YD=a||)GKCCLdp8W&4nVWLlc|cHm&P| z$@=*U3;|XO6paAr>q0T@&Af<(zKb@TT9c6Z@hg<8huGcpSND(={3cxacb@kv(DLOs zmk97Sl9x{QH}eK^{Y%gx!`_^GwwC1W2rC?cJO%#&`FHjx?hs6L@* z`^kf0LX6SLX-~uZzdr&53NFt~MV37_daoOKi8_i*K%~=Y%i|8Ci~XR`ZgJ{r87^uz zY!_p>y4Y$X4WDYjE<`vfDW!L<2-{?=E*gHRR)tT+HsM(6=(zj(eA<=8zF0`N{9a0n^pE@bN%k_cMIVpoEy4Bcjh|`s zS9H2nj1pv=xul8utaOIPgC3&*0n}P~d4-z6phzJ#-2g!sO+d=G_7bt2))8;}Wiz8Q zw**TBqu8jAiTe^8As)MgKAT7_=zivlKRuLc1z`~gd(+8*nZuawA8zS1i7WhkmX|sG zmaeax;~C<;n}3)d*e+qhrWJO5XzhWce!!B;1k#08@s?M3>Jh^#9xK8QTqLwQ_abTN zs?6>lE$eA|@As~qk}`Zp2)nh)Np7MwIksWbQdMFL?RpN{RpKE51)u?xj58-%*J0tR;>lM_V0=#AG7duM}@7gi#F( z$&7HLXGlyIgRgael~QAJI3j7B9K$2gMT+4$$=b#(WyhivaIG?UdT^ft{*`z2^ zlcmBc>RM%%*GpN|^921Gb|2nq2qenY?cj#;z$c6^D0qwmQHHBwOHyCyTDcO@ulcr& zGOnP?8^pdn!FS9k?r11LopqoQ8|sG~)x!+j=VtM||8x|RZu@;0<x+e&q+ny-?}3;_tnwKNp55^t!|n zq29SOlQ+9L&0~*_N=>jcsAm|{sD>xS$wlUFRZk)0c=Gc+9|dT&&)e@|-pNR-cNOKy zb!AW4QWQM=IBBn4yu1XeR0}Yn8m9et_^YihTZ#xf1lybSqlH@XrNQh^N0a|ksd~LG zagUdev7BD0r==fc57;&i(y4{6j~McPY#5XSW)EavkH*vi8$FxV594S^)Lua-?Ug3GC7kf_XAHvh-UNm~n? z^8}!m1tH$Ach;A!*~~#w*%gi1-=J~2u)o^g9wHkJUaVc)SXK&W>9V;0*8&slSFk{( z3%bo`dcm4Kk@qTqJzlXxVE8R_$Up7zy7PBUCn+J8^_+Vs!M!xRCi0S&-h1@d zEY~x%f|M7mmyAXM>e!JMtp2Hp<>^kh%4k)cN0X16R7E962&yklOIJ zM;N)pj)^K^?T?#Hrv`&?(H>JQlM5sj^nS(k`k@@F$&CoTc=L!u_G2#R$D$3w6{gigAY5s!-~Q|ze-YFWM_IlZ5BqB zIG>KTdd_SubZ~EUmiGsDA7n8fK|g>re!V;#+LmnMDPMM}GqGYA%HUNlhVzkvB0ym~ z`s@R1=lX}lBjqrKl0M8IL|1WTzSP7IgLXXIhmH*0vtsL^*R#H%KnDl@^K`gWyYuYxo=gA|(OE4A+lqt5nk8ikgh77E^??v%I^voV=I? z^rr~wCryd%2Bo;uY2J9mtHw0QAX&++4g8=+O>Q4CgS6ZG7KGa5W6cja=l`M#Xpn3# zq)onWzhmzc__S(h7-rNc`lsvOs$v04m|anR6H5EcU%i+7j#2g`%kh2=l*W%4TO0}i z!7ymPT$1!k>OB8WWQ&H?LCIsZu+PJ~CZIn<;8~WNW4vCi9E(vA_YPh|Vo?!VwhoI& z!9drYiduhqU()j+w1gba%nS=+c-tzQTd@VB-F)?Vtv92uU~UBTIfrUp(Vq~ooK@7Y z71mpvOfgHWOT`g3ayT`2IR2JbI4p|gBpmv3+u&cAG78+bXe==LEO9az z`Az(`e)JYmpP%iVU|%zBn>1j%CBr@b|k zqmp0ztS981JwGQmPr%i%=m~zTzrC<3>uD;!&a1k;FfQu}S%d_@MF)&YZJ!P&XJrbE zn{K|~PsQB#!01$>*zMz3k3vtT_F(Y0O>G(OBpfF@=|@ZRYk&0(6+gehJTGZVX7^Z! z_r7{9Ye9|+=`(fk9z4M{Db{sY=1*mYFt+~}X)4`@ezqtMK~ph-Q>DXB&(L=zJ!DrC zZrRQ?fz<1p-m^W`&E>UnNdC$r_9QcaC(jqIT{P%cZ=mMFf+wbdjK%JcZA%f^#k!_N z$dz&B5gFN6woQ*pjNP`&p9H;v>NNL8vtktQUodp=^q6DzJM`Xbo#XFUgun)8s!Ax6 z`Pg^+DR8#)-223X3(`$#8Lr|qW5zU%Z6ZFu_e80<#{>$R{${^XoPqeyUNZ+yJlNsA zBYltH+YggEje><>XDb{lUjYP^a|Q)mB`nYQvL82%`{!`Tp5R3JUNNOcs0~ZpM>g3w zGKIS8wj?4s!w6>LWy;TV^-bl}sJ%(*fAVgdQm^8oxVprE~7>f_oOQZlIKZYOa~UhW(k2GvS(Y_yO9 zmXv}7ErKIbzF~BK=M!6n+_)YN+JN04kAkxW5h2ZHIRp2sV$2Na?;JwYc6hxs|8}cd z?1;>xHODq>U<%TUmtcBpjWa@B%O3$_n=Gndo1WW4lbcAWF40kCXFs!J=(ukwmV-iB zYVZtlylU}a`1Ae4h_Y4uqK8fy7vVq3{!3}og^CmBomaLDvK#~=@pSiraz)1iyJsZx z!5!VJcQ^ifB3xmuqvneE#lBa64NH5C&Q_9D6%Go3o9>*s9~6E(i#vmP#SB%x%1$&o zr(IL{*wpjthK#!#_pqSJ26Rm^NmqDFhwjNp`4Loi?tb^e-Vy5EjpS#*70Fqu++q;3 z>-h=v6OAxworh`|Jp;dmJoRCMJiWV$K^Zbq7RJ(sQJCcmTmEZJxJPI$^~ zJ{I<^(WHd9AU9@{>k2`NoDdWCl!~sK^;7T>|7%Jk%?m6M0cO(uY{oN9|D*A2Pif@r z244j0(vD*Pz$d6b&jq!x;m5{J|pLF%%(7g<}8xMl|`!7w`+t z|J?T9Zn`FYI)C2b^Y%YC%pDL_21hLbi@JM0d{! zzbhvE6&%}aaV<$&!jGV5WC^}AE4OP$di96U4zG#aEw1vPoe;B;b?1E6b!9tQW7uIz zq7xY2SFIHY{+=@*p8K?xtakgbtOHWVyAxJki+m`Gond34bE4k6XKQ%KY~H-OY5w$p z3$$rLbtCIr^9zfke-}9k3V`cRgjMrUlZ_~4kpdpE)>+y|A3vx@V=PQXf)*cyBG7Mex47WCp0z+S=XK9X%5x& zwSX2_YRdA7g~|Lq;pMof|8tW_dwV(<&WF?GPs$PNYE=x;EN;jZ{!{Z-ju{CV;APcXyZW19CcOqfl~ zWAI`sbBgknbWO&?+Fx4VnVA;PQ}@``zLFnl9&|hdmURCy(DP$IDec~Gv7K2!#2~cx zwSQuVN)cG^oh>KG_83xnxB*LR+=8*hylb41{+aX&um<#aYw_F3y@dH6?a?nn0Gc-M z>?@=h(oz_q({E}R!Z`n~&%!hCQ#EY&H0r@ylR&hjsdUGCQlhd(vKy8r5Vfpfx8)lO zDLEi?eVzwu^xf9cA*5Dj@*B+d2Jrl~PiJ)dA4`VQ03nhvv!Bu;k4eHgkjJud=e^fF zDTqXts(Ipe*1WuylJ)tZwS}9L7R;xaLY(71u=48}*X)1YB*TwyO}a)l^6tlEx#+LG zNa7XgiPwcd@vvJOShau7Gu603WEvml+(>-9>Z}%=$xG!;>t^pb(K8NvR|W`42AWs| zNI;;qWFZtogZ>~bb*T!^W_qssEsp4@MF z)enM1wB+qpyqPQv-ww$WM|2k$9T%P9+fI{OG#Pcd7h z=_{Vw;v&bio&%RJRFkL(K2K0&s2vU<5Vi0yff5HgpPgWrew@VgAY8PMhDpXDmY1p- zJer2$YL>wem$!m0o?NOu^R@6>0aE9S<_gdON_DL6GlxEo84qNkCO$HY_fjTy);75- zU17Iqx<9h3&rfBxEFDYOoSx3D0UWfAER7SCJ}^yh(TI|$>RML0e<+xdX~R55ry{<^ zrTz0t4MR;l~b@x)=NYi|YXzzn;CN`gS(X?!IQ{uOL>!7_M zFo=_I#PcCPW#1S&@CMmWyvz5j)4!t*Ve`S6v3@PX&>lO8FGBR5v)?6w_MPJxcYmL< zoxUKx2=5C7lG?j;RqSV9VfJlipO8mJ6eK6)fM~!=(RS|7QTjJYrg1Ii$BHmZv z;8(y%XnM4X_%`jhtE@>lKe#i5ZxNK>e{u9s%+0e0z8Zv-^<8V)jj$b(aLI{iW}Kr$ zPI1rs6&NO#O}efg^j3=dAH5<<=Fjd-ZP%L_{`@!~jX!!Qnht(;yj=X{KSj0yBPYA>@Es;^vr>C6(fI_-Wc zQ(B+ii7^|b_!|NP!R5QuZ1qMKiNGmZgo zV%w>@wEJ$&Xy$mj)>j6kHd@=CYWEUVQlDV5OtH$vKRaF#)Iud|D95=O7Z4D8A%(nr zdfoE)EcBsY;7;#!&u!w|E)5~VLoa-gL04_z`}Lz@Sg^pU#A3}zIM2WdG>Qf=RnxT< zo;odk#kqTV6l9a)a%391^eO6Zn-a!bg63mb&VX2U!}F2FE+K=~uSILyZ9deNKZg=y zN~?!L$VCz3u=k2$(FutKKSZb%JHJrB`ufy~lY^pH$v6}Ba_35$#zb>v3A0LtD@i*( zFoKRs#m(W5{O(Eap>{wACI5b+3>o4DW40Lau> zQX*##>%^Rx@z}D+Qh&yjx{)gP0NPtYN9vs|(ds`M+9UCL~9a#yxxvx^#?#MiH>8pP{PC zG!vZD^lCAp+-;r60nnu^Enu5`cZ~>xc?C55ku~*5Q7(++h~maPUutLv&EC#<69qrP zi=w)KOoxzlx^IwbV$~^R4&ziQ`Dnl#Sa`q(XB?&giRQS|a(0UUKrVkCG<`5w@1-L* zdqA6Zwhs^fWU^P^c%ji~GAMDR2h0(i8RG%oIkH`gnez2};h$UvnBOVb)nQg;Y2cBn zKorHrad5jQ;NYM;O`N+aa&!b$UM!+vH)rbIF5eU>z2WZ>N`^$!8Ne$aCPqA~OK={d zAskC8jLxJCEGtCP1w?vl={A$EI85A|^9l}>5_~Bq`=;hLS|6aqK-ZPdcn`V9hw#RUo`8eX$pq;_7S*MPnS6ZAPjpfA;!lgF4wrY%@AV}-kA;m@x7VSu zd7kKNxN5tT&I189tE1pI?b%h-VZtG=euGqa7bCO}zYQhA66g!`$^Gs;1|ek89L5MX z%?!2L20&);{WvUtAcz>LpuW-y3QJtASq>N4kKlOFpV~2q3nhYZMh<~Psvqpb(G~S9 z(bDg#{l2vfQ%mam7ZS26yGyzrWQDSaO3M|H?p^?YJ)@J;(N+1fk|7f{`nb9%3UAlI zTKaMn9$TjW%p7C6=13T&$Z_*ZyXSx+hd*=o9U!{q-LBm2d6+N_<9-J2PgU(Xcs7aDz-NN))T@z zW-|wA#GoG5f03I!DYI9X?xV_3JW=AM-(dQdbcbA&9dyyr2v9OB1V}9Yl;`m)AIwZg# zVExTLTa~O2mJN{Nd6mI|U&14AHMyV?K(3iF-5mxxdG0MZ|D~X2te&V_)}f0GM6G7i zlI{LxF@3fd(Lj0^-@dXx8n-h#GVdhaDJWMkmga_Pt%hP2D$;}zd)NkD{taAfBswtVJ)T$+ z-@=?IZ<6Tfk9!2k_z(`vI47VZ^YAQt+@ zMMPP4V`CO9bM-09 zV2J?CmQdkzm(?Y3dtq8-#896_+xWbIC_L_7bzr6{HlQ6!6FC>Od|=cFRif}L(i>sC z7-C-B=T+o$`m%T7p)>_rSVf$LtcmenRD6E}{L-wSF3H`gR%ro$A2XC;w@^VEp)w#G z&_EW=7ESEt=1uAQs@IH2DyaX>TH*VnUaJ6g9!=);-u?`eYN92gJIG+~vxCucXVW`D zp9e(FCUxS8I36{Ug0{-WZ%zOBIbDoatC{5(TaBl46i0*&N|bzQi!@UxHZPIw!p`?S zY>Gt5$QU$F|7pb=m^qlSGQ^iRY&dhWCcoou8VzHNY}{ssDS@DD6mv<2F;hkHf1|uT z8js$rf%z7NNf&!v^Dx%}%v6ODiR*$hJE3BGCw6mq#P&XcJc~~p3Z9PJ{0qd3ZF++e z9dr6dSNwyoY*k~ODaLZ#9f2Dydn$xoN1{>)idmi72LF*Ljy-|GYV?jdhZLxt=#(y$ zTZ$~CZ+%*P+AHTHE2KcEsKaJo`e1ukTO`N7-h*E*jA5^E%E~1YxPs*v=|(jChyW{$ zJ9|udt}hfSXv@2=4UNjf_!C9&h;es~Ru56%_VCBJ{{hm$&F>=i9LH%SKR{JBV_J@a zqwkUS5SEmwdGXo~oqSnY_+W=K#v{yJM`mr*uK>ki)gplZ{Q4m;VBkZy-zDxUkpzCE zT6g^ZIrW+CeBOo|={}_-z+_&({Ns2ZF2i+OCV-sn=vcEBO48n)nyQiU?Cmo7-RHi} zQhQHHsV7a5oT6Q)8ol;by92%y-grLDG&`=Z`Sz|SiDTMwW~vQ%oSl{)3!V%BMYLxuLJ4m#~1?D4Ja%y3x`)?y!jRNS; zqp05a0d-BB3*fivk1*^NSjm-Nl?%||EloJFu;Apjn>ywhJlUI>@WWs4az*ee z1DlPQ4BxSjeeQN=Sr!Q5vo_g1Ah%ogguU4KI4mi46~J{?VDk5vmoHAR*@TVlhsVLy z2+BkEY*hDmT~Z6a;WfpViLMzE!*{oXxQLmFbXxhmrctNt>lXp$DHpI37A>zoyXDHB z>QsMENZ@NDTxFm4h2XErRkO+CBPACA=DmFo=VuF7Z<2`T$?FuX?iZu{Gd-!YZ{<&| zfH)OuU#9;=MLh2LfEDQU`_BMjiro{>L(C|=yh*mLiAo$I{`vQz;d?15Q=ukHjD=VC*WtJXyG; zr0Yko7--+Ii|~O>xWC>OO#|3CP7vduNZKGuD zf#N>(AVKMLBviR{187PW5_cjS6>#s87@vo_zw>0Tya}mqnRKDsF$fR;bFi<$Qp_1a z*#k~ZrQVH8qsEPyqZKIr+4L2n z`ug%MDI#9#st1HSoIv||u8?UpKJ?>_*BjEaka-=t1k)wWv&|eZ^OP;4+&{vuTo#2hJiAlbTd}?^(aNt4ELooAg13X=hd;-vlf=Y#+Qx zR{cEF+1~=tv{N3HpZg;4T$m@);p(F?cJGh9{LeZci`=e6cO2DsgI8ZrpUjK=@SF<_ z#^9j++Bz{vNBx$BGa%Eux6QtwCx*g8PIR5+A?05MCF6G-kA=VZMn`aOAkWKC7}OvU zLSD=LnqHs3zK&{FSEyG(I%nfV;iwQ`#%-hP`0S3Iv2HL^AxL@;@=v{N_-Gwkl14sX zy1!GW0W`MBO0OEh8JCGc?i6CTx%|W^B(@&ujd`=(o(^;b%AE=#md5cmLgDY=^XoA~ z0c)accPILIQM`OM#>LYS-@Iz%3IHQaZp@Y#A9#_Zb|^NMwn-SAO7BLkiyL9b!ss2a?6%VsxH_DO|3DihYw5>~1A z{l{nBx^9N#ib02%b&C|A(by!f?E$5>ibRnb7Q6$z8tNIh%I4slbWN3e9=K=9H?AAn zdk*mDDOT0|hmwVaup!y$t7xO@w*6r|`UFWy99#7f>K*~#sR-$fzrpc08IcS=WTNu(=?3!fICl3!gIU(PU_SXPk*C~SrYG*;*feBH5*hXjI40II2 z4d$Z%K~YjM=9^}KQb{$@FmaBnBArNHUr>er=?d$U@aBwcF_UjHwP5G1M>f1{92LHB zqI=zAZa^52i2K^4TLh}_8yqNf%D&c)#zfiyqZGgNk_2`2soq!Qlf{K{D&SMOG>%$) z4b+oKZnqO(ir(@Bg(Y1B<_uVhl+jAo4&EkXC%83Zsn%Vz*VW0^*6P>{Duc%{jBZaL zv%^6zK_;(#?8z4pG$f|oHj2&1GYUcV%ewtEjt_F=2uO6t9VK$+;O%diqfPr$gu*n8 z`5Kq$f?+1hs+NXF;#MErdDrkhQjM)>cT+a-@*z5N+s7xX9!|eJqNilh+h;%F3ca@6 z)##2Y0^B<`?p2-9DB}2eBZMS5l}@s=Q_o~5mX~QltAt(`KD8X-mN)Ph9Jsd3?j&wW z{Qgjr+f;5PBEkm@n*mbtd(B-~R{T!|2WD;1B^|{W@ ze6sK-DY-88)6liU(9S7{!WuKsa8xajdo0f1eJ>q+{sn#u29vF7>3r(&?~}mbhSSeW zH7(<*t+tjzsaM6ADOM2a_r{N3gws>*zNbeN>lxRw)!!a6Zirt70AH-AE!M&1nIoyH znu2&{#|i4|%eeoglFdgSn??yA9|k$By*_`}GDkz_hJ|BlWM+?Q%K7bBPKA7EPyIKV z#whr~tbZO-3V-1%6|e&LIK8umJ|MN-%2T@kSUT>w&_`MvbZ)-UQD~-Y_cLc|_h_%! zH%~fKVvB&+s=B=PIJ*;Vt!93!xxtKnMTj`mUa|{sv@c+bt|OZj`P8CXm~~PD=Q&Q9 zW-7MfZ9*IDmt-k}O(s6kW7Vpf9FuPzCEOzmisjK1P#+`kR_zguZtQl_ zq3TI7!jF&aP6V7^(JNraJFAa(Rg2B}M#f-YK%U^jdw*`=x7jh0nZ@ELkF|Bf&}msG z+&PBY)h0{{v7|XhWbIsHQG|4blAt-czval3kc|RL{H%K>ri~9GoqO@X_#eb^sinI@ zcxKaUVTYeHI)ALR_S{~UYu?pIVw@f(nvX!U&f^3til&$LE!@iIn%e~hOVBB3Uj{YK z;UiyrNOIgfZB+1;?`3({@`2&WsB~LES>em|@Qqt1Ng?SHV(IbRIWF~7O_(9b^C$S( z9SVNy3k#z~lpmKAYR5jEL9uJqo?tu8sxe-!Do^ADvB{@^r=~Id;rTN2EhiSuLjaf% zwYDK5;2C1MqIsuH8JSXszf!*MdcT{+DALzrsC~479DwMl=$Z2_3Aa%kbk_WiF07O8 zYW?M8OGEJ_9L=s@YnQ#!V_FhgpTjGldsW({Y1R=Y?PE+4@ko23!vjVva1sZ8V+}-o zQ;9nP7ml80>XKh^P6F<~pLJJN#hrc}Qw?Kbu2oFF>W_1t3@*(zqitE2Bpny#f-;A3 zm#tq%$6tpe)%?aOeEEMqMts2JE6y>e{MpJ&1P-yI$F=%K(0PdNvE8Y~B*0vriWQGl z?{*Oa&L+kE(qHSS-Fj^dK;FI>l+dR&saMoQzy4B`0bo6zd9uSgx&HT2z?*Uv>2b4$ z_@dVGLjP^3mfL}4sbN?;w`;ik8}Ug%*85o`f6qfYKil-s!F%ty*^0$K)X_AU5pQW= zRZ}uNt7>QFyC=-fZ9kbubKh24k~pr4d!~_tA{0 zcOliCRMY6}eY1gf(3L>dRdea-q14(p7&FBzgGuVBC|i4JU#BSC<7SGv7Mgx>y_7X^ z9`;-WBDSX~;l(ANABS}h<)J;24h5!>m0$P}Z*PvmarS;_wU%##hU&j_tv!ZS&jhJ6 z8D>uFVk@Y>*c?~ZUVF_Epd##M+CVDOr<((OMS!L-|;y0Kyqp|4x(wNbq z$>6u$in+h8jLHQQSyle-@+Gd~NA;h$1XwXh#ciByzFdxd^v_9K{xMuzrA3VJv#~Pi zf%gxmU2ko_yMdQN%QUr5lYo`or{9zmq~ra+vdIlBKw|rMK3%sB4+l*YsCk}ZCnjFy)*s231T?|5ekjv5&HwCMCj)PS;=?N z-AdL+AN6ca_SZ)q@U=146<4-@R4c=+cgBvnuZy{cM?Pe>wo(h0*u91kZJ9{^6i?0j zfuXlgqrI;AN)er`p>OUdUss}!6$p>XCQCVgpLBLN2_dl+leuEkXqrZXLFmFH-ANPz zej5if6F7eNF%yi}M$)Lm#)b>|InQVE%KQ0#s}!5mBY(SPuHC{mi|wAOv1QO@0~RCu z|7Bu$eav356vjV}uc+(Mg0Ed{M)m2&_DlzB8SZ}lEg}uw3?W!FrdLaT^nXUtNKT{n z$dBtuTYRrZM)}GIvCK=!m}M=O1DsOJ^|Tl|t$Dk8DAsFuPOdYw?smZh0f_MAStm2a zj~DjwqAI@vH|ehwKNhOo@{J~`oC1ew7sEtC=$N2NqD$T+X-kMg>dPFEc^d z6-PMglkHme`FcEj>H<&MrHF%#SdMgv6mXZ+jqPd=(1ZCZPedKrxGt`gex4wjQOKTz zc2NZ^j#U+d);Q}FQf zLj7XF7H;|98}#TeRX`81FGj2@Y-41wZQj=)8M;0Wb(IlV|7}|%jsrs^XX?u_ zU047(7^0c^bnqb*b&-DTecX%II5Ej9R+3p-9ey=3Eq{Czy?yXo19YraTcRd^J#XA& z94z5XuHF)<5!ydo7Jqk*q(xxv2Sc{ms{!o%HZ#Fp%(v;c^-q%9qlEq)!fg@>A}dSD ziG#(n9Tf3s7B%q=l%(}MvATMel=eC8-m_L<0FZuc8ePIKz$hV$e@(Dv5A=xwr>y5Z zbz&(ZANk>OU^yvPOVuiE@JM{925>a))_l}lTkzYAP5FHgVWbP`JwG+fwu~DB4X-9YS zkS5%1oAvr=mhu1--VK68>dHJ3n z$q1ONrAH-O+v_V&dkdV}xtPenf+Lq>->^czRk5LG3us4PNDp&J!(Iq%_hEg!Y#|9u zNu}b{bWB(OYp6ZyO79R8BXPY7UIw6;&FS%=#4Bp3>>qcdpsOfjUnF&A8vW(x_arSc z+v@i@5E%DYCGPxJ3+g(Z<_S}@sP;-w#3**p?7jnYt_zgPye1B1n?CO>mS!O9#CtoT zg{A88T`dr^E_w~Q2MX;ufXleHNI(i-pK_|U&F5V>SYM((ox!CFOBGnn3=mM=uSoJ_ z{?Ju&bK}M%yq^V2KIQouw*gmBwgVd-uV~-4wf0Y#ib8Qh}!2OBI%UZ6^p=f5#nTN89&yDT1mki>5g4V&E)h z`_Wo5Ob<2m)a!fXET_P21XFt%#@n#Pl#;P-eZlMlDQoQi%jNTTwY_lu^DrGZ=I`IzTgl0!yullLzB-KJbKt}$Z5V>Br_xg4gq$f#QocZD36PZ9ZdpEh7m zix_Ww823oZ2Wd`f+5jcq*Nzb1;N+n{b$n^t3Tv_`6r%Xvb8nSy5lTD-k~>h|WoOZD zO&S(2g>e6Y|+0q);p?VI@S*~L8uFZhR(85Rgq4-psKg+U3;u)SVKPkrS64qK+kk@B4gpi{wl*`$2ey@ zwF9Nb1=z@2sH7ZXUQ6WxXDdb$vV`O<%Ac_1Fc58Jn4v3XBfAqWtLq!~SNXjm3sa8{ z0=#QbpeWQBXYhvn0T7jO}bnsbQJH*Irf-LVBbzwJ6|$u^?BsL?0U`u z{I$^>&Mx59lpqNAWgXEcs|Zg$F7TtE+rLa+OuFj}pNEZ9T<%DL&vyv1kl4M`7i7q; zxGF;g$#4eyOYz`^R-sTY?q%R^C1sQoJp^5%l?= zu`j-H4-Vu$udlnNF}bt6?1T3*7@)+542Rrqg`RjFKx?*`L2PlVk%ZW7j-Z2AnlXn@{9qyM5uGa;AHs zbGFyHPqHs`jw4hU&$D^kY!a}rBz5*{ksmG%;B7^18OrZ0)-SL89`8K~Vp_LI#Pthc zM`U72ubw}PQ$jevWKONktSf^}-LX6UDM!M|-)mqBAHTIY3J2l28;7-PR`*5V53kD3 z^a*EM^`SMvAyC%L1vKkVWG%k)UPyyT!KPgKb_yBhD{nfxX!m>$@_REn0@V^v=m#HHe0?5%hkSW*8BGR204d?ypn zN$rQ=606*i!PvW}*kvu1d2NHn^B^p=btvHA1(So>F%*Z{^E+y5-+0?($)sZ24QyX? zo!wehZ(XTpILDwsr0)YPak@EfOhL$Se$ij$lw_cV*Fm2a^D~K&c0b8BzAQZ_7;mVp z?!jfChK6Ab{JTurDT2jlHX0T^)^uSEZZ6t1YRf5%Ym1sgnL!j)ha^Iw%LDm{BIR(? z>?0kZz4^~=_*z+W5m|WiTa<(!(^=S>q&TFS*GAd+X=M8pTRK*&;f8SWLPgvfXAca4 z?{a0)YLzq~uNRzxs(g410*ZDyZf&=^lMjp`yrhDiAI864m_RA?Xpdy1~3`A z)~F|YbAzt%h(gwga{h-kx2-oBNmsI&?I+f+0gDCHVvY{>d)VqyLDbbJ{c&`I$#i7u zoOnls+xd(rY}e{gJ5>|@dH_5)_o)6imV2c+5OKq__h-`zaKPq{KpHxvn|}TXJ~(+G zZ?Wx4_Z5pR@Mv<|f|DkvVCVl!aU8c7c39QPziPD3?LTdUHsEIt_i!~uV2SXYPBOZq zJgbM;ZZ9vJMyKDx6nu0a94<70hWX+4h%dY<%62AxkKe1aG*Y|2^rTTvDWGLZA6FRM zjtQa`o20t21R|U98|=WR^Yqj+xWu-09Qq!1f!hnXnTc+=)%jaBmbTdUBTERbn+J0C z*O^>i8rt`uAu{q)!84to&ksXjekL3)0O9g>sF-VA^PR@^lfB)}g+BYycA+vh6LiyL|$8}kmJ<2*;iuaGcDLzaef$6Uh|I9b_Xz*vv@iA z9ujH#LiU?QX1hX(8}$9Iy;^CCk(NtYx*gBraarffbp*)$dG%Et*37ARu9nri{Y zq_Qu>!K$zv-Q(*{xIzuHl|*X$%0+l7O2M*5j_maKeS{*85Ml$(!i3*VoR>KfS(ELI zoB9K5Z>K8~i!K8{RW8Sz_%p4G-Z)Mw*w0OdcFsfK1eMj0IyuD0!lbK8)9I_1)%*Rb z!$Ln5?cP7@c^MMOyAi2kz`?;eNS)>Q)W@!LltClG{XbWwT&sKg)-a#00E=XZ$2%8X z%S_^ve6*pb>C2%=_-YaqOmA;;PV{<9INsUL0|4Z^o>riGREeZW;l+fYtp_3=8S(eG z;0NM(VT01lb}pQ}!Gu|zz|v^_*eSO%8Uy@+qqU56SNR#kl&@|3GG-WLu+gURk*I?Y z+vj72HPeljz?qCR2WErOwvk>1BG$fSV$YPT(?egl$L=@}#N9EUj8*sVyRF3l@d4EF zcAuh&O#a4@C(%I5PMe_fgCz+%h@!p7Mv!6tNw%s=!18AkHu7;wsN4(kVl?lzKBKQ# zqyJ^XL#(o1#_Gj8=W^9&+LiqN<^yd=6{x1#1i`Eg!u~vR=IX$8Nc7P?j;MNC{0_>q zm`7Y|fR*fzzjaZjKRoO8jGqlh=rR?vt?<}~0x=OV=S3HXDiYX<*rHrZTm(l+(<;Wb z0jWKIzg@0uIi_Of^ssqrxj-)aoNwADw|m#k-j!cYHl~||o*oagpeEaq!`Z)$zkBBN zt%Z7Abw8M$YcMqHmFtFrt)5F;+DdQaN;OicD}z!%xV)2uJAP4SBDZv)3F6vAT}*hx zxfhA<-nojj0ES^rFyon9_&aR0Nlxr*&)`Whjd!+c5%!@yqQYADJx+288;aj5SP$wm zX!X6oLZWr4cwxuo-nbr-*N^#ClI;NKFYp$Hhq(rUV5ky5_B4`4RFxe9_o`O~cX1IW z^SkSZB-RM0Rb(Q|bqSwSJ)0g@+|-#uMLNj7$%B|VvG9kDQ|k-3EVS9_{$N#!79oOq z&Q$;8q_kI$HvHu(NmVA!RidI2Y9eJ8zqR1csbULrmK$dvvd|It)Tq-x@b}z@$Ox*U zUn=WQk~q3bOtFdE{gN){mn%5Xtbpi}mt!X}B~wxt*m!@lovwuNQVFjNesCsPy)Cfj zIepFi?*c-Vme&`mRk9ZVu1A)?UX=C&^T$S9u1%Tk@I43XpGDa~-tVp@GaVHwi)WU3 zW=sTfY!j^HaMwqO%f=M0FAVw#d=$o0SaOo3Rw|zoTP#p_pR1)BnZFKSiw>kLUEPOK zxu81@Yt}6^(n?s&Bh}<)>nw}f+cJ$bgH9*)um-|$&L1yNXx=n>72onyl=BRryy(s= z*Cih^9%WD46pP>x+0pe`>z*MI*#^~;g-j1g?!5bIo- z&hQcALE_1lJ2CdczJ_)&BUG(zRN*l;2VMEfDrz1U_trC#>d;I-2y3ibnb9b+Stw4S zm64rgE9;&;cB!Hb-BuZAHxW7^ez#KqenL5cgD)>lso|hQX3anH(>K zLDWT1k_Y|3H&T|WJ#piDFb6)epRz=;l(pa`C_%J>-<=*DwG*5doK~z8tIo1O9&FKf zy9dk8_sn@kE}DF?qQV%)0`!Zv{*$Q0I7f@>{V+=u{?$Rcbbs&_Oc12?ScwN+K*DG6Q^n2Vy$;C=KPtRYHMbv%UgB6g@ zmZ+2GOl5qbE^$w>rdl%d<+!RibDqqE@zS*^PV)(&7HblMK)dL#uu6u+|kpQ%(2Mb4PhmZXWjG;|o4=F#~kp$c9 z^yYBBB`~_hbVOo$B@Z#Xd~oqrQ~s|O&viU*YUnY&>2sMu-Wwe7)@dwt1H-u1s`BYU zK!lsrs2p+1;d5IkloCsgMsnht@)mEFx>uW}Q;uQDGx!Rsv33QbbW(5g%)Mv$F!URi z8WY~rURT^n_}i2 zy^6|g4_bKN3i>(E!GkFt{soQV>6ke+9kUhwe$xByW`Yen$0 zRzHsh+LZv{OxmR7%Zmb-y5&umSEHyerU{EHQ>lDMU4M^FTor=qSAh zUJn&CW2^kUziXC_GQ)+cS!k5f=s*u{@iye2W#0R-q8vN68(5y3qDv6SGv;4|Q$vHV zS(wm#J+Gy?jK4~V+B=aZpNx-i zDL|cQB=<3zK@ov<8su4vZ+~N6+q-V`{NbTlVaXf$ynw4?IXMWI_VC1Zms_Lq)#Y~5 zsPR=WYUBj_PAt?Xo293hwkmmgZnHb^=g{>?DmmTmD=$ukldiqO#S}}DaY|?Djqp~y zMmf>>P|7nz#WJ`Ddk2#)A4tc?_j*mWt9N`NSM=Hg_ zj$hw=+S`Z6Ds}+?!Mg5cQI4_BL)6#xeteAGL^q_Oua*yA&FbUWYUz9rrKSPj$qxXs zdt&m+pAG4(&B5VNNzps+u8PE=3vqZrF)GnLq3)@il?Px==KMu|8la)1gl4YTNP?&T zgL?WktF3nIL;=MW`3(V0)yNr^2Zq7-J+W_pdHQ-|>C6(?+_3zk;C^#@AU5XEMHf^v zhT@B!ZP3BxGoomAI~)`L%J}Vmv>}%phQ4L+VHRaN_k_D&5ZcR4>|#^qMtRU2PYw<-F#&nV;vsj&94<=(W*2@bZ_MHIZ2>ek< zqQ?G!uUhKe#cM`EYEG0s?Pj}?6K#oLnzM&s3gdrDiH%nOezNxvDsjnb#}5RWuidg= zxt2c^{MW1Fsg|!k^^lZGs0uW9tbjx$;<&Wz&;WYmmoX>9*oS&-W;>@vGXBDt6{!b6 zh;Xt0i6OZm;;oB9-4`1knpO;-qiZbHnr8rcipLh}jV`;S{dq&2FDEEANcE7yIa0pB}` zGE_?91HW z$bqZrGVuv^iF)AUCz4INVlzM^Q*Q93dITZ_Y!jLk2q_||EC%Mo`8FC=wYuk z<{3?6_H@X9YEypvD`kCQC`O-#j_cs-GlNGh^_$&=RgodDfnCj5+gNYi6_m;;JQaei zsKl+vu&?fdl2RQs6XGexcfuquiS;?~A&>t`rB-99!ZB^sCa;VTIW)zD^Xz#>Q)fjg zg^EV&H&3z2Uv`y#^&X>6mF}?uoSZS5bgDbV#=j^ z7_phCz$KI_^lv!V|Ag}Ix1m`c&i`ZYJ)@f1wt!KJf=W{XJ#>)(0s>0!SP%_edPk*% z4ib8(Dk4fi5_$>JdvDTX0gUwCoAerL=*io7&b^0o@BPMjzux=v?Lh`RJ8R9hW?OTu zy|>JhO{zmDH=t_yR_M1{y9GO5>YTWzU74u8bmh7c@jgXA>jD)0QsE=@GF2x@9ldAD ztocvij9H=Pfn{y$E;{=4h=`0);dmf7?OJrjF_nJSEAxO0dV<-X3D+;{u%%3F+*Z(c zvkC&8f0Rwj1k=MZwO~b$OcU~dJxT~g&Tx7mRJZZiO$p>m`F+u2-Jh?8eRmGal z$t8WPw^q?x2(g@!Eba5QtlA0kGm5pF@6RDCVQtvr&24k*TiGc`9*Y*9?sCrb8wStH za%svh(!MKxNZ)cy{;ZdMt)B&uBE`O5NK3zp=e3(dhD~-(*REV(kWZKWRyJouDk0nL zF5SBQz5031`$PFDH+1NwLtu@4@nhvOb>{0ls z3m}4{!%=}&&=fiS&hE8mG3*ZT`Hj`vQ>5r`A!~*v>kv#!ZExkxlLpqq6NM&VgFnS4 zV|~nWN5o#YFP8N0@j!SFnDI0`_4iw-;j;PD2c@rT=y~GqroNgL49U%dk+u#x`>aXC zx-JSq3@#*+*Hzw^P6CQy`6SFVZLKn4sTsq7u%}kZIV%XaHY6E?hkzmxM0^UNz!q;{ zN~Cu4tCQO>k;Ll@;T59<=|J;Pp)kvZXmjCw7FUF z3z9xLYO7Wh3}FwOmYBNuQ(8|BtewEJ4%J|cYIdz5{d)+#Cpyp>Ar81N#5Xj>hgm*n zKRa>FWw^r&$YiN$f>gx@$_9PMTS`O`FnrRQkGGV1`l$3eoP6TGcJ^reaY^Tg0K1T` z)uI6MOO@k@&yL+cPS8$5qYh2BXm*7QE{}V3=&oN$Sy?%XVLFT%=C5p&yRs_%hki~- zW5Rvo70HAP*bc!V;I(n@&#$Pb?Mp6O!D#8vGgVXXL#a+YB{!VVOd$*93?Bj#0<;3n zX!~zSKewCG`hN7%h1P%X&W7}q%G8USG9rn0(Jfbxq*y&OLn;$WE^VmYRH=Rnv=ICy z>vDBdM%3l@mG8E**S{~^Hvybvb}h+h&)9(_x?Uk@r}Z6%fsMbw!)7LAuNU?XbG_LT zKfaAlez&mV!QaA0u20~QnYF!@+*z;~5>svrcqqx5}ySLRO4B6j@y8#2A;&IK&y0Wp`8A14s=(LNu` z`3}L`{}Oefd5N!y+_zu0G6QjuS-<6Ya~vkPJaF}_H}Sz zZNTWe+_7z`Zi6$nt5~D@E)W4kIdZ81X)t_MZSx2h(cz~0m$G|L2%(X5X2G(R=Jm)k z@k28Ot0l8BW0U$mAbtIXr|w_PbD<(lgU=SO>bU(b{QPyb&oYw)dW-dVb3ANUP4mic zmv{P;HvBG{h0g4?Y{P#7SJ#x;Fuzi40JzAUchmo(H@A6(rvX1gUYGwL?H|$x1m9xa z-)uRB|Ncz-3_3Ia`eJk0f0F(U+!^2C55VSW`n}YB%2$*VQ_r3{^{PJh43`M)MaB2z zeq%JDE5P-PKQ#>aJ$)-WLuvj8j8C8L@}YH- zRwEVb)&d3T@{_5VO|{JaXSXJS^M_J($J9fgf6c7w9DVdV#`l*@?7k(v<#)WkZanxu zI_1=ct^tHyc_BZAMb}D?U->W6fli9T-^w(-qRITuC7uh#I{#1Pj8Op1bJ8RdRIy#t ze*bGIM3(hgw9>w$p%;WI6E598uR^9vDn^<~%vaep{{`(4kY>1V^uMr!;4flG0B5x3 zuZgg`n?XE03hn+=?x!5**vDu(c)Ay}1Snr! zqcXL+s$-ww{%=z}E0c5;bLny7oEGDYtC#9%Vv|dN=hkjV;rTmHwYL{mci@ z)!onM(c%HgT$Q7N+4qionoi;BiFHZ1u5|8FpwrM_)!c2* z{h?f^mPJGxaB$L!L_=9tW6rYs=Xv@S^hSPPLvJ7(i88&tF!9j2eOSnv8ZnN@ouraf zj6~O_c&!&*kA|Zy(Lv~)t4Bhb_N1%lS4ry5>BC|j=1KQR{W)1%CP~WdmdykimFwg@ zZa$bzAYP#*#!k!JuhT6eEhG^@w^aQQ`fgs!Urb*tP^?BEm<4*)pWdcS#!Bu;>PX^9 zw*K|b=l`ZoG4^iKdVuyT<-jD0fl1(DoiEu0I7sXtO*}Z~Fj~RnOjj)bw7rs^B2YPi zHb6Mw5$8_cj}Y|0`IW{CiM`GEMvA(cXD8x;X5#u)G8<}BPYhv6GUUgU`&T!dDg5R8 ziUMpN;wLYmo6q|T(|oRIcNZj;>zkJ&8wK7`=*f3w-oBqgApj?hPF7wVbf!Kpr(cYB znUWXY6Ah8LZm(X4(j|{xGuxxwG?pb9BOklRY*fZYN=_O~RNHgtMf7VIc77umKZg^; zosE3|Vv-k=anJ0F=HowB$wTCJh_QBM@IfLytMcAe7wL_+Vn@*~Ua2%#TPVT*$tq#! zIo`@(sxdGwq_N!usQsj_)s&>;MQRg`9!#=7C~E}qqN2xJ_(GP^mPgj9XN!o_avd z6Ss@rinlqnH~f03Adgcx22y7N9zSx@;cfvZ%9rt151meyrm4z z&;8|dv)@WTquda^`J=`vXpK^oTH=By818Vor2HR$89>q)#ld}N-v@a#_Qz+kp~{2x za(me+U`3a4G{1EM&5v#nEq4O}yNlOcU&G&Z?XHVf!HAw-anFe#Wg+#s{Q2Tg+ONuH z5^mb4mo3_3(f@@3A@brhsso-iD%1hx_`-jM*gvyE3E4>`92kV|!)GwG0{e+@=kOyB zj>Z?ApD8aV-I-cZh#K`D7_u7Ayi(L#5x<`xsqoH=Yy-5xTuf4YvsmoulE|Ld2(1LG zCxmvb%A9@*^sF&{@V?!05G{mf5bPhny!?OI(PKr4F*q0fbOgFO{t z8_^#~ILG>P4C|Bn-no|gNjcQxqJxMz^U|IPP^j9ta`Va9dxs~D?uYMqEAuLc$k2~z zkJz$j$2#onKhKSjoy1)jOWxcgfI5hkE1cVC-~FtYKab+KHc!5W1C~bqYs3NTaTSv} z>QOi%ovtlmI2z#tC`BKj-#hGh*-Qn;Ik1c>N|V-z%D~v429+5An^dhTHIpPqA@`Ll`^B%p(Um<&}QO z=*3RCOFpdnjX~~AIIsw%oV%K+_2E%~b4W6qzM%t!`*M%dG zq?gvgKfTGf>MAOU%IDSA!+bts3R(v?eV2rXszhNN9S;9T?g2k^7tL_GP3C7o4sW7) z;L+8iII4Uj-2Kb_f>^ckaWx(F#juT4w!n%}dx%5}q`clg!NFD86GtfXSa_*BxQj=d z39o(#xbf=N=Xq4EO*J;tGTzEEejebli^$jH8au;wtYZPa11Ra010xoy1f*ITC4 zSJ~MgFWfq6=)i_!?`5|o3PUT2QJpO_G8=6R+rIv$=tPFVZG6L?YB%NB!~&*6REF@% zy~7bK)PQu8?vbgziJ{M_W3SkiNhU-J0P>Xmv5WEep)X&OGKrPa_NvB*gRlEm6B@Cy3Wit@flRlUT1k-lge~L zv?7l|bM<}#;4PmJ*>Pl|@r%wV@O;cmQ_cpx7bg`wvh+}`auLk_RTx=6#}jxGBHc`S zrBS7{m|Ak3r^N3bRY#pHMjFvpaDPqD(C~%t6GV#JkF%JFm~OY1X`qO~a*-A<5aA#j z-kJCkumHdLWFXJDv6l&h8}IH>B&x&PhsDMI9aoJ00#`OA}4dUbOyXEg3|h z@P2z`n?T7#B95Dg^b8wlF7@r(`I8%#hPSSNRUV&|?$2arl<9d=m~WPt>wTvweY9b1 zl_5Sg1)m7=&w0r855%9WQI=X=f|wFFDLY++I447IpdF641pj1V##KM3%oLfL<@o&p-}q_Wjcr&^w8 z7f*Q>li1~UI5iPdL<@o$5hmIp#yMR09px?78OB#K!H=ojy-*rxFtSJ_T4@)utIlPU zGn1w*>;%&?5<4#7l|U5Qwd_5`aPz|vaO$r68Kzn$<19RkFQi{sASe*VNDEuUb;L0{ zW&xQPYw^LB?A#gH0fqUnG*UF#Its+5?&8l~G?^PJOCe=YEBsS3FR?8lJ_=5)VQvHn zhuqE1HQ-VONK(G3Zwa52e^&;RV8mu8lkm%~pA?Lbo-G3Fx=L}LflcK4G#-*Nqsvvz zj;TT(XM8n0`8lN3IX`@0xyr*W%oGy{r!Kze&4s~$@v#Z5=qt>kw^g5xBdqF2&@}3)SJb6e^K)o zCEjd?U`Ed7F!oR0#@K)h)w=VKuwd`L#eez?CM0B-u1&R@c>t9Gjs_W^QUiCIK)py6 z)h&w^Z~mRz=A8(}q3Z;vVJ?g~A~AW^ z7mU|UgPtLp=+nGNXDN>-JLWu`y8ErA71P#i`6y(Ujk7wJ_5RNt z`!rJR;a{NSCoTqnrF;1!*hQu6!a*LH)~P3M@Q$-k1LAvRDBwCB3ZulL>YM5boHo2A zStz9Q5~I=yNTmxYurj z3TiggXhyZ$qEgKvQOG!WYwFdN-DBpA*mFL1D;(fTwXMT}mM>tOa!>77;dq3PJmxcK zhA;p8S*qMJysj~>1PS3N^S$1OCFz{Xs#hsr54Od_vh9PItdK*bKSszRm_J$&23q6_ z*s$*!zztEevCH58p_GSR0CS>(n6IFd(cv;^QYi={V7cnmFwe7??I>C(U-A7=O;j#9 z%phWRdY~oTP<}ujlLA&#bMZzL{LFWAeGlx$%yUsZOImi^ydpW#mTL&$SrDnk9wEE* z;LJXb3oJc(&AZ%y+Z1k!)T}8C0z0a0P17M?O~zSh#tk-<>86~8^6462i8HdAFY0GD z6a@aY7eM==ooJM8U(!bl1KC$y>=lkE-%sDY!$HA)5~TfQycj3sYQpSWAsm~@sKi-l z8YX~!Y_bZJG^iq`-F|dOS`e&q%x>TWH<-Op z*Fvzn{UA9@hfWGGY)-}q22NaE8MR~wZ^;B=c0g)&s((I8AB##if(sv~d_P2k*z#YJ z+0HZo<6G!;=`4iot3c%Si>nxmmQ2;-M(+ivf2?(Ezw+n>FO6t+aHdLKizH=g->n1al zy+~uD7o7nhd8L_#DtlDw6`zOh+6Xx}Ij9B$%ryUhkR^J|kKy3NCC1OrGA7nT5$aJx z!rT}gQHg}Dx>yUx5ZRV~_Le!zRY@LWfe`i*(i3}>-?vIX>QaPtU6 z6Fnq+8?y*9(wnXW@FO?-c9YiA#_dmk)N_%MtDc^gOz7Jx007S3>&RYa-{ zZWx4ZZ{9n}hXMX1E^?NZXMAeHz)97`K16nKVA1|8s_YPW!SDq!i#(+9M+==0-&)QC zJA}Bl^FSC+CYV*Pc_N%U&ghGQc8jm&>VX16SlYnct~}O>e1}fbpeUxA{o1*nPBDa#3Y481PjAZ&vTsxaLPx`U82V zk1$65r^Lb(b)V@BlG7HSLMtl0^7g6$5UqF~&1^&`$;_ZZdKvr1Ji9Aiy4;;-sSS9W z(+s-zsYWg)wR$b~>QN1+m;ZaNno;DjB!-lSk^Oq6b?HisMJ))%Eh&acK z+;2;XmdiXU+sRU1wNu)10?WnDhJcXBHXC0NZXneN2Epd$k}1O7ZzwAxpa}bj7gy~i z6}b)`te8JV+%14~s0romwwUtBL4rBGR1rx=&_mN*^>IX9$?oO}h*nc2l{MxC??xY8 zW5c$VNb8=O&`pdQ7zcLoc|S>T8T&XZuG2<+mJhcS_KP(r-~oTARCaf)5Kf$1vT*k) ze=nj=5>v-JknS@1r2CHS=g@jpu)BkA-`5_H6WGNBktXfw&`8%lox%9s#te#(HDv1- zlfyKoTSt^*hZ}kIAC6R!ukDcX!Qg%v^{YTEYNC~(UH=u17XmD_|jiBuE48gtZ$;Gn00wVM;US82h%^riWPr7%; zpKNQ2>^T0g65l_TPv5T*uKyx=h7h7py{AT0c>`mF^!dEoXlME8{o6JUO%+sz-H|hK&GZtni?X;;%3LeiXgALFyIx2Fin-DhP#+$DU>uH<_J;8$>c{W zbQXSs1VHI-MY{EqFXgZ|Bo^toc>iqW=IRykY7f(b9oVqkDj)$?{Llubb zF}AK9%OGJ{SF(Ql080TxOi4jCdyiXM$iw70>Roe#-ar@$~i0pCeXESLbX(8e8e!lU{*2tlK@^%k z9fe+Xeev7fAoYGpJG}u}3@g}Oc~kV+3g{bxQmLoPtuvRd@vWWTB!tTgu)||>938bpPG4y8lNl#-pJ8&8xR`8^>`1dLBZSjxxveO2;+lL@F z$CH=V2tPRdG%t+oLI70)Y^9v8nAl&geh$c`fnPM(%+$83_mBPn&WAL{QM2vfXc4Ik zME9BNMr4yP57OfIi)DkQRc{>9>FX z^nwp*pI~8__L_)Dq^ptp!27*Fuu(@uR5SxPUWNeevx_n_XXpH>kKGVuOp#;*c|cL= z6pok+2cpf+^#XAEiMNLPz;+BoK{Qm(66?kYL8e2BCaB&6RNUj(@!m})rLj?;1>bUy$-PgMOm}kwLl(2839jv}C^pyc7ner;@4fEndP*_hjyc(zsKj|e zq0lhTnI$R}g~#=GcH>lhX7LrB zahT6Trn>x;1$mPbq|X|1p~$!4sDXU$XfWL7*-feC{4{q=9|k#a(p3hobW&l|m+w_O zW$Eu@$l4n9k0~b6vov6~@^=H^EC8-Zs*7F(VMa z?&<5(4pz8VpKn?(_2F8Z(UDJCV1oD^Dh(RtYl1(2(zhZ(_1=5nPSbj(#0%M(Ze}xo zqOkug(s>#pT(8u!x*Ja5g7O$yNEhD(D-uM+eNJRK_e^}T7I3%Xh&X&WWV`ZVrPD;lcT{TJKDyk<^x_CG2WL_|zff13T@4edq#B=7Gl#od3}``=g4iVy!k1$3I65V7aVayijgQ33bvm}7?-3trUkKT znh_7an}XXIXwgF+b7CyPc>N~fzl8&wF`gE!i9DmW5i)VJ0)W6>Sw=w&NwZmC#r}iULC$JE3<0Q$bU=Qa=D(V1!{-eG3a8z`tWR8C zkP3@%A9x~QNc&+l^S@gB{-2cTb?wvUMC@#sYtq~P6XaNo#gQWUpIY%(!^K;`u){0- z5q5|jJJ*kTLp&G<@LMs!d7nA%JqAQzofrX>(h3J9YMZHf7-6te2Y=?cR}By^qNs&n z<6@XtyuryFFNGs?wvS9&mt6q7Xwh> zLhIiS`QL2m>07KMyZqvfw6SR7wT#*Rx8^|ED^JdAP?=7 ze;9J{(ulw#LT?B7Ef+&%IuD>O6i5}Y5D(@d*vey`sJ-l7eOr!8Ju$dO$N3}|w4E23 z!EwlS5YF3wI0;HtD}5$wM~g5{n%xHbA!cKF6Fpu6>}s&cY8|JXnV3A&+6n}b^5vI+ zFg<`i5@5Cn4A@FXziI%dwABFO<{VCGv(x4Fx`WvT`z2a$ISh*4 zSe^&7uJg0!3M5^s@!ECH14D+ROpqk|BaSsAKAG)zpjxgt{pT!161SVEZaCWc%EYE; zq@2dJe;u~iuXI{^cF#@UqjK)@Ol0{gzvmiN9OcGXE{!>(=RxGt8C|#kNd`K2f(YS>*M|*m zuHwP?#M#~)Kem-mph3`qCM*FMhQ7{=Idz*m;$ReZwjvF9Gx_wvr~(HqQ9l%ls7kl~ zWReC!q-m*SvLsu0t7M$<_>1|b09=9~#tx{KOoIGX+%nrMGk7pf1>w8Prr*91dsfrt zY0Uh*R77w<6zS^Ee5PwxA=03#0(sdXfETKI2pI}T;Sxcu$gzZ9Z!ZI=b+bZ=x-xFZ z3kwT#$s-K3xGnL@oshXwPJ;&5r{25cx5r^P44VJ3)sG)Z!uBooy^ykYCYI~}8ohwR z=S6hb7C&`QQiC}ab0cm4vNm%FY+h1ka%26Tda(njSY{NDim5}U$N~sJoizn z6boK}l(8G>ME={b1E?mV!H!B>hoH{BPk2f2gvpD}QlJI}=on3TNfrc{x%o(BkTc?M zU?!0=RqN!Uz<{*?YcAUQGdMaAjqLBeJPjodX7}Nwyg&lAqGe06b{MNfQ5+I`uxeht zMxN~G8mcymo!xV<@pA7d$5ihgUAOuw+o;~U+|N?uzPqgB<@akyM*gM!I{qN0Y;bd7 zHg*pWIiz8o$oV_Q_4O4Y6HVqPPM3yCwN_>}K-}q`;ch(N5XMonRA60q8LI>`&g%T{ zC~_pQYNo}B<5%yVg=rzQfJHdW{8}Q+1|d9n@(db6N|YUDE0QQ@9K;BoGw-ibDRmQl zMTF+dkGoe}PCHl_rvx;8tfgX4c!a3pWY8}NAkt9xubodg=%}t;*sS#*oCYk!u)^gL zYt0gO^{+&etse!Ag_;lkr36Hb7Ji5YePpUI8eoB75i`MDJ_{PD??goWYix!PnE zWo2cZzpMFO8hOZLE{q-0*q|Bz0kKomGfax8D@xjp1FNZ*79)4r)V2yi4)vP_K(t)( zyZ4(O{UFBvco`$Ol(Y`uD$6qv7t2@7dHIQ$Li>T|B##s&Mr~FRGBX#BcXL}^R`%p{ zdjAfg*6%FAKr)(k^{DcRi&9jFjQm=o_z?%sM2ksCH`s5q<1nFAjV1;NhKEB9Usr&T zQo?v2ApA zh=+9AKpc$U?>XvyYvSQrEmYsGk*v{Mx<@pkXH&Kmnwy?&$`1s+zHj_sHB}d1#Du6+ zni1lmAscwpcPkq7+a47cNYHsQzJ!8mY!zXA9hEshUx$k=18fb8sf4ki=I0%YM#^lP zwq#Dw1=WN@tW{5}e1(zI4n13Y_8@CKzv7zVQ}^uPpzVcBV4Bl?wm!4E%l&!1MTCHz^-;ms!PM%|GMLt%uDSTWLGKG^#HzjJZw=FuvQx(e%f*lD1T|k4YIK|4Bq%S!JQ-HKJQ{ojJawYc&HZ z8M54%T#&h@NY6y{>=$h;jRTP@8h6ARwMUr3=k^y@~bA-Evq=xiblMA z$)oWc)4BAm(B3LMKY!k64ZEq3=l3wl8H&bsU@)z#bgNip%eKF8Ll$1EcOcCjf4apa zCNyoE8e%8tm9Il~s^k$+f!YiUMeFij8rG<$57$Jb6a|hB7MWdVL+JZIFZyQ94|B5t z3AZc(-*nvC(x71@GW025zu|V8|K7G@%M%2%+tz65FuHwoT=*!1;h?eBvE$84|4wAM zY$ArXrRqS`=0~)VWtFdKj4zGU&6Z?$cQPsl!w*AUoT^DOJT&m?JYb{%=`urqN-M1! z-EmR_rgwI%Fl!Z*&rXVp_iD;*!(u!vXBUwE=vuiEZV0<8xdqRH6p_-XLaX#9+x|*C zYGUn>K73#;rj=37r38zY=OJ~~Nfl8!6Me&?eo2)H5D(?)o}4PoYCzgxvlFaj0$W3TZGrciC%h|HzGi zG$44Ew(q8lu19Y-xal1_G*|{NH_T5Vw@`fR7eI`3ucEI;uMR&DCx`~Y2gbRCd3!UAB##A$nVHO6XIUGD_s5#At%Wc4jxT^cO2 zYWN6qs%GDtaCz9UxBJ0mC!wRQ(R9a+Hggyxb2v3w^W6@%;^1Ll=H>pSPO|!7#B8=h z-UQjg%7_HKN|X+C>DQyU{U0Z%pK2UL&jM)N1|!VyNglR4iAVgI8U_@u9snis)uCo@ zD1tpF-wXH7eV`c>r*(gAmm%qehNh86tt>AFM0iiG0ehIMVXjMWn{Ri*5&RR_pb_A0 z)C)NLKn6gC>!q6Z=3z+VSPO!-Um7Km*z-Ky!XL4dzIpAtsQRNh7PI<>Z}2iZ`@6P- zi3b^z8P(NmIr@912Ni1lWK!!tv1aj6e0m~MWEx+`#R+l{W*J`jeQf7!$R~w452GKbik(q#aCc2RXsg_c^w%g4V|C@jpO!fms4Bx7*rqO)*7j zh3d(stc4|g={;F0m7cP0_5d~59ZWUYFCty#{E|LcqY2GvRwNes{uGl&5Blm#8Eu)e$WZP5zHkd6EytXTRE1xznPVkZVp2m2R#lee4Anj zvdS^H{f1k@ytYTnCYi$4oeTU<$RjI?s;ecB>Zcc({YQo+r#_ksx#l^HjMaMg=Z03> zxi%0clQFX)GiDWjlMdqZ6Go0do^vOTOxFRWK?i=L8jzrhFV|_&2N-<>o%qm7f33P= z=m@*-;jWYOgP(T+*4uoZ+eY&nBxWdI%K~tnh%v=BoQSpRrd6u%t;;g9M7ZBJt8`sk zah^V|1|#H77{7UG{%bG5VU`|NZrFAfXGt(XH5*j8SX!whAkJ^kTXetjGN|`<^WI%Y zn${m#v=%5@b$v{MhdsIY;aW#$sJ~1Mr}8yROzN*Slq+9?1<&E6(4u zDaU-Cq;WiekyVuqAS_JJSM1$-3VR^E66LuoKXRf4MU0=$%}hn{x`jR9lA?5=vbGG- zMo<{C0rMqfYJ|J%dudkU;)}3ltT?3Ko2$2Ab7W>hr+*tKwZ1Br0J+|QLfO!^SS5_p z6fVaV^B9zRK360ZLRA}zbC$Zx^wcC*PLgVH5hZ&KxnAyz8wJuPMY8orJMD4UlfA^l zLYneX?W)2r4}%w8Q3ztbJWh&KM|t#&h_e^mwcMhuo~tpNn-!ka+O6xd=I|Jj1U}VT zgMNF!qMaVF9iW=PWV-5vlNkZzn|3=&K zT9|yjZD(>JK4jj2h{(D)#!992O)vo!GK1~>{?dGV=lf=y=ys5M5rfzZZ6JzIG5dYB zk=)s@N(V;MO{w+pv~JibE6PsW0&jowxY_F0=aM)fubvSy5(}OdOd} zxw9Y2a~7}ihqxGRGrS#0Pa+w5GwYVE0#_LCSUbCWt>GnSKWn-4fgu(fUDIwVZG5tX zv0lL=sl!z*S|KN#vIFq!&H;WShcXkK?EVjCzh5?zi|=TA$J$k6m}~&WiyJzWN|bQ4 zNBJC2BZ|HSCeUCyVCyjt!~K=RWR^lHfwDFW?Y5F&dn~SWaC(-Twf#4_?a>^HR-GrN z$pE$d!OR{?-g`?%S>^eiue_k9ID&|}tek+bS!_ID#uZ-efZHouv7^yHlIl}YzTT5) zvEn|!&1rL#pkgyxRVF5md3DLQYT@AOinJ~2e6}o*dZHO+k<7h^pG63XO0b73;Y9W? zP`>+xVuNo($0T1rUe)j4uAJP<-dPg2x#2yOMjOPG43M?0hFTANjAt~f`%`C;+ z8+s;+q;FsMTMIt;6+C&6ThTb?lQeH&9Wb9c&wLc^F@LIE8wFKs+VBbA!}(vW{!wLN zW1LW{cAw#qNh}_!TVyx~4=NsFMk2S2E|@rKY!g6L96cX0l%vGGhE=v$8WFK$zw7801APu%2rtcpLv+s zk!uHjDhoP5E*HfrTi0KHr9;v^JYU}wZxp0gWEi!O43p}V-*d%#_J^1CI>Hvx%<5#0 zn0*wew0cl%rnm#+qcT1z*Y-NeGEd%)$OQfXn&voNDutzOl`g zyt27>5eHKcf%dyjey~%b=FE<*@yADI0GriirfspcijX#wwC!kK@-O3UEx(BvwOGJ3jA1TIQXC@-ck6n zjR*Tft#<7sH(cI%a&2uQiZL6G>^P3`nI6@1uX*VX$CHxH0ZOr*8(ySeB2#7-|MaN? zuvAoX>VO50M@P5oi+pRkpJt<9``2?|{af#QO*M=%u>`4k+BBCRFSK;FR|(*qYkO^% zYN7>9BiT%F2R`%lSyn)f0}p%1EhGBeSk8OkZuQb~vY6DRq;iYy2Swkg#@cMOwwq|` zzY$^_(Wm(l)@PUYV3k}A+eJn7N%3_5XG!g3-N+C3fq8BHTG@R}>)s{! zE|iCu+qrPr^S-4XmC_sU#jQwz1rBCmTN|;JObdbVPWF}tNp;mf_DaJ~BOY|2E)vK~ z>@;{kX%-EepNMC~3ENp!{vnpyVFN5CriQ6)O@KT&4<5cxSn0VjUc2|BtDq8NMJleY zrKL6BnUr*@k$@Lj87Hh@{bWbiKif_0S8gveMY`{<$ln0sJueVFJKxi{mOYzDyd5ho zeHys?Co(=g_c~&xaPaJ*DiE$jSg)DA32tDhX0@nO2ftf*^yodX>j^x^j zlR^BkzmQ9C67*_g?F*Mkcv&)ddtg}AnjO;zG~g$k_3L{rUlEqdV#Cq)9Y-==Lv8g?Y~XXTggD7P zI^OqHMQmYVYTug_w{Ht2E@odS_;4O2@%gn`v;PmhUJ$Wxt@BGa4*!%?PtSvo(eb%b zG&3*KL=Q7FGPimc_inA5p={j}^w|wl;7LhI%fj%Kh3TD(-x#FbBIr};N34&G8CmF4 zwil)+q5i3#{k^2>?|%Opami$LZ4G1g#EX)JnI#17rMUB9`;Kba`bhV9LaewYB}W75 zd60Dw5t_bhFGY$~-+Y$&{7!jX*_J)s&xJC#CFmK74{ytdeBp#af#Bf~z;XugJg-FJOFX%Rnu%nkQ@&aN&|>BQFxQJ=?r ztF?82a`|KI)?ic9bLKh4O?=0Ex@nHcfj--zSEV|(n%UN1I8eZ}8Ef=~o2ZC*XL~-&u~+Q0*Ut(@jZ%Bg#PVY~7FNbK45_rf97KqQ z)G@b$KT#}D*W?hvUDN>C466QI1JkH|s%$H63+}IhZwi{xi_@sX{a%)ICrbN$^q*Is z`mWTSkfGeT2Ri6cdLOy*8;$)?qEi3L)ATp;IBIIf6B4#_&dx`Mx^2ly+WW1? z(dFeLehdWm4<3mv9UUErln)D(vNY!AsGN>(AF{%8E7tVO-Uysbq}e7lM_)2ZpNT2D z;g(R5p__J1yYOl9RZG6*V`Fb0f>?AXN@eObQAK4n@^NpSuewaVFF$?dla_D22_ve8 zPxGErDc~X;6wz$)L8IWk1_RxcL@vB{X zcZL{4^Qc!YSmT|&F^N$Sv(TcIW*93NMgQQ!w(uiFPTs}lC+Y~uBS$yVkK8eDejL0f z2`XTDL(PK*M`B80fn`5boq!>idNWp^UnT30`Dqnb70`&M*ktz*RNl%5)a&^JfkH>a zs@B(v4`%JZ1k#99dU+oq8lOGoQ{Vt}UU*T)3+F0Hr8NYa^9nq&#L7VxlXJnWB=5I$jiXnXL&AZTb(WLyP3p>J=S zPOncl!OVQrTh)ATO`EZQ!{czcNCC4Tnr4+0%Pcvc9YyHXUoUjlf;}8=Nbx?nCSCez zz~oS9A6b;s`_#MKOvZ2RX%Z6!tU!m`KwR;3p3|`pt_H#zjW$`q_aV`;?-bZ$bi98vZ zdYh3-KDd#GRr8x^`(ry)?pl-AElgQ-f8hd=T>J)wD3gfzKGbHx58GX;#imGY-5CYt z)^>P0ox(g`7Kf`Rix;-oeDB>pvSoP0Dq`PF42cQtl>`*Wrn^ME-4xrA-br2p>Aj?5 zWUF*ZdXRtS+e@u>hSJL;u0&kRHtHmPA}-Ws_a@u1o*XTm?;6Iqeyaw>oku~{tGZrd z7vBj#y754N=z<;jjW>5j!qNJ60gvHoV*Qd>+xeXmGjwcy-HSI82Vt-#dmh*s0zH5A9S!kXWsR0(_p0P zL4{P^HfFFbNye~(Uz9UQE7+sAM%hd&=$25Io$~-|x6Ag1#aL)YU3Xt{d7pMa?k@-x zt9{(cN5eq$-xL>?Y;a02+?v}w8C9W=ztdIA(b(GKcm6}*KvI-mTt7MyOR7F7e z+lIC`hVTw=&dF&z#B6tM9a5jjC?9!w9^7#})SR%@dAbH&3Lzck^cwg&vdjE2wF|!8GZHm&2`;;f!^O7~L-4cG=kX!cYwu*(?Ap%mrx+`*t z{mmV?Gi~U!<*U0Yk|-X$8el&PR+cf}hv}xwo>6LCpM$Rjq8ULib%E<#3g_)~bG^Ux ze{kk+UfRl@wTI^lQHMHq48oS zlYK+D{Rsy?g`1_R&myie(kso$v>7BOCfZDt#EeuHf8+*zSFVpvOnurK=IQC3=YZV4 z19|D6|S?2*o^8pB-F)RqWDSL zcCY$gOvCp9^FPeouAzBeyZd4aGCw)_aR2GLdQEk2Krbacqtpt!Zi~2e%I`M=>6c;` z^r`EJXG!BzjUATc@1;QGPqi&8`(v=w=vduJn^@6@U>fSMnj!(M%_y=<$3nU z&*eMpXx3*U8koc{7c*`)Dd+jJU15BY@kBv)PSBW=n;TN$5HYP@KnMTvUa#}pk2{hy z(0ILY_8%|Xz<_e_XrzB0sk|WRC#m+Fe<6jrC2_9b{0|1MWQYsU>bZ;N&5~}-D~BpZX4n{BRzZ$x|k;DH83nQcN+H7ufw<6ha}U&ykmvD z21sZ0G9qUU0HUKU;HT;XDh3|Nl=ui?5p?-MtiHWMafg@(w$3VHu%m<8BiTnGShjnF zm5E)v?Npdr)zGz@9)%`-L#DN0zEe+rNAbl2nU$D!t0gCSYnibv!&+9KJKm*HH)(%M zMzZZHnpJ=QxHI%Ki37@CmDur9K64q1MCd_Y)leNIVp<_6_$vJsC2fURMTDhsn=s!a zF3PBQM5>e@;L8*qy?u_I`h@dz&u4D2=btwKMLbsz3B539pzue^mq6RKl5Usd(%Su@ zKT>agd*{ihqHXbqhm&ddB1g;JBPC_!83Tpb5txl;syC}@B6Fj?pq$v->~|VBA3S{b zo^ocQAdk^^R>I1u$WOpmbl5mvZiv zVa;cv^#H*svPj>Cc8!HVf!Iuq8y4F?%YLU=^I7+*T^<^6G~cn@%I9gWfxNnVDz%6D zLVya+<+d9Ij0fD_SmaG z?sc!Vt~k&0TGxazS#;VSrFskn6xdF^>9)#cWx+7oH&Kh6v2Q5}ml81A!Mwa+`Lf%p zeCM^Ajh+}9QnaqSMYVLb&E&#(c{VgmnBIgy`i!OvNx8W6OXq*{KnN7o)Mg}E8ftt9 zumim{@y(|41lgYfykdGntheMfM}bmOMNnjrVaPZMNxTJYU(S^bFS*JB0)n@G;+fb5 zrF^s9usk(fMNU|~sM1@omoW}3iKgP?)J+!ms8AY@{UGBd2j&4gz$a#abb$6fg;!^1 zAMM(iW>7oYao(q#7w<%`h2kmm`iR5f1Mn*R*iJD}Ki}VzUCQc-5cacF^;dQ&3V%KH zWW;Zx!Iu5hT(iWEi`EEfG|vYGl{nUN%!yupZ)p%lHLT(l#4z#8ddcKx(`eKh^2*q&)mj~88ZW(*5= zDaE!NV=123vUBoe9DfWpDZR3fd-T0s`B_@QsF#f_x_gha+g$t z@@Gfe$OACtd8V9$9e-QcvG4ET(OoL>xo+yegI4&TKr|-_e0sv-Wl+2raeMnuYWhc%Y(lQvQ@YEGYn^r8~UyY?x;8)ZdGtO zcj;U25%=C-&@}F_x5-*9hum~=JPA>dYJyGz@>onnH*|f()r+9GxHmNiIA*%8SGsqu zwTG#Vg}IDb3fQ%T)k?F!hD|*kNi)hImty{2;nMk-JZ=Eo-w?iH7rteGhfd{+x%gCO z?kvk{SR@q!f$ZFC%`sVydd+leRC`dwO!;g}S+{a@N4me7)^Uw(tUqzFv7CJr`(@8p z(wU{bD#4E>+SWN#P?{(A(_PLPPWKEnM0WU>alhftL!_^wMD5L^dHDRcZkr;n%(rDm zv0DtFVH*=h8Tb<(7?W$>nRGJLCL#eO?&d=bxWeXqFZ>zUS14Ml2z$Gw;6(r5DhW z^29;9=aS@nE$@o?Qa8dUgA-(aB0)NP^Bz7K6_e#*SZY>9d{w*j}$CE$3t7*EA0Q15tfc&xLx z>h7|A%oA(cs`kgzV&FoVuo&Xk1g~K|nm^vQ zi3fAKzo>P&?hNG=)TnnmJ6qLjA0rEXNCvT?0||7i2<_Oio$YC3SMRC034Gh@_}HyA zxSxVM+1QcrByXdZE2RJjs%OInrpAI^)^J*F?(fp|B?2b|>@(b^13!?Oo<6^^@-E9N z9OP-`aXx6Wub=c@IiY|+U~~#P(ii_#SmIOR2TPah!=-qtf=#8_dMD33+S^VmERYIT zx*j6|_ub0p*9v}>@BIF!^iQ_p5m`|ymezh$ID3cZQw1=v-RiEd4)Icjf)|%*<>YK{ zK#1Sc!ARx~jSgA3X?6jL7Ch;C(6hR}lX1#dYn70fb5knYx+q^X_|fHD8p4nukX?~j z4o#aC=+>!p@1X%y(5KHBm5$LFZ-RbeIg5iG0XAq@j#}vA&59I@Po9{B)Jg~A ztoGQ&iqmD4qXQTQ#(jKxPniUl?xnLUzFL=6LT8S=LfO{026#V;eoD#?`Hn^x;K%}7^B>ZuhBd3r&uCue~d6IWwCh=O~B3#Ud~fBTYLmn zZb}ZTgj7M%CmS^E6qK!@Q4bSWEK^d*{e5X^za&nyr-jTnqMK+GH7>${isbR*vtPd& zec}W{%FrD(;VES7hlH6TJ8B8H>;6e?!oC&96_aO0Xe&r{>A$>+zs6Iy3Xnl%eLVN1 z*ec4TP*`B4Zu+-*M?cXe&@}d_`3tfBaUdh3qvh zWKCxhW%7td@RsO-*Y8~Mn&b1xU92|Z_sOzMmaVZWxDftY7lW}SQ=;;1p){i7gT7eJ zHLl28-uCZw?S(phkMaAiB9cT;*>v`g(myxYKfP$fshk{zNQd6XaOqsPuQ8B{qgSXV zj-Mrb+lN;0F<+b>cx9VF*pz)@G(`gM7$ZySx5J`3%i+kO`Z1wUf8!p?0ODMB%hA3T zkgU(8ip4U>Wq-s0xRg!cBMTUdF1aHI14qovvzyg{KwC8~Td!q`9q6vJ!}-8QfIZ>i z#CtI5Sfqj#=fI}q{Vc%_3}iE$`5qB}AzP(@46vXv?)Fi6cYPkmlf{jcZM6!2Ty*>W zqpp|n*S?pLYk9W;>F@TM(C8^5rzl$64p(^N%P8wt>1Cs^>(D|NXJ)VD|m!2LCDq$03i?v zynLknf@sI>9J6Sn7k7!W=p)RHC)XqfV>8h;Wki#W!T{y{Y-|*IRG}9r^??6I4End5(>f zlpU<2)?&jc51jgsqhb}y6Jgtl_(r?bYOq&+5I<*UPgz!mF;r$09GZyx$|c}2PKY;$ z(syD1^rU_w6oO_gvp_sUHrX|f^DkX@yp8&m_%fMupUW*+cr$qEQl-}ttDx#^5Zb2ldtzSn1XCz?Oc(jTlk1G zSuO62j+^bH``l`H9AD*U9p{RQ*|n5|hWX81?eZ$T`>3I!541aCUh!Olh+XHHjFrpP zfwN?kxP592YI3lwYwboX46J#XsTpa4%gGGg zfv3yG%$^hOvHt<|$`Fly^~p1mwoO5ZmBSjEe(tzL(I>sW$1>9Ju)q)EmQz&cRF^Ip zRTT%kK(yX0FacP5GrdXm0Q6+h`%^}(;rQ;5pfSqGa=lB9QWpa${=Er8p-udDK zC_9)a^#cTzfmYh0);~oYU7OyB*6fA{Nxqw7yt>Py@E>DLqtFmCiPbyY+cYVu2*rzOlPLaTf1*R%#UAn`>N=I$ zWFgwD(YHev%tmh%liJd4g-#ZXkHh$nm}c_xOhG#tE@8qL=m_L@ZM&uM;Nrc7`5hFbIq>{oSzI2 zuNlu{Cn-x$uswNgoo*8@)31~6h!`i!K#?usb(f#4Y&U_NkvEJs^v0l-(444f53@$< zE=38Rg*IklU8EK;)F4-W*-e6H_}0ZxE#bLRESg~=T6SgoM?d_(;I?nDF5?EEGfUdO zd%W{-@Hw-H4x4-e15Ox(yHlksU9ON`-<KziNW~3-DHI? zShLuxYB|+fSD@RMjy0Ff9Z{LuuPzgs5}W^=2&|p{*~hfAaU&}a#b}PO81*s>JbBpWbVhO zc~h!;s&tli=i6P~t+g3%LOgzP>SS;n9JEU#}+MU%Xv7g7tT*jq~15 z-hN|LZZP3srF21QOsT0Duilh#!X`EgKC|*I>A=Z!H8(ehX3X8_2Yc}oC~{t4oqLfY z3&6ual}oI16Y`X~o$d*p?zbk-BKoukI&dv)tvQ`txSOtd$1pG*f0yTd%#l`*imP+l zrI>T)@c`rtF-iOfG3Gs23)Q3@zN_u2Irh*O8j|BAy-cM zLRsq#fvg7St&tLr{9-OxVu^02ygN?VzrL5SE{wniCfdRuX+oK{8j?ZK?{2~$n&tXC zg?xQVvdW<#B?Xruf0bdEx;TsKwcj?0usx~*@4U?OhvSfRuCD{}d|Qxo?l)D0iS@?5 zo_7{5q6Gb{vy&MONidntFhTjdhn+}&qW8I*5`Zf@<0+E?W=Xj6`vJF^ybgfs$X{YV zrG%!hn{q0|B*cbbtB}5am=5dDn44eG=|{!;{=zrx2-4>HOd;C&Pf}nUSLHj?sb5e^ zmh~l!RuRZm@L0?6lv=X#AHc84R=b4L?Ip&9yamva*cUO$A5_%LFC;E`CI`ME+Y(hY z&%AU0$DDvH_%qq%rD;cBbaNl3LoNkCWwQen` z8%XK^aaXo!&Pd^R;r!(CJ@#KsWHOyhMY(H@3&4Me>Rgs1?e8V@h45Ya`V_?Zyy})? zt2|6)b~#+u0Z)}DRA1A=_H^D)%z9()lX3?o$Ldp@U9}9CkxBg^W-12>Aw7IR{Mae}YLSA*yT18CSdhyVj3c3js3W0oo*lcxzT(qvy*YprimU4ih zzqx)6i9w|ILHFTavPd8t|E}FPYWs_Rk&jte4Bc);*LN4D|BCtT?9zet1@~=~PhFjB zzIZN!QmU6QX=RZY2+DIwzKYrGo|492)l2>|3l$d;Iu8E9(h; zlEkwztd^s*2?go&>9&#e%B0Q*{jhfLj8$QI%g;Xo0*5k-bNuqAGf$5W7ize35S3tS zk_^`wYTWhmYn%pyMHQp2LqkJYDuhiB0TxKn+7Ydr3-a+;U1H-N#lm~^yvKu+`n}Ef z3WntM1nAkrr^XlzDEu#07~kK#6=uKOI=`Kt*Lqp8V@lyT+CB~sCa>2*;H$9vpzu|> zm88iEF(NnRXqX4f?zRnp_~){55Oo zgOu0;i0ExV~fD4_VfvQ7QIs za(z~|naX31Og77|_W_+pDD_#pc;rVxU3 zz?jw#Tu15SQD5g&;9MERg};0}(a51i%p@#B*06R>^yQ*93EgS3_uS81q^ktSbeSRU z;oIeV%#A!@T?Oq?*u?LvVp5WMklqEv5okHKtHZt8x7y5qptxmmX$CVco~mCVx%{4O z)8UZgS8LTylOkXJz^`eW)r>Mix-;$B&60Szcvvnn1P#WlJ;KR{8CY?W^e8xAT{g^b zFJ_DX;Vac4xyqQ<&i6%r128V4FhZqC3&o?zwh)>mtnfmUdjz-2m9`X;z#YHYF3fK8U3(p;t zdPEz|b%We*Q8XAlYH=$sTrNTPlhp6AHLF2?ehmDg3pn0H;=TYP5bNXSo*4_lU4J(HHb-HQTnT36&+-)IW3ee_)=XjZTR zJ5n@=VQz1nPxQ+2cCOR)=2wTej>N-^A0kF{45R_)k=?57?Ck6tnWeSzqZr5DbS)Wm zPE_-Qn3#SudL2fk8wNo8MQ*Rqfu3R!#9Ydxtelpo`xG=YZ=)6__W7Pv8{Rq^M8ozQ zM@Im_f|4ZiZOmY{9x}Sxw-OhpZed{~cNzDK#GMp4a*boyet^AT`2CT^?};A1javM! z-ATE!Q$)iWYjtTE^kl!#e=se$FoyLcT}S*yZRy+3mX$TN2nMiQ9vi48)l!>nqaLGZ zr3LH2X$J%n*&8G|yuUm!f%U=Bi&t+ir9#3eU;^J_;xcQDqWye=l-KY90%Fn>Biz8U zbqQt9E&vD}?7FrL(9})h!5A;-vXr`t2gcTkRKZ5r?@E5h~wy65i5S$a;caYe6AbPCln0Rgd{nGRc zyS>5usp+Zn^9JMYp&*{UNjPOiFDI)100q&@2MHyhw)J0ydpTsJ<&$KYe>ZF5zi_tM;|SWF{jId&Z}nK?!hR1Q z|Hh<#(>_*_PPWc$I^FNhUR{;&&0CdOQJn3hxq)D`Ab|OGOp`S%U$o^iVxMktl38DL zk|Mx!f*t3lm*Y0OAr0W-DtbK5>D~TDb_j5=S+lg8Kw9e(!@b%U9%_w^Gq++eExw*{ES78h%7tOMr z)o^Ps!3WKZ?k~P|OjJ0&>VaGv1U{^C-9d8Zq#k2EJUU66D`f0t3F<8JMttQN;dH@< z7J+!pG-I3V_q0?IF)+p;|0sLIPy)s5!yTwL`T`t&Wkkd+%^kKiDT9EIc%X8zj9!l* z(6JwjdXd}8N6QZuVW+Dd-|b_t!mQX8Wi-FoQb5}UF*&!UEk7p1$zChXSKMHwHp>E> z#PM@`AyCN>nF0jxs@8!Pz^X-Wb>H4I-aqKcD5B?~A^(iCjtNMXY>F_9FXWe8w^tIn zWOMwtk0TBcnb3Qv`YDkh9~BZNntL{jxxFK0NV^sD`T`_wv&vCHMm03&uGI;_Wu3m= zK0xk`W)nAcf5(SandOwXbBb(Q3tN`2bF)#@)J~Yr07@q!u>n=Zo31VX*>s~F5vNlr zu;Yj4V9JME_8{A1x6gcw3CM`-5!2=>Ty*&<^5(bjjGHXr_EpO@#gjIjv}~T4JuK-u$=0C9RjAh#A1`{1oGw4*Ir;;zW{pS zT<2m8;R%gONU&fpbB`Lg{C6YU{i73k`2>`+y*bzIiPEp-GZ$MkiU5z+nj*r#y21|C@=1U%NduA%wHgZ`*WlVmlyJXJuou<8${7LUjAk{IOUE4#4Sif? zck?7k^2X#(_Dcjn(yH;>ha`2Jiunh%wDrZ4zq-m&D*^5G+H)85rZ(9O`^rcBu8Z5NP z!bZMGm2GyVVNK>}CoE57J5A;zQd@OM-+MtPfhdW>5u=sM2ac{6oxf*+ywYYOlf=_K z@*GR`H>D1BBL!{%Ab7$0^LmK1e@H7i-V&=awV2Wu$rl?FBIzQT+HY6jQruk*ekEB7 zh;Kf3)EC&5T%iIu@=Whsx?3Sz`+KL?!_kn31Ua@fSf0^`&R!E}_X8-B$>TLxr z&TdGcRVlVBnlVKKL&7;d;uzx~q>~B&b_i4u0wLv@L&JfWfjcwZ_4Kq=7MmX;R{ife zR|%!p_(UcoFjhI&Z%4YhC+G61W{4Ss1TSYYA}*{m!@N9wZvYBUqd}ApBx}+mc6+1p z*t<#{2?4YYhx_?uZwa8b>#R!jj`&(5%^Q4`*5BOT31*1zh-5F*et-MMU_d93Y`njo zK8MTMq+w!-*M2dHrs!Uhsr_}ASJlTF4P>S3HLL*NpL_PkosB{DzkyZ{1hm=0`!0m(AGT^L4G<8qA3zxMf<{>66Ww>dR+7oVd=WJ?W4ArLz4s`X@Q#krwZ6s!ap zb{l1kY_aQ2AEjlVnrK%7xm58gG}>rw0T641qh*NSMEq0Wx8`u33BNV?1|XiUA5C3b zD3|veKZL#oi&t*y{u63xAi9IAzjmClW&PgO{z*R7DqB|ec-7!41IUu2r-vBwMx1}n zfQoO9wBnA3ESFCtfE{;y-@IDzIu0`l@cl#$UP{is0@$nZBLV|=j@*X$hp=< z*YjA>cAfvjlG}W8{MOUiny2PCWD7T445u+c~DZ8Uizfm55D!pk`Pbv+x)4_abq~mkbT|(8!7Jd)T zwD#-IKarh#zvPG1~4Za z%#EV~z3Tc$1fZx`nJK?j4{?(iKEu$%%9W^Kzucd`eYX>JIVAtMzeb0RLHFa%u zLCnR(|BZEfhN^7G$V^L;>-03ge1R=}XK3s-pa5&<@{&~+Wq=%|$1Sn7c#djeansvA zp%&;wAL5Z_+hPIp`RVg#8&Vx@fgPvXzR9)*OW2`u*-po)`O?{q={PUf{8B7|C>0gZ zhuBa$=&kax$*GyJHTYl39=n#<%}^_*MTo5xqUzC(BmqF52;*HvewK1`z?T`2bUf+UKN-QKi^|rxmj`f07ueK&nh~~#0HlrzXb?%Nc94F-YP%1{V-2{DpoX}9VF$D|^mk%H2-$|2BcP&QG zu^jqvmjabrkM(#q!?jPb+l0yPOm%koHHagLXUpCkSN&-k4Bj8m3Uy(qv%ielv^^Vs zKD(u+xOIO0_N^M7F~My+fP&8TCZv7C86X3ERl)&i1qVR#1OK$?C2&7aVP=Zk+uQs7 zp#+MG_Ra6Ul_fB0T|n6YIMjQ4PCIf6TttA}L;MT1cgmi2&n{r1Ylt|W{FG6!ht;8w z8YD8L^j-#YtmTnmH-yGnFI>3t%^%6ZC$8j+&TFR8$v1Gj3OBBK2h^FoV(c#{9}8E9 z>q=4IC`ZlOxmsd?x2pz+se%Y+bD~FECl2L}Ss^nY#p3YDBdashc;rENlK1fE-6cAk zdZW3V@y;*|Fwc^6c}ftTNyedC07bwdS?qpS%5~MmpRgxj2pA8r|HLHCZ|wApHC*=@ z?>G_iLB3R{l5=vlgg}NB69RyM@4-sW=&D~A%%+@*vK0pBetwpKbutf<84LD(hkL`t z_7?LU-=B4=CKZmJfM62%ZwI0yB|z-N`cS2~-+Y5>HrW^ehP%w@ZE@@PB^ZQ?{#V+8 zV8y*kbQP2^x7sY}v;eknET#~$H{Uo#7P!z-kRJ1@yyJ9l-?AaX<@7)mgcpVp+*Z|m zj+px`SGHW-+{UId(&7|!%NPqX-%2S*@#sE%jlSJZvH6~j27L;6108Rh7cT^`6ZssY z%WZt*P&tMma~py%v^z|2d%xOJ} zgOlk1kh+iaifi9wz^a$PrKs{ z4YS^(%&_;=Y6qEZn4S*fMuKG%JT(n;yEsl9t0!fcL~!xyT7^9NevfA7eUQ53?f{Gc zpy>rgb#|c&3O_{dmg}tW6T(6?2eQ{_a)|8+&Yl#w{h_9Kr;N~Pz>)|o=Y#qH z5`Z?&?;(#FPUX3$ua?+b$ks`JCMiY(KYR_Y(Ws96rNp@WueW+Ol4MRyBr#)S2+>Ur@ddb7G4?rED?nqj`7oBxYGm;CfJ?EKwj^ z>_B}M#bnL>InoT$)sJbyPu3lk<(`dC`w=J&&h$}Uc;c|~N9NHgWYfV$$yx+)f37nM zMCNl@!~@PVKIFqrK#~n7~;~f>`SMV?I>RtJUF`w7IK#V*pCwOgo*7pparGUd_D?{P_ z6#(%8<+FP(y+1I9rJROU?`dlQ#mw&yT`W8~vU(yQjx3>aO)kq*o-z{&V!XS$)pte& zokUp~)czF7z!^+p6gCOP6&Ap?5b`YTr}=shz8S6>Ag+IQ&mFAA9J6B2_D$9S*Li*@8+bucW`xi`PC6PiT`fq0#QO4K@jkA5XOv@!dy|2ow@Zd(h+6LX3Gf%7SDht@HkH!taGYn))XinPg$%Lys zke`w`Qyk#JQ6IX-4t@&!d%DU%3CPBxvnA4_;dK5H7k7=WV{Y`E|NLfEDACk4ty~%?plJ7^{=4>liW-BI zr%y2oVdrBSlCZ|CK1*BcwLWdl{nbLoO8YGufTfVLTv0Qa?ScekQ8PKa-|MT!HvyKj z)0-m2?AL{1*md_X9h>`lAV8_)8(+r{=oL^u z<@qJ8+c599dW|Km5vQ46MCB~0Km>oRf(6j0gR+=n>lqe6p0(0huh;-Z*! zsF@}|G*t8yxX-qh;b&wGE@z6l-kJhCsH@(thU22)1b#C3Gzz|ew+AI={{3*#K)s9W zX@tt$uDQEV@|QHM7*@`rk`nlSD_tLt9hes~Q|FGP?{67e$r%8eBA|XnXaq13aIENX z{to*(uKu0i*hN*T%{h(H&&`cv!m}6rXl@1re54wTxGA4Mg*=$d02+tv#`C%8TESb0s`nyzP=F9@gLzOy)T*c_7cTs8uu|rVqZR6jJ8!SmgQHbLG@T@oUeYd6M=ri?N5su&X z3^XxtlMGhS^rJrm_ueUXVye+)KIfKQGy@8<%pnE8-}s#<{1CsVeSh%dBY^w(hGV)V zgK^sIUgq~_Kb-_}Y8Y%i`Krd=Z}engDP2t1D9acD9P0QSLG1k-xw`;2IM}igCwe^* z>#C>6Yr@Y%e?u_&GhA*bFFjY%q^y{<-$Txcap3(5TK|Cs>9vxayD(Go^769e2v0y( z3`x)Dd*8zL3z8HTCZ>T-4)}(q?C-;f0R7cH3j1!e&N}{uc|4{T_5N_CJe9Ez;_Fb1 zEq3D`keDJ=+N^4dCG>gJ)$xOvHXTlK#V)}s^nR*8#c;Bb$#YLph^KJmfMbI%G@Hmr zvEQYM=Xrxk1SK8{fs_!YwY5(LHkiJxZSS`>&WCcw+FKIQ#12i+fUyeJme;gaI=Q4s z5T+TE%AP3X212JY2drkw_lW8qp+W-u*G`C^Js3;4pp^3rNv>(cXDH+Mx1oz?Nov1x zeG^Vz361-iQ{07ajF0usVc#1OXgfl@tx&zqe_`(2p)P=suzO|9F&53|eECN@1b4~O z%93@$1q5-AF800qPln1=VoVrbSfzmb1%+P1=7|6gGd7v3{o>hALF^&UzR7Ggq?WRT z`<8IEt#3^+JWuT#01+%4#?V6hRyKE=;4YXW;bAiq2&t8r_aHaXg5ka+Tc1kaSQ~Me zNVgFkcZODYO#1EsftA|%9v6Cf!3t1N-=&5n>QKZ#=Cl2u+)@9|GiyM5Ve7k_Aw4 zNl7w1H3n)BzZa5&tf&k#qsnf9?UpVI&7wKI;w0V}be@j=TUfx;e8367}pcJsJg8 z`yX$YX@GRp-?@R{_PPcK0aUiaQDONlwsI@o=0Cu+W@|Wi^FPTU;&i26N@rxx+*?q8 zM#w4YxK{({U&&kJ3hsBf`uIm@^_#Y{pk9*jCqkxD3MmMUQ&TB$iO)O+<{PnS@qEzu z6)tB1E^h7py4Yah&jC0}5^13J9b@(%BZHM6UJtmCYJ-Y-as)~|oE!7$dW#4NvH$!T z+(jlvX-95I>CNc=AU01B7H)YQ?ag9_=ZuU7pc-xNDUa;NQzf&J&WuKa*F6yui|{H; z_>3t1a^D%Pba2=*X|S>=6I-isvIyuecWI-QO_IY4?Wel)nD3=SBVxosz7L963B$Nl zZ_CD_4?8I1;*RMD=>PiEs-Fgw{j(@;$UI1HuW9pp-#>;}KLNr0CYxE>#ZBjKfYaq1 zh%v$q76DWPv_gGEi4Uv922z}_3Lv=hizYxhA6<9ygQ9;j2@oFAWNy(m%EfB0XhmMW z-#rEpSoRp;%SygbAccjG=KOJsmaEb+Z5P{FlO~p{J1J0l0On)$o)qB%NW8XZu5gmn z&R})HbIO1Xe;0xDG@RKEMFCk^`Is8df#6!KhymFCSz$;1RCL)#oyZOd=bn>|55vNZ z%tI^}w_j-;<~+O00E-jvh2=;^pb4N#M{8rF?lX3e5MO=FZ+vL(?RYnA@W=YX`nLG@ zc6FO_O~K+|P&Gywy)`(3%U5M94RH=vaFt>S`unISKKfzT!SO%ALgvjjO%+nO_ei2w4jP5#3@q%za}wV7z~CWGfsq{Q#)^;$1@@ z;{vT7*2t-8%`vC33AypAB$2R+3K0UyW$nAJ;$kf?rYy@wZ>$RkWL3}HFhW5;7BZTb z-#==QDdVUiH+vF3M>)ee!`1teXN|V>9)4u9@eVQg{6%Rytyz z>7e51yiOJ<&@tb&SkqnR`^fV0R>t?n-9MN|R3Ic$b_Siv6+Zi2fy zo`7pw#e$Mu7;G`m>pS1VT%9VHtpNe#W(Fc_J8^V~NB6d%>E-&#=whD68g zH+V*h9k?0PDd2|%S!ve1i)c*yrcP5qEFOWacrVswWf}t?8ucNxTz%tkRTgZy?m-Y_usxRhsk^<CWKLo`S9@o;jw2p5VLx+HoS z+r_<#h$_oKr!QS3q!>10$PQ=a$TOVucM#~d`(Xv&p$+yZzKChE5ijk99gAjA^$cO- zYwl=>ryfFKg46%nOuDRTM&(Je(L^XSgY~{!=jsw!_{h&-zbx6{@Ctqcq@NJD_7R32CAn3eAz*6jS(ChkXYn@z#0*4dPRyXnA*{Z)5lT& z@NErAB#T?p$dg0-*OH*l1}HcPL0#H(gLOPmh=4i@RAAj6J|hvfkwXDu0*CYECSDnh z!)1CQ;IuO}3aHb%<=baxXUU5I?g*DAn;*j%wOfFWjF8{DwHzs(w_5t0Fweu+mln9ZcP3v0J5V0A}`~*3;HpCp-;t>mq z$d$`7Qvs$OdOPivQ{xk!La+gjqh!8aE0CKz1qlw4u&*jJxpvEAB7hRI(xqFI5Pizgd@(xL8B6_l<0 zb@svUMocHY!D2XoMQH<(2E10$G>5?Os03syr@UmWHh(B+-&3<3&iC8G$*z)Xckzka|v`x2^g#qKnmOO>BW8ICxHBzQzX&7La%cGTqj_kvc1+7!}kjsL5$Y@ zn_*&L_klZ{a6kan1P)v7DS5=fg_c1cX0K@ns<$@A@br+jGnAv2?8Cb9V4j=Gnz?v0IogeTblvW{Mb#oYzRzrms5JUK0tRINo@=2H+AmIAQSl5+unn)I{2^Ap~QRWEDpg8??@Fbncx%Y$vFZKieC3Gt=ZQ zI1#x23-C`yf6PT9Iek6>a*{?k{*(EsPC0^M9dX;QBbzDo*)&+Z|4EZ zH9&caY+jK0?A0H$KOqd}*l7T+QSg=1O$G2W-Hhu`dfHp9y>>jc8iyDF$O}~^>5fbW z7!2nL#$RAJb#+a258gLL%Gdlo+u^&MWlrd~bU`u7#@W~@pa zq|Sr~$5z@{m%tRQIV< z1B|(D?wn9op$;JCVpdj@1#5jDTbyqWIDMPeR?l(&U76@3ZJ;y5PwwBO#Hebc;+pmp}~m{qdU) zulrN^CvTNs^f@NFVc3&4-m9mg$qnA25tRI0RNRhr`CDp7Fo88bXdj;R@H^|o49H&F zed*5T?5)|CHM_1K>}D>1v9a}bryeYYP+Uh6hMBP&>5|O6=}1twL7D8}5zAh)p6flq zI!xXQrAs)6Ty$;=k1u_rcqv$G`b&3;LY3lNGQ<;ed~XDFI+~8wl?&liDbAWZhM#$u zgiKg@Wpv(+;~xD?`dWWzoNKN_>glZlY4y!lKAUS)zfw&p)6;FYL)(p!F)F#cW6g!Q zM{M_kn|g9(ZLmC~bMirZQf7m!-#S8(qbZ8!ZO8XzKYxxzlweQ?XIK77{f*3)!q0lW z)iNa`P^-b$l?1vF{Lz#4ba=b^L=QsOEz*70LS^7hZrMsgG>@U0SM@AiNmn?G+!Oca6kIk_p-driNSe%bcGPD2t>Q5x@`fhkIq-9t0@L$qt*!bhC+O4B0 zga0O65^+N*K2rtsEL)oEkNRgtbDN59IvtCdo@#7VEFW$ZDcyb@zI$@;>j_!@z0oAx z%@K1gr{iZzHdz1uo^^|CzyE1d2Hsiu{l9G(5QN%f|4(0#q%W`UI(7W}Ita4Nf4}8F zKglHgJ01V|i5%7nI1uo^Uo_r_|2dNU?hU+m|F_|YZ}R^~ZpZ(h)yUNG`BW`7W4Ee& zolxl6#bMzq-#~=YB6@`l4I7jsl7Op;pHI(AaQ*&iXM)h!!S(;AXJ+Jkw-#g8gItTx=Cqp>5?9_{F4>7u4{yH@9B_QBcN{x9v2Xcg3 zwFgsa`;>Y81x2x0Oqj_9;yt@uENj;f;-iEy` zhLS^3x^{z}@UeYoqVMwRrS1c5MnWh)V@jbQ$mZsRy6DWlfzJBrsnkL7!8q1wVjRiN ztU|(l#gO}8%$o3F@8oT^sM;2Q_ID|^Cwn1M=# zG&#g;ULWIHt`6Bf4$zquH#JrF{OM6{w>mi2=UQ>gEq2)VO+*)p9K-;+-$<{;A6-vd z4)4WcKPxs0;k=K5f-t}=b$O=MUK;WUd@EjV^r`18;n2e09sMM;JfFe!f?fmIb$_F+ zYUs7C`YEZ#lI+4Jm5h_yQ- z*|j}E_Jjz`s>caC^s+Haj6vK=-_kJ2aYXpPI>{srM};pJQ_xazKku4qYX=V{34yGR zQ|(pP4+>o00OYi||JwIL5`DdKWMMZtA$f~Jz=C_^FDHs=Q1hVB{rGPSl6UMD^33Ow-Dn3$amSeK+@zj46w|WddI+ z@Rx@)@DZANDQEUv$WZV&ffCH)`k%$8HVj)2fR7W3cFA6#PH1Q>0e z^p((D#k);-cip>d_ltm26Lom##VY=_CI5NPh67l25~!tEz4HJ4NM<_xOGX$$e})sr z|I-WylE#PmWW!yopKi%XUMx_f@fwHXT=eOwb2*kV)`w#45cLojda*f{T#SF;1Ng^) z91-QxAC~rtqQIB_#ZQ_g^>u&u3+W!LTMf z#zI_D*8iu?B|>;U{6YNBOP1mP2R9`m1-ceh|L_?up0loy8OjML{-0~e(XA+ZoLDyb zRD3_S3c;JA{GWckLMzz}pi2|NzzR60>JLRrs0}R_yi44_UU=YH1G8#g@hbY)GMN}9 z<ok8at|HsAwE5Z@@=H7!0B?G!D-zac37-`!%g1nzdI4GJcYXE}FYytwm}4`;>@5`tWkYC#?Og9jzP zfx!Wsa|{v;B`zhWGwho&e`FH==sOow?Y2KHz9{5SB~!9lnscQs2ykUEzuha7OjJp{ zpx(=XKxa1wbL=m02*Z+%^Af>Xqj)5^|J)Z%0{o^1KE_4p>W7r5p4A3Pr>TRU^J3`~ zRh-t+>0lUJD}MKcAQmHx($JSU)9N<ZbSbiP>VH7+)tGyY5nUzobUYB zp%ANgzk;$DY^ll^gyl@`O7z=r-?qh zJ&A6Ye!q2ee|mniKBFdJkB(>max3ZR{-tKS;c%d=7@FKs(WCKqkU}tcFy#@LnnpFi z0iQSZ=^iM5xci(tWRSV|symTk%LzPQtE*ExXw;y6`1EPObr9W_2ExFoeqT(qvsqRC zI-yv|-qn0+=@H#Hc%*AFn%8vh7dwnBhF6sl{1p#mGQEFa?;S_-g2n+8cs^mhB6Hj{ zU@mghPZIeI-_~sZv!i+w?;iJH=?Ti@DpxqZhp*-Afe)K%94f-(7-*{@4|h?~YzuY2 zQ~tGZV0QtV&HFW%GpN-QgEjWOtWvQx7^| zP+yb)eFoY2&NNsf|G7}25PV~-XZCl+h3Y_!TKGrL_U$C&}?ZK3pIddpQ*Pe_pO z+mDM8q$Ve?B-&ct&YAUoJDr}?EpKgXI^V^SF_aGs7pT+sBW>u>K-ZfI;4~l6Agk!! zG>+6GNm|*=s7-u%I>{gt=%`g6q-+(vQnHXfrMq5uTyoaJxDtoh9-D)cBdm(=)rAgwvDQf`~AP^XX0` z$?0?hago5_K-nmipkl60{p4%EZc+WU_14mo>hZL-n~T+yQi$B3VJPWTy>(ji81alB!K4g`9j}k@@(5nXXUCDkdG-bKH za1-oRJmslOl0z6cb{QD>g(=NL7Z4C2wF(QST^BY^ z2nGrw5=towNOz|SB1j3+DK#M7&47xeAl(Bhh_opl7 z|9!u|zI!d!dLCi!`<(miv-fpfd(YW@qoeUJdMRFVUv$9GrWHzgDw1@69%!h~hl%ax zG8zw2Pe6|f=|lZUZ0UgbR+-F!t)1C}!35QBH9YO!vSy^9hk@ev!a^#Yj5Kgb8oWAPCa5L!%At0AwPdu zrUx~RLcFo`=FdExOMKG?lG1Uq4f$dz$*RQogKdo}b`bD>z>a;Kd+h0v zVuxps@!3kOu!H_Q&No~Y6W+{4kTALN_=Wz5W!`R{kJ>LcOXH?}tw1m7s?z)Xs}{f# zxsFtP!%bQIt4Qc7?t{{vrF=&~bo;}%9A9x*1w3o#CCr3x_`qZO%7h;rDF?6W*tN!$3qm^5}@ldv>CP+ z^w*yM^(uK~FitOxB7|N`yj@OKogH8WJP+hhq0pAE-k%M$W;5w9C#}JLVeb_-hVD$*nG#W03P^Q&Eq;+feN7Ip*#D$Gire_4SU#1Xuf%zB5cFwf9WH}{ zEgKw$@709~O0pzVED1!@9+`OJwjF2^7{Rq>7cVHmV z;kpVW*p^P_3(dq25@23pIJuR$&1sdbDfn58xV+VKL*rZ&G-l{zpFYvA zb?*z@-x@4PQNclapir4F%vi49No;9pnQ$GyQL(g#+%w_98+Y$coA5i0o(OG0G`>}i(Q18W z$w?Jus;fED|Qwd z9g%zw96Opv%$n~%CFf)4>tPq#TminV@Au6SR#kd``wrIUGH5?XEZnNl~>IAFB`dkcj2J`H(PN zy^dqoDdq(40a-YK~?Gn;+d6mpgAj$II`})Yp+i|HasR-Z;JO{wXh}HE#v5MQZ{~C5yverB5N)&nkQ08(?*+ra&z8eFFC{pvAQj+j=$upSe z6MXgxCzs=s+RbBIEIpmG=p%_;F3^btAQRhorGg3@GFo22kb~8@1fFk@)ABN&-5OV( z!#bsfUFc*g*d^Wh(0%c7$O4;j5eP{o&2>1+&wv3|?1vK5BX89HP#dPLHT`>j{(lge zlQbzL1x!h+2DLUyTX1JwYMIs>TX@G4X#z|{=pe8LiCjO|FP)GaFJF#b-&=S<#Ge4x z#B`eWJUvb7kLlL`{QjFc)#DVq+PheRP9#<_CP5DkWF53_L$Ecaww0&=ew$(^nf5Ge zKm8HK(S>g?nw|DavckF;RjTD)(#z^(&o5hfw35(kUFh9YchZx58e$20_Vh-Aevaa7 zb>iFU+zfbR={^n??k;DuI!oafZucd`j|8-~kvd*R_WTKs!ka`;4|^Y{!-B!QZ~NAp z#uukD04!&-Cis>1_i?h+2``sNqLvJ%*er9aUjF-?1I7#R#;eVj$$3f+j*+;Lxt~m) zM>b-_c{9o_0!eai%i%66=!}iK^@gLu(zK|#l*{>&AI84Fu(^yr$TaXV298#4tIF~h zUskGUmhY=Rz>xU)0P>exqO_@W#^-=P$r+xoIr4U>=gJiDoK7vMELXF{*_`Ll(2E=~ z@ThIit<)(405Iy`yA4oP3}$`PIhQ+Vifyie*%hLDGhzy61`|F<8?L{y@aS=bi!e4+ zIz2B!j|3LD44jt5(j7@5z8>IxtAUS{)^-iwrh;Lxb^B>VzboYA*NL_4^d497N%`k_OPz^OP$7@ zB;X3aMxKhv6=6Bu!?;-&gdL(N-+jWbicdu1D7((AQK5`|U0-sXvhomrwMKLLmy&y3 z`zf@b=9Mztig4x7uXGSi;AVW@l&IYiV@sw! zI;=((=?isu)-&pO_03cxmn;>`R2ex=)@^T_;OcVPRpr zS4(kLNHxE*ctJI2+U3$11E3g@sPGvXt@7Wi%J+L!zp!lt!4>21u+lo?18NGFVir{I+)WM$Z@CRg&SC5AKg&eYj~1B_-SE;ZIm2qY@9JgaNS7@OSlG*f=(uK z1D(yBy zaE>ROW3LjZ0_HAL(E2oKeac7Stu*JJH0A3{ktp$ilutA@9^{|?iv8wn7@=o(^5OKO zL2XYTHyw(DmoU7v`8Qilh;YTY8Zk%3cued{nYx90c{yZ!Tfg+62es>$a9D^Kqx8B@ zX;Z3zIK&D*Sb298o9q_%FsGpAF}6k8`km5-ok)b|_9=&Psy8=F!C``W0lFjP!rDa~ zqcYSmD2xB?-ZSD1n8u--B6tt~MQ)^>fjouf%Wg460%>Ka;A~fyjXm9|?feR`qa?ZW z;80vl7sd%XOB{iNo+L-$V?PcCZG-&ikuRagLv(rQrn+ZwT^{=zF?=JFZV|(H9rIgB z1)w*Qs3y0>%*vpOj*iB^7ToaVZ*g(cx~fY^`fTPQ%fma73qQJq>|M<$g416`mY3`Z=7Cvqbxl3a1mvSh24}=;8GaiV1 zuRkO0RQ3oeMd0i{#>yj6rBz!)YoU^;)5Yu;dncV7(OpC*{aRW1hZ<{tqEg=-RFXKD zX-)U<;1oS>X`I?=e|am`yYx=%dOy z9AhlvoZ+}K$q@nDRbqpg3f4f#*f8etnHU#Z8HKCr=#sd>7CVyUEbjTj7vh3X`U3I5GRQY=2Z#hA)zU$5) zvahCW@w2CGl1NTo-ir(DcYA&N+;_Sop(z%Gu8<)+eVIl(S zR@GWbrkBZj%FCv^oa<`SOlnv8s}^|Hz4Lwl0w0nUf2rt_BJq5dW>enlAN@Tx(lX*Y zmDnrTE%U4FDKl}%OqOlEIc#f%`Jv?-$&u(OkNKEn=-g-7NTBm*z=H0)O5M%d2Jm@Zk`aa4EwaIx}MaPUFFz3riR%I}^O`;Dj;51 z6O)*K*3dt-wW*rzh(x(mZKYu1^}h{BDI8ycnSb#{iT+oo1s zGLf{@^ICg}O8fk|Jr_U)FZ5-`zlD)UnSUkrfS6HsaSJtfSQXdhd9bA_nTWz{kw4Bm zh(3<_(G4drG&O2)!*xMv+$(i$Z7o;As}u9{u>II|x`Uus6js^C7rZy zW72s*QiuhO3)8pfaJk(Oq(xK9wecmx(+?*-_pOl0%2(A5AdOwgTs7@hi=Qn^P_>Qx z6tIZ0(DoG(n+^jXC}^;FyqzF!z2-$bodeG9cR7wL8iZXo`PyA(jr8h6c)w0c;qiXs z9ffdU$s1$v{OF19b^_|tLhl8*lYZ&o0&v9O@-_OC|CC%hH9W_}CZ|xP{jYE+DCRJ{ zkEx`v5(GcxtHaVVe!=kdsQ{Ca8X_i>ZA_d8TpII(;SWmUdxld!^F#7?CD@}FYU407 zyYPLi^`=6}wEKWxQ9;4_KG5+_c7-&G$Mr!NA7nb;_{&We{}#$IgDF-9bR@TGcS*Vx z^S_uY@ueOno$#O6BXSHf{LkzEW#|9>HvV7j!oT0e|HaAo+FPJP}pPF?7=&73%nX79@_UJ!LS?YhDNJr8#uAcR$0Rm%h z0X}Z-imWEeRov_D67nY#zWty3kxYH4^)l!d$4ZBh(C{plybaqur5`1RpZo;^!M~;r zDVFaXtxi4lD}}qwCbaH_q|yi-d4Qb3Uet?x4o+e==jlyohe3X&$<_fzgT>^h>ZOW* z4aLD?pl9=86(c$uJ0)I=lxVW}z*u3l%;kk{jnj#{L3u|XmCv3u z=3jg67DB%bE3pgXvwp%55-dsdu~KA`Y6|rdbw0P#W^UzDC7v|S*iRrew*hGNA~JV> zm5;}1^TsvBOT`%$2dWO+c^4O#3Cbp&3tp*dkjGy!x4dv)sXg5;iHm%glV4$@u4TOW zmIQlozo|}U`9K3^E1aBS86~Rm{2s`f&+(+5d7ZF{r>#)1rrYo-K)uSpm9hgdqbQBH zxCLM)D~CxCnrc6!bYb#aQR^A8I{l#ZV-?|9$S?w+`5l8s#dJWAOb!!zeb`y@i#)I` z%s`ZY{OjV&JW*Idh)O59mKDs;k=tPWx} zJe!n)J1!Ob!J$s|6MGvNoDAT}5eW?2$;`Iq+#zajqaSk445Upw2Ar`m*#IwZ8+VsM zYnL8CO_c5E(vlS=mPFjoN+S0*h=I`l@UMJ#-rU#TKamK$;NRE(#ZCMFZ*|x?t>+On zwOUED{b>^Z)vM{C6X9FmM|3JN-{{mHOW(wn-uOavn??OL%ZVhO^zBPb*9OuBR%`rk zUAc56J>dQO=ytU6z3|rq-xz0)v@C}^H$1m1k_2E~CR>w`kidVuo)>bVy4#q%pJ)-LY)eyqPfqj7KOt*F#LUcqdn zy}^MjC>%Dul=nB-$qZ8?B_#|g`UufyQ_h#SYER;^stM%rxHoxg|9LGwc_#>`#IDWmW$q*!9Tv(h@{A1h_qC2 z+`Spv8Ga4Me}2Jp*I@aIl2TGdDcC(Y{Tj3ulJ~%uuL+OI?WiPXlxEat-kuHK{>SGq zRb!Sf-wE#u92sA-H%jJu@R}onpQesnlfbI_q|H*)HI0k&5=C&~cYY31zjjFpO2_|k zHOZbmy19d^GY%b{K+t@>VH*Ape=KRw)FVQQE1?|qwFRSgH2*lU2s)W&I2~OWDS_w> z-b+5%0~>;emqPWdkOL&3<%p2CTOG0rO)*VN2bg_#a;XnR8o&Sg5>s#B5vMQL5X8p(ENL|CmjOVuZ zWh8=TJ3valU8?onGuwU1684~=sCAi{?6zrf#dr7!k zr@WgR*rvdOW!G!$`O-k>$v@7~f&5Bw^@-c@n+?vEp1eUWmmId-YQM@u8r}jU7Gh$i zyUfdQv0)}HFpS%}uNe!Bz4lGA z9BfxJsPCM5myOH~eBSTsDL#HAL{C6W9Pw5Mx9bvUjNvC;FK3v^5_JnakX13j-@#*6Xow<9WF+Ju;tQu-KZ(94T35jRJ+v(v*t4NwJBk&y+BjOC8}oIsreH zET&{pk54>|;gONa@9*=F5Gg4=VSe>ZJMZLGzW(?SQ}BP!Z2c9M50(dRI4)PdLaP+# z4(tKGI(XG!RuJ*=vcG24d5Nax1lcG#o+FWZ>AXSnc@@=jC!aTTbShM*TxTqY*3&C% zyyo6VH4{fWQFvnl8*M&Iz42XR8A$LYg&x<7B2wnTjFEdZ6oSdjeCuP0+0P?(&O^c- zg;0?>gENDvaSomVHtt(dFj&hMt!W;|y#Og`ShsgwF-x+rOQ32iA=h?hL6&j`{<~*k zv$X*Mvua<`YgEaZUa6?EBM+)LDur)g!Q6JO-*&1MTZERSQk(D5h}$)>6x&P>4gcDU zPKam#V>w12(ITp>aV<1d94E`Hnwg8YhXbbG$-K-{_YPR17bwH6IyYUNNYzcj$8Ipa zbKY?&sU=X*J+yaq}7$c z_xMQ#H|KP*If3onRH!XzpN2guj9*MdFQvh!FiA`uHtu4 zKadlyOuq1lj!yd5tk}3F@<>-B^Rc8I!s{sLW3b5pW$zCggjYyQSg>ekE)z+D*nz6Y zK5fU!ZtAQCL;ct*>83C`Me5}P;+m@jC8sP2ZGo!tcQ3AkRyE*63gma?ib`DW+e}mg zgZVonwyJt5_*iGDZd2dp5S{IDnl&q~Mc^_%+P`ZO{>z~R+RDHXM%~{2^)kT+M|vRW z{5cn(82Sr!2od`T&iP|cN`;huh3zKu4Y>|KA= z)6vb{_V%sb3WE`qFDVj&J$9O5ydj#TTJlMtMIuoAau^n)Z##vC$iQR`ut!!ay{gcL zBi_PtyF(8xEv-{A$lY)k8>yA^6qhbVsoX;ANrw;9&?Gf~_z1ydT@<5d=|X)^w@Zh- z6qQBuTLXn_5NhlG+->)*&tZ7%$u+S1JW(hf2IQ-4{w7_~ZQl*4;BZqUq+HnF$};Zs zwTj?>!IkFWRLM;oac%5PKSsZB-);&@DpDzL!*60F9KKkgM*($LsV>FN*ZyZlw%cP=gw zS2Q$C>QD%L5deqJb(O|ET2<&25$XS8%?S2PdbF*@t$AZ1dlOonVOILnN+qE3&+B(phmRYYi08DDnp*yjI+(? zl;^vJ;J2lDI$LYJSjNjMwh~@LLl*z#bsQgJzb2!BpI4^h`t{d$O8St$tHOPUEtAVE za`iiQG9a?CL|>U#w2@AHO)kC)mARh{b@-$D{ydp#4Vk=yZAd-KGs5bUK; z>S31FpNOrq0M65xtI>JNLanP)1U zr#ia*a`}O7;(za|JNEUS^{))?+sTNd>+nuL6jnrtIpf_$xXXuR0g#byo{i)6saM<> z`yGh`u)@NCw=QYjL6rj_Oa%4YDjJP;Zfko@>^6G3d%s5s6GoZkr#T#qk%cd>YqYSM zaZ(%~4>5LMgSF)asvKnkwu-IB6TkUga zv9G1`pY&xkC|)ZEj;AXa(s}99Zrfl1;sG00t^2m=oDq9sbE@Y$!HLAK7p%3iqN2aF z^NiP`|3hITt;t200>gMX^;jb~RM@ajbxn}5ImFfi>N9QkGuyZ>VTYSCmV-Bl&w40U zK)lR`YodrWXQ7g9Q;wN9Gt7}mJof!Dg%Nu)qtk_=i|+*h%lRx(`l zFvr;$ZP4?)1Azg_D*J9YaNilxLqw>({}tdPzbt599*dN;WocE`&?Y9n&snaUpQ3|| z)EOyvh{;yT(q_{c#4+q0cBUFVD9}1B39sud0}fMPpWf{Zc}EI%12TR1kzqWxE1^fV zz&lVQD3X7fg$^ZB?n$s7$H5sQaXdPRBJ0ubm3Z_%NaC#f2aK)znyHx&nz)9>o4NIi zSHzc&$;rvJqY==jBX0k&a2$PbK)5~GvvTe_?ydX6TCXg$MrS0c`EnRlV^l$P-1hF! zI`2X!BInLnO$7o1%OWw**v%bPV45Bf>gj)L=jbXBg1U?^Vq(*KdicOhA;J8}KF^+E z<5BqZ_^MAKhy%b{jsumJYC<3oVxGVxbr*#p>_iyTL}iLey0{ z=r&S0z>a?l@I6b(7a|`y=;(|hVxT?TA!-GKpAIL{+M=;lRU%5^XQSY_V2a+J?wq_1 zB`H<`&ozjNscAyfX~!kbHyezg;egIqD*5zT3#$(Rd5cJBp|A`w)5($|dVp0OyzdV+ z`-*<8SC|ZfUe0%g;5|LsHrXz{!N2%_kTHK1(H%7a_wAq2<)`%k&LQ1-(@Rx&}y2!76XCmE3Y+D=V2W}sAiW|V{ zydO1>a%*Zg?)zLdG#~uD!NepT?%gP1whJQ?^9wIXRWmNNnT`>@kz{|mqaSq~DKxms zb9^VK<#xmuHh$(vYD$g7=75@0cKRA`*1I`6(+ypT+!0YSM2Sr!?5KBUdEVN3 zfw$!x{jR!O72rl+${*cLmWXsM8()vPr2k{S0{+|Ote6wYw?k4h>d6(`0Cj5Wr&5#j ztVyg7%n844$nxWgF;||uX%x6AwUmJ%gbc|-VtC+YV`CG|W`M|b2bdW$q|_Hi-4n=`r8y+ZA8y>b5# zmrXK5Y-PG|?+;YIO~;JJA`X z?2yPfgbJ9uBq_|7uKpqcWBd)!fVh~%cp zVEN+jxZ3-*(J3@KA$Vph+S{aE?Y{8ujD`Q!WSJ(@Pr5fMEA ztO!z*b%2jZ$-oxDmzh^BG_ZD9NPNQ!Xoubm3Dkyl>&ydk5dx20mwuK!*A#Kq;_fCK z8olt4ozVcNemwIwy|>)ULb)5+BNopam-4P&W7?hzU3_NGMK0uGN3{G?$!@DlHuBay zyuj5X=1~wBNr!swlY_Av-$&B%Vsb`Y>{}efo|-YtGKSf$jo$A`6>9f~XI6li4wxI( z@kz|*^fDqf%OLM7(oCP);;L2qVY$?|f5(l%8ky5QBvHzn(;7qRNEzUxjl-w9cG z)G>6m{4Iu-Tq}D+K>+DoEL6hjBQ*xVlsICpO${vRcb2@sz)^)72DU&!=ZS}8_G^Nj z%NI||YTvQZY@4iL!);2pXlN$JzP)3!2!4)D-_#u6EQdls?)SWLz8g>43lnu|V>b?Y z-fvIO=l{L!3f!&R<6|DpV0ZV&#DlwzhRbGA$EzeK!CHUzP;hOdTZFteXOZ85< z>r5%c`J%luwNCLhz)$vW(=Kzy*L~RdgLRwI!lv zygOfQA=9j;#c5mOz0Xsa8dnv;+0oYvJG&#YCr8^|?0qbOx9DpuoHfYt#SWOewaXk0 zKSZWNM_6CCC$Fk^H)>SRN({jB5u(Xi}4|ezW9h5)Nk#%l=h}FzAnKjw^EyOvf zk!mVTS@(0`5~UHk0VZ&&$C8$^xh8cC)ff|^sH(HQq>r0xi+%uPt&dez2kl(q_8ZRu zAhp_cdvS4$U>*KuOoXAuZmh(G;hnN^Z5}&C-27%SZIWjuF5a>gdl4 zj9lWe?h??(&yzZA%*lAq73CIEC7{O7%gp4@Op^6#b4WYcQZEQD^0ka!&a(OfC=M`O zHG1Mf=$dC-Es5*rJj=L3mv&k*@(pZ^cwswD+xRtw(%xj6@UjUb9@la!$0*!1McN;Z z1-Lt+`VH4t^mMl;hbTDb11=cOhU8@3$BJUC{s}%rTxn1iU)2HPSl+pAC8SfhMPf2_ znP$y=7o9cQ`+*c% zbzF*XHsW|T#``VswpayeF}{CvnZ-o?CkL~_z^GQMyMKwA>E)vb+jn8!-*F8tYRN9r zZfaycPzRdPOk6uHIH^AmRbe42^}MAs=Y7r~F-x)tbqf+#1c~Y*1&m~DXf=@3#a1intb!MK z7|b8MrZZI8yln|URv4BFmrI78`@v_^Qz@xS90j+k#aAJixn#vfDU_O;q$3C8w)c8}8n|2S z3vPMu5Le4ZciAU*g2A2@H+Pt%VgBkVMgl2^;s=4o{UtiHG$9;IN6K8fK9 z$!Ng&qfMpx)!9N^{&Xm*&! z1R_GC#61cn4vt6;dIx|o+u*YsQ$?{M%RTW_ab8S*S2=DhEia-SYPOhqfEeU^qM)Oa z<3rM+mK|(h0p;f5`M4cm&-LDa3(`A$V3uO$YNgx0k(IhT%44ht9_4r@nya28Zi@2` zyrnK!!14pdLdbe$^73rRJCp@VzxydU@{mb-vZYL=>hWN*L>x@;CyZ_Vxg4+csT+u6 zwSafodWknmCv@`Bz+k^DM!SxEG{3TAZn(2^Z&d{+?$(^3t8nP#MLzw~oO{$f@Exd` z#ryJSjw~RGuy^RcKatdD;kC6_r|bC!avKppGss%z5|g*9dF3wSV}~S1MgU-<*-2^K z?-Q2;P6x`+ptbbvWbb$(C8e9&z?OHs5+LF3Ekzp{)s+;TdPAZ?#`pu*!My#x$3BzC zbqYEEjv;s%0CIaK{HJEZx^dt)E1T9Z{p zCK?UK18((j(r%tzay3Ulb(AhMU+6=ZJXnJ{S_-Sd(Z6)ReDxA_G2!W>n|b4|8LyGU zDE8Yik;zRQ(>`roU}wg}#84aX+v4NOgnb5aCQMPwW(F)Ra@Z9U8nlZyr2szI6I%j% zRNTi}u!_HcKL~m>Ysn0A_LCcW(~mk2D6jDrxI5|LS&OHW#T17+3y_sZpITo}NI>j5 zcP=@aAE`UDJ7WWnAbhwYlcXqS;ewtNVn1;gd)H9k0emr#4&!xk#YkMDo8i!O5C}1Y z=$naEciKRtj*m?~-TctKccw4IzC<@&EAhb;DNnF(<|XDQ9xf5J4aGHr0!4JSuZF|b zr8ZngyQ~vRV`jG3n_9PvI__sc?l@^af?kM!yiDsk*3Z;=Bl}mb^N&3|2U6)O^4J_G?$!sR0{I&^S_rJ^92_eO zRmFUjvZ^^c$fXqVPOvmo*xzABhPl$OpxwskIyAD)`nkkweL^Xa;xsg{)BVLN#BOdb zD?h8j_c<*_0>B3GbRJw`)@k@M&#acy45?!^ewA8EHB}`hLIWg$*Pkx~1tO?MHAc7k z;J}uw_bC8#qURfw(T`TU%eKS05T&o1pOE$nBOWN#wX6t;H#Wj&GVpPHF$$A^>XB;rDcVKW(^I&9S!|hFnX=#DM;{ckojg)T-vmkWM zB6g!#lLBaHoHmgZV3qdvjP<&gFt=E5q`fEx&}K)2VP@&ooJ;~=j9g+X;u^EoT^Grx^5U2^j2@bU!9hhq-KW_Z#hW|js3#b{c6^UJ!a3@NaCI&QF3!EFi%1-jJM zWZ)R$w${MU;15@O^K14j3yJD&qDAU`ekHZhJK6Zolh&(=6_)6b;0mLZGV;nDGG@d; zRNh``8*wI~+r1thh+55OHlU}WN>}e+JX|GOQ#;MBMh52dQKdFR!N{{TAI?W#_z5T= zWaK^i^I%qe&{N>I!muF7-5VcG|E~X)md71J!d6Vsg0Dz^Bl26l=767uA1K( zhdbBELTv3tb(UtMIO+nDl2)zdJxf=PzQYmRL^_j0{!3+L0znou!l`UXyFS$d3?O*; z?da(;i%wxMKs+Os(|JS(iN%~jn^Q%@gjzwGi&sOt&mG_tg3IZ;$%>e~Wc~=T=8foX zu@_8X7Sr?KM+R>ozCBa&Vv)Emm7FKc@x15yHWpXb@y8XL#f z3VQzd2G#DhDe;W1xqu_9`2?R$LFWx+zgBLF>l>rxk>vQ!uXi_SyGoabnN*~L3zCI< zJ;pwNnu1I980*SbSRw!A1f^rZeed$yTHgu@3U+$QZ#xKjm{M7QW%uKyPi-wo>`OJK4H&s3t$;u;ttW+E*4$>VKvt)tb=m>6+6*(o& zTl;z4BX{X_#NgbA=7+cDjW9{Fm;4SSmREr|=z_cR8JN=5_1G^rfhpa&B#$e%RM;z> zcKOHPZ=M}kV~UmJn^DhgSYSB_xXsTw`O%jEQN%y3Dl==Hn3yQf9JvSf!YF{1KpS@u z6X#pxHcs7;ey5|oJ6AQ`xAK92k#3I4ltumZar_bLWRkqQGzFxk?oTH6qiO@pr@wLl z>d1KSJ1ZcXfbiN2p>6>o_KMh#5L^)fxDNuyh#l5@pevBi&Pvy8pqPr6t7mcUQQ-_z zPy?9h_cgJA^Ry#DG(0@W;U$9++qO#W@$pGSWO6ihNJz!X&(J0nzXpM>MosYcmRd$` zh8BE<8vYhhyV*gT&~oUUZP=dP^PKb$r~b zyIkOJU0*(PAbE406~_xX3Ss`yEwozxJ9VtP>~46=-4$EnsuOOQFg+$AQ5Y9eFKo!Q z18Dx36R@Zs2q28xica<}wA`rU#;!&!%8xm%U6lmgYuDp?Ak9Aw5GC$>`0wtw7KUw% zHw=1jnas3tVLTrQ?}{jaz_yD6=$yME6`~b@^X^hpGm{@ivjw@D$CfT#la1gDf35(d zu?Z{LA+GT+Gt)_jXviX+$>9ztdBdOypNsE}C4b)4LL-SeHm{R2-7w%Xblh{d$$Mo! z-6U545Nwz0WmBtk6b1QH3?4h&

6fAl5C7kh1{`j7jBxYryIx;k#+~pq2V8wMnPXkG$h@EhKwKFRO&sgK$0i;56}YC?&O#l zZoDr{MgxFA&xh1|Cvz24(*z`Q#z0wk;}EJ}_frP>!@TO;(ZWdg`c?b>mZQewoC1jM z_0Ixc>2>?v9R&$!*C^sx6Y+7s|_YK$E6wA?}y3aA2 zyJs2O3oo<-Qm02D(xY$Z_KZ#-JkD2AgYiBcf7T5z?AxWWI`}g;If>?(6{>t$KXC9FV*(068PL4C=TsEEi-jZr-sE22fyOTWBz_)~?4&9smW9 zQRu>?bD(Qpq_u&92}wzm1>XB&8E3etGqfyf%eJknNzyETTufAK7l?AD9(HyW!GG4O z%#{hQ`K)qNz;nsv^;G67{Sd-Gd5AWJHe7S8V!TRS?@Krk-Go<vYq30c7+ zR}sc=ngxeFdW}qaGC5gAqxp_H%tmY_+N1}`CelW-`#?pa8m&kud2v3|2eZb|L!kTR zE52ZL0~9|*8*g-<YCpM;5g1-VU{`o9ZvYIQ9Pzp6o znwX|MmhML-2?HPFhU`oLVM-tyO3j(CO#deLUdAPk2+_O_VYIA6f_lIgJ zoysdW^n$XeWkAwXN1c=j9gOK$7DAnzp&^6;$i1IbXJY`;Dvin=0F zG>xH$UpSJDmllY$Y7Nc8Mq)E|cudTSK=#k);`Oc9pDWKw9?8{4*KbRB^?PjLEZo7d5>FHFeK}`D zpA|A;c*0YiIhTmQp?x;q_?Sw8BH(h&(78JNsq~KD294{Ls}@-4Vl5_XStRmCTZ2(N zTH+VvhgNz44Tf#V_>LjVL6l#>>XhvjfH1Jzc7N&sO_3@R9(Y?{h!p+}gfRDsiI$y1 z4Ee=eZ3->a<{t``OBwraU1>AEps#;guN0=(rR`Z}J(IGGPwXuIbIy2jVgkg&4(EO* zd)V|j`l^JNF!=h+Pf*ptJuukTF|g>RAyf^awEgH4kAx^{d*y<4hw0OA>`}*Sa;$k> zvK2?(yzF9Ax^@h7sUgI#W_7lclptdn?V(jfmLeuuyM)bHEUW8)9(@_ zA)5wG6IHfw?;>AUKUd}ZVS$0Ja`6NIss(5}(A5&m*(w6iTi`R=wa9(QC@LNd_9=|g zc2^TqL~*ew4^D#Z;h6R^EInH;VC>7=HUzev+oK_syS%z89gh8UmCNuE(Dek}H*P`{ z--DRf7W3;i_?t(Yw9gTHF^6IoBaN9X?@WG}QfBB_Nh zfwtQ5&0v>3ifKgs(Gt@&?OWZ>N^tv#%`aaf+Zk1pl(=U9)HfwbeRr)7kmScTx*6HL zR>R$}SNMrs{uxlaH*I>mjvQRj28E4iYG_-AN7k&=EUf*60^k z?T@4P9;E9^uT2jG_Z&$`4XRsPqZp@d*PhL&fxJ}wJijXu(VJmQ`FG#)zH8<&EV8IQ zDA$$7dHduM35EQfi+f&PXDh=G>$Bf-ak5*Ld-QK_OqTkAz=Q?xdb(_<$g0=H(^mz9 zeQVJ1?io;v8wKG>f%(MJHk)r96s*vKj#lBcR>uN0!w}|rsDN|X%$fEZTKTr29 zZ*VXDG^l+b#1x@@BXIyIja8vqpsnT^E+~pwML_vNty?6#%<**${r-sxzCAu$st3jKDBj<&BF82Eu!+ zAhYU*j;6a;PW4e|;&CP#UpezNPt}69Ca4u!Tot#ju-kG98!y1(dL1c|q2-P)>O^^E}slmjcaOLTg%eCNW~a7iBhww*-3@P&Ai1{)^yAIDt9=)Y{j zE(dc$>dyCUePledhq7&V?N!V(aAiA9-EN%9QqNgmZTbl~ zobGOfKYWcHl%Wt}cr#oR$n{p0SiGP>VPm}1uV$P-zNt5baDHZst$FFo`{ys0K%SC; zZLBX{IthmsZhdwQuBnW;hS0N+URc5;HsG3Tizc8#Xa=M~hUQyZpCvS7^kWP8Kf)PP z@f&Qtd~spy2KCUwJ8n0h7aHrkkkXPg>-376sHe>=s=Y;DCd>pg0V@>x!hR``S*g#5CL9fpU}^*kQx(5@WmJ1`PE>=q9dA5q1q}Vp&O(UO zHd^rfaae`-y#ohsgW5CE7w5-UpPGGZFa6PnYc;(?Bmq63(W9Ygd$A1-DKOA4!<|Zw zjJkE_!U+ohsRat(JP6(1>W7D>1MH*N$@t(wO2M>e5P*K#)7}MY&2XI&_WAh{*hA)l zVy=)zTR+$ZQ^#J<3Lmk9+KM^gwih)8Jt52J6_Euk?a3iLS6A1}MPB51 z_-KU%>A7En3lpp+`etjKt%TCEXToCm*V$Z};f#da^Y9Uw1k#?9*u%`}Pml`RnJ7&5 z#R4S-WIn*&v1bbV=dbCCT4JgwN*J|30T!rdTdthW@6JIjCJ~iaS=zRE3Htla6uGpI z$AH|Q+cLsWh^(h{(?PwK)D)BfE4-fl`wAuZ;ypdx!Z0)th0sT2%OCbmP zeY)Pr z&>(nDgeI%~i6(Qm0q^Ds(Nd9*!(=`2MNwb0c3JDssgr`6rNOD|{oi6jx{QFpy7X3F zs%a>DxXV4_BS3CXIy8zrCXOkPbBGS+KJwod%S1Tg+d@&*;es`0tXH^kP>Mb2_mHyH z{`>Sd`G@z}TOO*{s_;#rZP;%lmAR}`NKhZ$hMw{Bq1{1t&%#AV1SqI-x?R#g!!{rw z2ZBkTgVKy=2Q?w>P%FDPyDBetr^C;U$t(v8FBd??aW5owE>wH;jJ&|tKqrFc1CGpE z-*%{{z3Hw5!(g#ePL> zUyMCN1gmXC*5zQ5Tw*%%1r|Wi>}H`ojoUh-arF?-Av@~FSrxi0qwo(6pAzQher0&Qm|v!q)cu7As8rEBr~sA|bJCfb;=QWsobT6!j_tR*Tc z78D-TalSod$oa#3_z06yh=XeYWyRESE1%o4LkcLv3PzwfcCp5Gd0=IDJS8!t!EmOE z$N&VI{w?FyX5EFM&qrEA{l!0YD$My?3AgxzV)od&%X_~Kf@;jnW#n>!s-TBq++Z(D z^G~4}!kN$<5_|gJmDnFHb6#z;bx$#__pW~#00Br+rC6}YPJPl8NQ(45$)aXt1X;?6 zCHth39(QNZ@^nKw-CR~t&IFm=Y_?0tUVep^=XPFK12U_d(6XA8JpKKuc1M5=#1m>qUr(A9XcZcoxyGGfTN z)6!N8ygyJTW=q0rGo8`-h{+~EqP4go!UlCmw?Ja$Du{JN2JUZcF3 z8LhnDO!Sk_0O2dX-(uuq{{ZSn5I^RW;9tmJfG#k5hj3hYNTqh!c1I^kEgzG(=nqF8 z3?c#VgDCEJOCAkd_kbJ2Z;zZRa|Ym3+kVEUdw=v zewbtmD4Rw=X1{LZbz@RY^w?y~DAOrP0pv45x*JqPVhAhcIVy@I;0SRh3fv`y zNG>@j1ujO9`Zs(`wZPIpGtXAN2I1iz5UPZd1I;B_*yB@o&IP~D=ufh6(KBs7a#izz zHN~nF4c%|IIB&T%4h5C}{&L1f!6i;2ey$>t|CCFqMXFZZL0N$L;OrZU9d6Z zs6EJCMR;ZC$S<>GXSNSUk+HEf_eZe8Xc+R?eJBDguEWgSEV>*limd( z+_#7|m^Wzyp~``XYl}coE$RCz!McMAbw~cw zOPB%&w=n7ES&&sXs<|vN-}h6?S1rU0LshXrsnkw)va=Z;9t@^0%4vQHquOS)Rsy=x zFh&o>EP+kMCVRk=#;f#)jKn^tKV)+O9!?p4y}i;f8M>8MFz{wW)G!EsQ7EDr*hAO_s& z@2tJ3vC=6^2C}fp2p0i-{_;`0bIRt}GFRs99-Lg=V@j}jA}3p_YMu&U$~yrfwkqug zf-)cr+%9vxUS}Pgu48dnr|=mKVEIA72fK7OBElwid{zLs0)(Zh=6p5Al)F+ z3_bMFJU0!=e)m{Pf+$>24c@Y!^jncmOCX?O*>c<4Uw<23ItmOAKQl%WKL;7w3 zJr6({JYi!Flf&zO#01|zT4T}$P&8Z3UE#*@B`nU|3=jAI^SBZ)>Z%2oC<5;Y+R4SQ)1jHG1n^#Cw-go2(w%rjsXq<(=4(+A zr;6&b+hS+LeNb@_LV{N`V}PfMn18dO;dWODN+aC8=k*X=D{da7J-^8ZlCms-XiC$$ zP8XSE@>Wy?F2xJ=tBi_J?kv8U&YluqW}1a?e2!KC-=8PJ)mP$p^i0aYlYm&+M7ieO zyMxW3#?1Bhu@du{XVUI8N95cw_Xpk&fUCSgTn2!O_xu!SjKY=rj50ZwxQSDDYJMc< zLV3ga{0DI6E(2Rrhf}8$LG|vtbn+#Idfhw+$dqcB>1rT_SlcXfS+`He7?5O(4|D|> z&|(CqM)i!lU%%tPX+oSv(elog)tB>MDyS{Eur>nPnhh)?@xeY5Q-Cw(E)t^|ODMG* zDxU$&QbzI@CfNH?>1BJ zRcEJc)%u&n_iUGs!n|UcA<f<-x;ipHd&`gSKsW4(^&{(mt*&foYrgh$O@ps zMcLST=HZGE2)|dFw~$c07-}Hf^QpjGa;L2F!!V&UHwB0iFH33dMjGCpSnjcjav6yG z7@Onep}p_kZDtlGYb%X?PT?Ugw)$C1P1&M2Pz825%#u%xEtG)0Gq-^5$Z+#yyw-0_ z6e!%vB$}YdJQzA->}`hJbKCll&UI!^goXF{4vtvNj_&FUdL%*ZKI@2?$LnLS4clZu zY-g1X_Cb20EoN>MHzMkqi>ch$3Dn1rLKIU^gqwW#1EmIZCM7B;FQBk?VW;0O+w%9D|q^sm3L1L?QJ}WfyDC*(6;{iW4p3$Jh35-u@&e@wqnSG zy0_ocJKsU9BiawhnKH!g{w;D{B2bLX&eg>=1c@sl^ypCcSb&_6G4+S_sEx5xcw3^s zAyM&S2;C#Q(Vv-4Xr^3jOD^!}eXV00dfMT@`}Z9uOkPi(-_SxoO$ex=T{Z`4?oJPP zXHtb_r2x&_q6|9?*z$mH(W*R7$522$*}!)WpS+&5QWv1N^`;7)Yy!*aVo(|h32U^Bh)H4O5$8XL zU(}|Mx`Q0*X=+3#6uPqXJPdB6sTrqH+`vW+YO&{V9R~+Qi-PU#4C8phWDmJ7oUD9$MU>(!W!Y%ZD_0D zisyJg0vVc`S@Y#RnlpTRhbit(zy6gKtO$ddCXyZgueVA1L*L5Y_wX2-H7^1Bmt6nT zBE?00otX=75>~Ce=lfH3ceS3T(20q?C)TG(YIuS;MDGWYa7!hrS&Ic)zuNb`TG45j zZ6c(_u6~{a{6~m!Q_`lA^Ppef_f}Ay+K_yQpxt=%cJn~XK z7PH5<#qt%1geRz1@zIGo#m_7pP;X`5;Q=aK*VQ4e^HXJm#-7mEO)Isi@b_#X@A+r5 z0IZVv{PVNcoXZR$DA$^jp8Fg{;9Op|0+EE(vGdzQC5cdX>}W)>NI}D`^}lw4UY!yU<0~ayapU5>3x#%{}R_06D}IU!V+N z(x*)!cirwLi8g`EJBh*n&dCX&x$1?pElM_?yiotqJAb?igb!>g76&%yYQUUN@+}Id z?(jq*P4y*hK#p}o^})U`GINtUO1Ke7*EZt%xOR5Yl&RgS-^C@8-Y0K`8<_k z*E~qpbyFe_ft)i4Xbz*t!2){mD354+wgsr)UG!vUNYJvO>77}$o?o@`)@}cnK>*%s z%Jh(!7aj%t%E*!sw5>GzsjG zt&8gZ?xdVJ<9HVou)E$j{sx7{9rb?!x9=UoYpV zQ|F^#jD}PK^&X8l<$2-M3xyUm#z4WK>4xL87kkXCQ-W`(%ZzA%)0*`ziuHy%-d-?1 zah+Df0E>jjyB@#C-qj|V2>d7UJ7B5fAr9}l%gBFzNbFkC2=mJ9Cw3POn|% z+dhiM z;3D$#rB|n)$^Sh0j;K8sJZy%sj^dF3%0G?)*cVSn^G)q99O@#QQ;_EgT(+xsSoR~&&wD_TPeav@t`hf}%H6ZByS zG#VuxMi+`#Z(L&R&!B~b|W)xNZA+hJv>D%WWv2YVQbxP(s9H>UH4 z0Or;C2g@tV$x><)`|7tEJ)~-!l@F@Kju;h*#7&!ubne75Q}hK8yxHH&^2o74&5fdV zww5B+oHp};8a&RKgtbJ>iqgqOtHkq?RsnS(#s9sqZ-kFcv*_8x9?5vjSIhtkHKt+I z^v8*CHVQq~t;?0Cz|*+3x6z$!BDEm14I+hhT`e^!BY6zLhvI?!skLf3-W;Lv%w1=E zY}yUR*I>%24l^+c(gQ(TNd%N08+-}hQBsT&a^ z7GSV79A6W&96OX1c1J|-dY#OuLr-@%p6rVHE*-HY@*0WmZfNE;*n^IT&LaEgF4$y9 z&Qf39KXhBuik?+Gu63QCHW0EI*cjHNCh9q=)-Ef6)q&$h}MJVT;ME)p(362QGap^a+DNna%R~htvb>Jl$;2 z!uX`xK$>IH9TgST(thGLQM8UkB%B*u{MFt!^_NIdHkIsKgMlv;YGs>c$CPl?nN5E$ zp-9eVq4(BV&6(rlkfuMG5A}ienbMZG>%k)Z2gPp&!@=3mI3#K6L7}x1J z(#uyB^Pmj2n}}(SFz`<^OMkz+@vxjD<(v&1Vk$Di6I(Evtr6Vn94ie*>OL9qbT$0v zjnxLY`yCbWFsDthNX)FJ9yLUq-o4m+FyidmTv`vmsGu!)IgK z@%jS->3+=%r)xGfV}<(PrUoQZvV?@Gp?8{)k5aSkbjr4L*jYpE{gh0HMYu3`7Fs<9 zYh(-n0FGHph>3|QH=gp3i2eL{3^&a{zGCnnK8?_Y^bI06I;I%eP zvCBO?YADBYB;TjfAEDxTugafVVO~@$l;++!8l#k7I>#)b! z^QyjYZ}%p3cFJuHQhXa%HB0GLfa>d?j|)W{*H5)fJ-13td~O*)4;aDAywXLzP&*hu z_A{?T|G<1`Vj*boc7wg+BwVM6oG;v7=CH?HedvZxKE9NU_;yWXul$4Z86(x7$ z?wBm?4I-hl3GEx3V4TqAR240;GMu~(e-~DCT{vow^QPdcx~q?SVU1^ z5rszGQT52{>CN=*E)h$ndOUf@6$26_%aP)D`{d1!pos{Kc;i@l>KmDvp)RPfbneY^ zx}%yTqy?g(g^adQsVr{GawcCyqhO4&)|F6)pQ+S+nfEe*@0FJebQUfb%aA4S1aqMs zs<+F#I8mivZmu0=a~^GSiD;bWUJ+u|D7=~bG|G7+{k02)*MwCK&GBWA^3G*XV$;C5 zN3+)>hy5o-E1N&zPjPj*MO%Y8R8>_IfVWa(e8*J!g2$Lm^W%#W8|*`=1k)Xl5LVdZ_zCCw3-x+3gF>6`6 ztX;B`4biu9fRnU-p9>)RAvT<)2g#*ictX+eqUMnY?Qs~3P8vZmbsr0yD951yUx>z| z|Eo^IS=SW3-BdS-6T05cTAa0)_TDr;tUP9F8`IIz(b~HMPtbw#nuA!py+t+evWZJ< z*(XZpKFgoQ`jMI+QYahF!DA4r#9CZTWN==J)|qr1m7n_{cvE6;F=U|xpv7=MqaTao zY82iZQld~eU(KvovDtaiv?Hpl_w=+5OS|0T-rINYmX11L3rUYiL`~q8_r3O zIbOzQRr@y2<1~66<)7Otu-)R+&!n%CxYUdzfRQkYMNl>a$L4iWWCP^#wxjdhMNKH} zm5WCWlH$aa{C1FF`-X{>>d0!hf)JguC=iEv!MJ_?`K9%(Pg*9hmB$^^4pI(YA5Po~ zPWKk8ocX|!DnTY^>8)QQO}tzWMgvI)#JvU%tq2AQs|^K_1C*pM;_gxTpBerveA!R1 zXg_dh%(6wi(RO$&)~c1>sC6&YVv5FFP|ur2ehXLeZK3*W=Ms{TdqHkCnm4N4Ny-|N zyNO2_BU4foA5MjgEu)@yqvBtS0w*E;tZCA7h!hE|}g6DWF-C5M)aPpAi zbf;jOoq{j!Z|t(SpYGd<>$1U~lCrf^E5CzR zFd-I!s9B-P$JBh%T|7wMzB>LD@mflrO_5&BJEOcq!^1uQx4`gZI+U{@VU?2Woc_@g z-qFMcNMZtbuKo7;p#|dM`MK5felK3R(7}$VUfHJt{W|dh-;3KO_Vo$Hj19?lB~L)i zqw?#XAgpnJM8c-kb9iVy=FqE1+}OD~|7yI(1&?y!r!&k=sv1#y|7m>q{aghhekOZU zpW#Zsa4xm}g^32~XV08RUU3aC%}IG~e~Yx8NJ-dAh})`l?7DtTngD;Qk8c!xG-<~# zTe^2TS|IUPjF1PfoU_wS|aP2`*Z3a z-6lU2d}@GuRojp5*`ALT!4me1Yu}3_`xX3XE+2`}s;TY`&<>o=*GOXjzJw-`do#Y8+kEzl-e>g zR|g9P{FKEa=+4rfsH^X0&_P(QJfNeiaq8WFWH%9>w_V30LtA;`Z$~7SqSM}}aQO1D z<%0^^RAcb2HRJi%W4N6d+_&SpcRU)PJ*Bix^hixg)FBYakiTX0*w0mua2bO5y9<_T zsqZcpe|s@qtvVra?->9OSOM=rBymQ+&S#%ye}M)XJjelvNdG#*z0PB6;mv*Iu=`5g zZXkRF-{OA7r@idQ@q>sjVW$hP#yo8g_-x?0=Lw1sQ}@Y`@BpOoO%;x?|1gR@kx&BBEswFm1~GZBrMqZVRWonm}G?T zPtkZhP8a*W5?g9oG`QTk=(%5j<9l>j;CsA$Wo00-?M-zBSohBW zKKWq-&g-q%mK@XX7^zkB0Mj(m?!G+~UsCKBY2S$UYsc}9l5D_TYt3F>#pWdMXIf0R zSP?MzYTl-b9{OBcuWqd`3R&ibmQ$x!Yia#%javUy6uA66MXPvBbJQf_M0UkN0>!Ni zLp3e*^w`r#!7$-CWX$hskA%~zYLB~y_P_Rh49+`;daa751%qvpod~Y`I%rr49G(h* zXv(uLVqor!d*74ouZ$6}kZM%-qyi#Ea6f88(7pLo!IKRnBBj#%sN>plUE9fx;cc1p zr@;P)-%BiJ+6b*@mko#S@52^h(z?l1zE`toypRE$8KQe9Bde1ep5lJTW{v00SOoA( zbnJXe!li^B7l+{>Qah2Mim}~tTNvNWI6AdjTv_F#*l&Is7LD8jg^j(8n~%t!~7TivGQ#Q+QjKuo*H+@=1En} zQcTLn;tx-nZ_A3ETU;}#&NVKbNqOFWS9Pk7Cx%HL1n z{Sce0o>5PydUjd_bRX1QIS4Kj6rWsp^E=2Ho>vy;*WHfcP_9UF1N&Qe@G90NH^OI_ zNz@qGg|ah?o^72yvKbWzA9q*bpjKmSt$1SO?+-ne@L(1@JA!Y)Y0UxLHmjSmH7zkN z-x!Wo>#s=xxY8xwhD28JWx3f#oZ{LftNQ1=aW)$H`fTh2TY%hO@>b|tRW<5b2(DrP zxmAT(GXYq_*8`23WA7*U2srZZSY2IV9Rwfio`{Eaf>%O;)Ab}8Amqb?e?owO+YuyT zjy?EQyT`Q+>H}z#Ij{hRGPgeJI?HL@S{N$>`5BjlH(6D<4};bz(WAbX6$2v(g<#k1 z$PJ!C5%v@KmRxeU<3HG@J0qc&Q_iN5%EFNfO9kqF$ z<6X#|gWrH2MY8r8rQyoLFZv~afo!&@c~iEr$(T*UXwXc6d$p7jKo)^w`Bt-uOs@lk zsz8sp4`TRoH+f*MEx0(3x=GwkKahj8@BON3j*!(LL&~GoD9|wd0{xF?3d&%HKTUn5 zkSFWIHXOQuainqFwZD>t#bh>=N4j(0QSd|As0sefFbgm_X!}!zy+xs7wf3cel^;kr zkOLR;43Gn8P%ga>WipbYO6G5mjwz4bD~V;+`UsZuXpUmXwh`NnsL)K17BK_%!=Na3 zjMy2{o%(HT`rDk%c4xc|pU}yTv{deg;4Pil&p+p)D7TjvHW2fOCa4JrJK7blJju8C zzuJr`$#ul!7{^-wu$fLl(*5O1nNMRH{g2 znF~P6i%T&}j^9gGxJ%39deO47v91yO3V1rkWb3k{9z>|LSJGjzA zR570eno2KRG@MgrdjOtJ4;c;w+L<80A5`~*pr?z(PYbIdFv^QO8A})I9kEp=_VgYD z!N@k;)uO6_3^w%@dcCWw>*=#+Z$y(@EV?@!a%K>2Eo+#J&#N~Z-fjW6Shm#!7Lbi5 zr=m#F$XBZu&JeuMOEYy8ARSTg+z`SDCFA;5NZcehu!sws*GJNlF`LXSpDpvx7h_wW zppQg9X@s9~0@}d8{}NMnhNB9-ruu6-W#`L|m0EJ-I<6!#P7c(wgiC@fod*7oH*5lp8QK8M2-w{&+=wqH{#3m5|3t6`9Uxt zupmer?Lo~)?{Z_w_e9RgYLCZs$cChb|5~ zE=^yA%IP;)?Vr{3cjxdMNxaBisCUv;@NPb`9DcBM3G!_zccZSH zo$(qIkt$-5Xkaqfj(ZdF&ud=x1*ox5eIENPgA^M;0AO%(R(4#rDRG)5Fud&{wpZ;c zy%)7-KeJ9kNa^_W<-Bd|dWGk~Rxx`D2Ypm@w9CQdssYG%Er4sr09G(uYf|MX9UT*r ze;an+$wc%+t%|~Vt2a)HtPwYXVDJy=%2M9AA5W$pd|S}|yY0WHCp)Ovhw~hEMf67a zy&yVeL9s$v`_l!S`lBU3?IVLGa|T4yh3DjM33fk$h3IRQi`r3LzEx&uIv;ibP(M4) zzZJn&%5fAnn)^_GJ|HF-#gTmbcmjc_Y1-}58NkjLk*D=IoAd2rB5?yUz-R*H)y^OZ zf6NTvM@2=97(sNoE|}5hXztc0J~CoJsLTcFV)kR>xJga;Cr^j-(d9sJRP}<1E}4iK_?jtoV1318di~ z-qcE&js93AE}N_re4B!zD|`#0kbJ-yF%4x9@z}=5n0k)1oXs_P+f<4z2X2q5Kh`?5Dz6Y5b-}+#9)8UXo+n?YIgKSzAkucTULxY4#)QSz&?Q zw#M|}jj=BZbxk7i1Fbn>D`+PElWrlS42}O?G-tiIQV1|oEMN*>h$1|46}{slV4iQN zr=o{f>MqR3pj`#PG_)H%AJ^i95nj9CUvTL7^jW9O! z_;87}A7$HNeAoQk@}U56byq7F%ly$Gq2R+XakGGHk`{(uq{vcdJ{7)TKY4SPOVzpW zRQ(lKJojMO{}U+xULN?Bvy!Gn=ixXPz>zmbAWhY^o_RZtLgl7IS(MZm$oftm8U8+aax%i#0CnKr<2XnaTSTp5278^ikqz)L5N=jb;$dt` z2#C76Q+G@R!+oe23k!=Ca)aNt9Z(mPNn9%!6(&BaZ#pa;bod!e1^s2=G@^Sye<*aI zd8cWp^a|g7n9^l}1CxJBk=-f>vGdt$EjV|@5&!9{F)vrw6_h)8T1E5sU9M~!%EQhL zKzu%n+qa)8O(di3pXo{3BVpARO~w<6sx&(loldFdX+3q<^WNJ@Rx3^MKqke$^S7s3 zOs9-DYZ~S;qd=y6l(L6v{e-5UQjeug35@KQHKoVR^N1osbtrt_HwoXlL;16~50IcB zX(oi%fz-i60tt=VX9NlIOgzmZc=ePToQB5Mz!Qmi^$ed%Kf~uHx5RMm$~53Gyft`T zwzJg@7n@^`+up#r?CgifriN(ph(xyR-vQ_M46=|nIFBQqt9p1m7iWIXn}nyI^!@eN zEJR^q55sn*Gz5{SXbjdL?`f;RFgS3pEoL61>ANQ)FqK?g+YcqN@)|Zjjlf{-U1U#? z_R~m$ls}MZ_MBf2bGArNWP-ekQ*VCrrr-Jg>XZRG`MYN@D@Ie#P7XfNjddO>=;pQr4m+7LF5PCEjhfDsAO5 z)Yo`{Y&;BD=TPB52sr2K{%Upicj>X2HiM=ez6 z2qSlx+LYT?;)c-7E-xZnuu|eWv2|<#Pa=tCnmEXDL@&!lEq1*U1wh~r-t>BrY5K^* z07{2`*=TW^^!GYw@4&gf0LG~=gpx(GUa*9uU~p-!(slJ`a_#lx*9-E3bJRa_O^Rq+ zfw$Tm{>&{(5m}b@18Wiyu%~^nK_H5$8$~kjmw0ex;=$ugYSBl8L z0GqBh$p921<@#oS9{aCFWra$)8q>L?>kGx5Fk$D8{o;|1GaeTvq>P=ppTdmbNB9}; ze)&hh{dVWtLFdvm9JJA*F(>lZyXQ7agP2G2@izvJW!}PjqB}FN|FLSV(kHQFkB7u@ z1h0*!H97shCqCZ4y>ssDxn(lu0e0oG3+b<3Wj|^C_uS==p{P+;sjzK{?uGrjm+D8O zf45W(Ul1JhZ2-y}ir^U5-`CCmm+MBT-_E-D)8xM{qYMh8`}M8ro-ah%{_lvZ?;OnT z!*H4-o0Blges_`A@lGf0yS^G~XN&el*I5{7Cu|Nh)i{Hb?>dKxL`}^v@ z|7Csg61xKZjh@6SE=-v6CI{oTX-PoJ>s z34O1XcjqEPnt6bTVu)%eVbtvn9{4~^viT-yAv3B)hB zI;TE|nPE@V@f|ZOup?l`sQb4g&c@LG=WOF=5jD3;j!_-Ku8CfIcjZ*Jo|wKfy)1LTb$n| zssFfheufApIo_jQBh>rmhUOQBGSyFh_dMUQ^j}R-$BTT4;iEuw&V*fzIfiA^`ge12 zbW8^^|8u;+&zH(Lb4G?lLR=|Gd`rBPSFiur4&Eb=f7&5^b;ZU20NcC(|Q_y3H-&c7yNIq&~F!4F#gG&cLfiAaP(>FHVf zz^vbE7}U|pH=kL%(i1v~%)dQrewm_;nHzb>UZj#KN2KxWi#U*Z;>J8vg`QY^OSd{^ zYD8jzdeL3OyO58Su0sartZiP&Kc1vQPHAMLvNQ9scen@nf{`9r%2;%Pe>uMX)2kul zKfO}D{6t(%$KbcPzAXQu!54DFi+=f4ML}GN`)Fx~iEOt_)5VV4;7$7FERCK^qtR0T zpz!-F7qu9CuZZqLRBx(aS6?T`T5?^^?`n3O8`u>7W0OAr8j9EQ*XC5`h%$7EI(qSn zaK*1_G5pxkX3|go zyP4tN{M*dBX&(lRg)H?pQ0kP6#b|C36EH_*J0_g=nOR(sFjJ>&Ik@x+5n6MN)*3T|_qWB<4Xl&@M2M z4ObU`nn=BOK7k>7`_Z}5-!`T}9LSmW)g5<>s_TLLB5 zO4e99?%V-Eu{l7ExGA75h5DDo*hDrT+(pgi-2vZn)9?Xg-hFB?(D!s#2ZONj%)Osd zoOkYN)RVQe4KBk45w2{9X=yt{>3e}-Er>n{Km;lYt=5r{V^8DR5?C<5?%Qal@DV6q z`+*iqV25T+Pu7~7YS!k3kT}nD+#hS71pN` z^!9J%MT$T@N8|GtK6fN2ujBZaimmx`nOXm^lB^j|DY~B-WQa~usRb;(xdBwei+NTP zTW-fDPuj020`{tB06GJcQPrNo_Qe1&%;E4XK#&y=Jx2eo5Xe>DJ8c}}E4YALUBpRpoBoTsed&^e_89`+?r z)?@_fZH9@Z#Fv+q37}AdM=f=31OQ!7cn0!ARMf&i%M(tk4N}_HC+#?R>f}#x{~7p5 zykXeI=Faw{gVchU1QuaI0|D=S1UAPT#WI-D3oiTK1q=}=66k>)`oQd8;pz_l7-onM zbqA&vR%*anAib(!{god$_V>1Sm9BCB0tqar91MDF2W&j-G2FW{lfj?Dt=$Mv`-8I(C(TsSE7s+e#e;wKbj)|XtYXRsX z__26_yUjrvub2(KV7@`r{8^*qMSK6q5S}nxBltu4-r@ddRQc^?qSQ_Q74m*B&g=*O zf>6KTpeLdDr#JZXMtEOpA!k)wo#;^-? z7NV*nJh`2KUypr}+CliApZoK(`Vtrk7Fj%Oi7V8`5(-%1eMYb-N#YDdn$8Ha+CEjR zDl5<@&>+C6nN4yJ+WQZn_p3v%_0e%N|EEwB*t4h@DocJeD_nuye(c;p@ZnqW|^k5%z-P^PyWmMdphdq_`Zn?#cagAyb_18>yuiH@dGyrODs@n$#(bE z<7SKIf{%p%wF!v;cLkLbR^R_?UmD}s)Cr2e<8`&T%2J}85u+G89Rr3DQbVpoP)$^Q z^=*GHf_#qp9t$zWKTH!n68VEAo|>v3G%=4~J2uLea;72qzmN5VIRsb)Rt4I5rI_Gw zQ+ZN&(te7ThOIYKG!uB$$NiTPBw#rR`3CL3m2$jWA=X%pQ=i!lGa0;f*HDueh&hJ1K(cY|CtmL z9CW{iROrH7bONg{@PDTdzlS=Ty#lN8ia6HYl?>EJ$@8y_f4(O);g^SdlBq!o&;5Yx z|MUIA81#tQK2V*|25d39*u!Fk-4-f+Q}6SmlGx8G1@?46vvb>3;n%2ye#URMYc^ZD zDDxQ!U<)*8{Zk%=uqJ_(oZV6^q)j#ejWKxqt0~g0pUuLwPvFHDVh%)Tm9CHzUGi;y zRdiV#6#i{(rSA$jDDLy8egYMaK_|BW&+U)TfznNEm7L0B66YL=LY5IvcMnVN4~IvH zUOw`s@>#!pHkAjWXQG%1tAy_%#Xd9{=y#i<%I$38OpLqZ;2$`}R)?x2f@%GD0Tuce zL-Mbd;C*18!yMC0i*3P(IUr@tp{D&&iwzVqBbU#5?g2gzrkwm8%_E=okyS)gS^ z?LR_%FWMho9Q2WGj;F;G>;giN8@W%MczGJE{zdn_OE65X=^wMW>>%!%>|iE z;ZS1-;2E60n>?gMj8P#cwV0sDr1C||4$*;7Xv~pv zvu~b+>aMVrrcxiX-f z?DJgN@kSNA3eglwZy)np3PnYT)-ANq<9q*F%|4A3_&jYqV{X`vm8{^G~ z(+5{!SY#_Yz*9KqQGX?TLFRe`)crsIb=_&&cZg+kwt{Vy*$S|lvJgmDB`lt{0kXTm zP`&nzOsaG-UR}KxdC0WgxFUL~y3XNN@XnF?`JjMu=Mq64iYzvUBwQml1JY=LT-eXDN76sY5EXcl)4>Q|Uk z1MMr^yAjwo+*@JzCx=2JcUoS@w8HeHMhy)u*g<;pk;7C7KXn~iV6!e@uhjN=l!aO? zPOr}WR+BrQi~o5@etLc1SoG`^yr?3*@thZ}MFg^?YjbQW&kx5%4B%E;i^m4gAmw(6 z^rFI-eYMkv2R>fi&+8sXD-19&G2L#m=L?}+kR2zNxv1r1KQZA4DQC;Hfq(bN;ggT< z$aX4^Ged8{l%mx&l_(&3x0voUx;UKbC4@6J?B4=<{gYhiLr$@Uq6K{&?7go{0&*Ry%*tQayEg@oFq6{3EtX$SsEb zi|JW(ZNQjgC`V4M{%M!)0Et?qZ&62fcJ|Ix1Z-zhitcpzycnDa83Srj&s^6MKJ=2P zrAx;N=%Y z&W5$gL}drraSY;}+^U8Sa1bRtvA(}`#n8-f4LFP0uR65GbXe7PvYURItPiV)G znPv6!GxG9Tx8c@jGs4xE5=;AFBbF4=GSHI@f%jT$-?@agtIa1CPK72T#jd6|9OH9|`^pURxCX4dEl7H&3UVu(oL7EsUitohZIZL` zl151k6$-`yUJNte>-a(eLJysj6jebSs&(1`YAQ87`N4pVtEhhQIoO?WZ=%Z=q z2pEeG(E(Me(I!DJrwQMC)AlFeFWe@Upu9+H8tvosE zxpp8tf1uJH8-rc3E?~YyS3CrivCbNg>Z*WPxyEgpEoHXh`J2qk2~0#g({dhzKdSAO zfWckYcU0#zl?=o8?}s%|ysG*f4DhNs;I zq+3A9{NHG4&EL6pGL=4m?lkmA>RD3MOH0%FFZB6ewXvxn?HUzyflAp$!$@Qrv>4L@ zQ)BO820cVtFFm?{sjrxn86eFqIP)W@Bkb#f zw^{kDM|O9zc*~1*8ho2pV(-wPH}Y`ArzI85i2>{L5amhh>@>z?M3aW0DYpY^ngyLT z1?z5BV_Lrco0(H>bbNKY%6V#DXJXfT(k50jMtDi->ampb_ z1~YH^PPTiltxfVX*%C6p&+Y|gWAfdrqm;*9ul8uZO5zC+;9$w2aVCin9;Qj4iSxKb z;tw3-;{Tw5vi;DM5q|O1(ezI&2MpzCC%8D6fL9gZ^dkJh2g!|*lILPo8{iRsaP-Iu zedXN$2=2!oKlA7fNAfLRG1TH%`osA?i+!GK#g*yZ?>d4kT9^j`~=U6|SoxbboJcVyHV!gp``X3TE z+ZLTwzc$cNg*j5-))TzLTER^MWZ!g87g727LQy$D_648}Xyzpj5Z~?6&F5dy&`xS< z<*7$r41OJn{AK^(&o3J17*Vp{m<>vJfqe9XSvpXVr72tS%0VFWvm0-Arj$oUDvkw@ z)H$h~w9w5ge!l+`U7;V@XN%`FruvnpXM$>vNMK44eFarDg(r^eH8sxPp${U2uG5fE zxj<0u5J<)&kYo3LJCQZSaKv)t*zx>?Ef;miyk;WM-C#OaGb$T{fx)hCkQ8`v3<&+} z?zp}Xuq{hS>ilL$$}P#ekn_C@sjQO=q}E6UpTkIGGOc$=XD6!E18(FUj&~kV+(i?z z88m*(Tv4nMI%#9a!BJ6=`rlOoROq zYF3yT@5E8ArWGaqdUa$Uu2?b)9E%8yDvv_~ihVXO>-O?sy6R@O z6C|2lW>w-J+_&O?H^hsLzDBU?TNpS>2co3FTTdT?ezbLf@NTD7K(3K))Z={iw(VHc zL;5kMM2%K4CMKbRgCUHJZ+>x0=a5;;X1*rj*rQ&0lpHT>*9;_FX}AFM7&D;l=Tvc% zx}EKzgPn@xt&IEAms9dCi1eZY-k-IKQy1&&QzM@>HiA?!4ZM)A^PG3rg3bC}w=uyxH{(dBM}$ONHszl9y(FGzy-}MHNPG-fTlZDIUYpHO2xnDK`?LB)iv2 zA8k{;y+EHF&u|mt(HGS_mQ6)IQOKz2grz2kzLK+c6m?WN>rfiTpl!o>I~#@A`l9vX zhHbetrd2>~(nAX+egFCV6xZg;nl*o@c23M#ty}WNdeYQ>;dP|i?K@kG^HMJTB@*55 z)<#y|S6Ghkk3G{jN6YO0NbHZ@Z?fel; zi;rhHxvjhxO^?!T_6?&)M*A{#Z92ck3c%gd2s|pG&$(EG6)WW+*G(sRAT-Ln++DBo zeJyb?R9>Boy|rWwF_N-xAOE_(p=%Sq z!h2cPW5=5nPx>3qDs8LVDwl}~)Ojw$cur40)|p?74-~vhcmC#3x~mD}VkQ|J)Q6fI zic_A#6v$E1=KU#=klXEfdgnw|Q$>E09;*pCK7|Rfnut^qt&P;mtw}O!GK{2B#XXdN zZYIAuea-zYFGzbl>m76_2f5Lc(Rdy`oob50>2*jmEv7$?>b3_Ntp+ zEmy1`k+?V>m7BFN`$P?4S3r_NIzOKUb&bU{-yQwfT`6T@0Uv5tg~#~;stK@GtCc*B zf}azX1zY6owRI?O{k}@%kKX>U#A%CGwbfSJcoc zi!=p1m6Q@HfN`9{<AbW?b|(g(d9pY0 z;od@YL^f=qW2pnCLwAf?&h1U(D_DJjF*sfrw*d zZA6sL=E6Ac-5gZm6j|(~`g&+xa~kThKhcRIrN$%mX=>Wj@;adPP^ZxGK`QR|u%Qxw z)q&OdzH59aYZ$R<;=KM?1Z_iM;n*1OCkE*Uek{~FLHgxNA4kc^C0#`iB=a?i>Fa~O z^$Fe4yDNEWm#7gnBd1E4D3VYj%pX1J(J3kIPU{<5dBadQ-mMe*2u6y8rEm0fVPK); z9ADhV-a9YoFW{feIad|h%7l@AxN2#cB~Ftz1$A-SzR+vh^qLzII{MNxY#%}--4WE* zAJBy4sY0$Su$uG~eU;-xwZ5_%gNC3RJ<5i+EhZZN6+R0JZ8KJjF^ zx;KGG%tZX0o|c$4=^K|s^5X%~xUOi%-a2UeyR{m)^4RjS1+6?vgjW7It%sC^npC8? zX-EAGxi`*gl3MH9LsE5Jc5GXWKn~|oc22wwk4;gTk*2oI%$M4qwQCg%pVuaAUc0VO za{wDxi0Vxf6NzSgH?XSwY$?kKvGiW+GSvc4{KHM!dI1<8%zxuh_iUfec~|i`Zodi( zL$ON-VlTUlt<$vKMei3?uYUv{>5G9O`AQ8v9Hg3Qhn`Lt%;^qka_3%AGEsyH=Ns@g zY3zVAild{s6lf=BBCnNkMa^yK1Xr^CmKWdPxZ8_T@IcH7uSORMp))wT{}-ocJ}oUj0tr^U`b#jFmi@s8>-J zLb1g4p7&!VVoJ0x8VCazO~2zImdjsx^q-WBrel|&BJ)g9SxOxDfZG&yUym{wsAY%i zyZErOvVQJuK>ggP*{TgAki!j&a58xYCksa2yWQ^3TuX6pPE)9ywkie& z!N`NyoC$-x(x)Pix}dKau>xM6c%BTVTr6(!u9PW%?nCZ;xa~abrA77upE(EZ_e8e# zN30h;W_(9|}*Iv=t=t30d*RaVKh7tkOSZn-nx@!i(#Q4#k48f)M66_j*&hy|SnaQ5L*Iwma?^?`s?OXpA zvl-2@N3F-`ETyX0Jodur)H>TB;`Z$i(-q)UbK?IpfV={NeG~-OD=?ac;sxB@cH<6tM@@ z4EM%2mgO7A*za5>2#1J>LKRM#4*#9{F)J-OF?yzP<1sPO98IjnQv_+0c%p?tu@lkL zpSAp+YMl>UD}3(HmD;*UiO&RXiQo;I^z|-n8I^m%-Isr>pZx^B2g|jL!(69}ZJ&YO z$P0})YM+08dKXI7)>5L5#%oZ6zI*uR2x`k#lCZ&!T&@ygW!(daJhOh??>n3KxzXLZ zTy4ip=(T6lMAAn!8za+uvltxu<6BdmB(dLL_+6Iu<8A^a`G!cT)}f^Z2!a?&6p-k; z^0U+c?!MTACd`6x1Uw^%*4H>H8TH=oSU>zu*I$PPzlo%4U7;IA0)H6I@b z+ifP1sdOw4mLfwd97b8@jkdFW{4oqv(U;g-3F=3?RNljP7V@&GrFnc%vfh7f_M9O$ zzP92=egZ!-G-VXqmtT(a>Mb<3L5*E5=T(ygp1d{C$s8Hxu~O_xY;!8^bWb4ePd{1E z?9eO9&QQeo$4S);q{1&L^eS29YF2c40~ygL9apEmg%TnzN-Ioi3N6o`>}u6stF6mQ z?C4!hn$t?8R%UHwQL$jy%e-&%S+}=!8Pi zxRR&qVQbbEt=i*F>_`4*+jR-^=oN(4LtreG5@>Gd*z*9lI7R122nOyM5QKT`1CEH& z*<>kTDLiBi&tUsyxs@|pjT-}J{0oHoYv)TUw|4ODLrabZ(tPRG*6yJlrC;3W@LcgpV<*Z0E5~+N+RXQ(@&rdG_g++A2ljZ~ zu}R-r=G@^*1oaX6%{l$0#+}zQjup5fp}NPx%%y0ZamV)(L;?Fr;x;m?)hiXf&ALmq zCb0(YdnDIS6;gUVS)5GG&#=>%8GQgXQP@yK>>zyNEuL|xhOQ)AEI>FhwSGtlEo*Mh ztfU8XW${bCGt!lA&<$%v-DI~aE+Pmuu9H?|b8VD=ae6WBqVTX)w$Y2D(S^?z^I(_U zw!20v=2~4MFvs#KiDx22nCQgZa=S${rKlrKZ`XNesU{iNuLcLFzVEXi>J#Q5;_6#H zKI+vs>lG}W#YyGt80aSZJ_mk3YiQTufWZWdI-PcUE&v#8eTy!pq=IWzs>~uKFZ=%r za9)UQy#W)pop1|=P~Y3xc10{)u8|}XVCR+Mzc)|6nW>bxYl*7#y&@v%>o+RJZMZl8 z$ogHDatdO&s2bvdKVE!ZJzO_9-6C&U+fl9}+w?6BEo3*>E{>Zpb+I3p+~l5gT^Zw- zl9*i9_76}P~fJDHkWHs5E zaSr+}qq6wx@Sz@d_{`Yw=8xKnY`dLQeaF&*(yw#F7Tc(P)qZ-3?oY!SHlyYC&Edxa z3^ki_=jsoipObu{E9cMmtZoTqJ;(<$b+Q9_WZ4gWqJTZ`l|5FM)=gEby%=2#`IQHJ zhS)M)9RuGL8f*d~_4C=Da)Z*MEW750!JuTKu#4>i~2snyV0dcd9tM zAxc5!^3#L69S$j31$ z!Z_r5B1Vc%-~M@ngnw&Nkz{>?ci*UW+j7;o*>)Id&(EkctLP9_iK>RZJqZgIXkqnQ z84X#kH-2j%zqs?YTdTlSqT>7*k;p(kc5h6<*$0u` z_L+((TBZVmZ_P-1AO<2e^xVgd?*`dzBwZHb_a{;>`7TL?xMIHC&ve0?I^?YJWcQzrr3b|FlyqlX9e{t~+H%1j*5D4K;9!rb9!QxtyUyyfbtM(msbxp3 zB+|P_YDo%Y70wP8(TaI#(fhBhijG!ybRNvin3`&0Fa0yu9u%7>ku?9d4T2Nl!-=+n z?z8N9AoMTSV920;2#X`OPLeKHH>l-0s=R5?4C2wYRD|`?i#*E4p{?yFL&Uks3_G3)gBe zKK7+`;8(2<7uux2up+ly_mQ4cub`c;J$73NO87~uJK7u~Q=M(frU!d2iI{ve-np!g z@-8%NQ86x=b+4Xnkxxq%>@Qg1cOVLob^2DRYZ2xq^aDS36zsFMnzU_T*S6x`Hkpm< z0I_38df{~P=?fraCq{`tk9Az%1l>xSNv$j@;)=28&`Pc9XNJyK)^{cz?2Ds+Xr-12 zbD_Z-AV1hVuAI7eQ(n;if z?YAGSa?e(>uN-w)7^;Q6!b(YTa>=Zd(+o)l-%bPmu#U^y4O{u#4?odnIcR4#RAwL7 zQ9j6?WM8W3yc&}rYUwQLIUhz)(NOwrCl=*fX>U!#+uEu5f8{=@;2Qj7=*2b4IX<>4 zrVsCM`;{RZlHpJGS=!J6|7uIGYLWj!oGE-8v5aypx;b~S{m?fi!`d_|?Y6fZio`d< zGM3ZsoL>A<`0uC%K(kRV)sC?+585?yS8$`}t8VJ#9`)A(>MDf+zr1z03(JP}ydmG* z;6KCvyRv2T_5^0;4TWstr03B zE|sc}8x(^@?@FVh#N$A=jDG__5Sui{gmY$~l!tTJ?|=cWIEYJ3v-cPl9$qbX{6HPB zK}du1Yrk6Qd%x;<7f!N`JCeBaV`t|0zto(SEvCxa9Oy22+C!os;c&$qEXn zgC*E)Fd$hepkZJ;3=A=&{ytg=i@A1c>h-VQ1g42a`H(M)RapV4Q_x*$7~#75OX3M{ z#WRpXXuPmJoxAl2@RvjZ&P#}ypODe0k?7WM%bC!uo75Kx=V@N)6d1r}1?yt+)m^U> z<;1K)vse=XR~q_>#vEu&RKA8aBjL*dj%tJfPmiZ&IttE)h?c1Q9n`uz^f>$d zNw!NwmM(shZxOC)_}f(hP(;8Kc@BB(=KY}3xo=?pw;F*rtEBh2v)p#BG2?fg0%lRC{4W~ zl`QByRE?hzq77k`V&U}E z%fLQl*&&Xh=dy84gRD`{qi5a&KS(&M91!*2JrnD7py3M6>WEKZ{%;`j5P(mUug{)b zX#E2C?SGGsVH~tjrNo50C@uM;DWWY(iCvqGa56wc{l87JP6eCfgm^_YnMxX!9B<(X zJw<-eFaKMB^yaU-XliJu(yzkUof^bPRRru`X&C(>jl|%0kOP)VM)W&W4NM6^7G)G? zq4U=HL|V}?e+<`M0ouf&b((EUu>YIXl)m=oaD^sd$N$?X#HD}d&-ll73P{)^ZpY31 z4M_pwsD`RM*--mu3k1&nAq?d(MQBWa8X9bFr4GL%q{bQ$Svi~1D)$_+n zY0_4rjG|_Sff_j@{GdFle4n&FoJ=l}WcGx5KiRfs^B9OO^I&ysKL+XyL-1?D7f*Do z;Tgzy@co<#szv@_1>--BEpQeQcpgy zrJO%3F5O9l3H@;|6rC?yu-?0E_Y4 zOvOPF;VD%gUHVtgvXUs;%(W-%ZB0*Zj_nvY^=fJD;>ZMG=JNiD>`|;NP*JyqSnwym z+z+mGy|25qsn4RCsOI)UtDe=qPBXDxZ%Tm5ln~ z7NKY&4Hr+fsLpsqn3mf{HYE5a9SKqTHJhl`q6i*^64zpNaDwf}mX@Svi6cVwqB6eHjAk38zqlT&;~LPg)doGl)zKYeL%lMrP7IRdimntJovBTwdX{!=(+=LHD;(sQH+kC6p0jVUEAX26888jgM1;nuL*g>I$SJu&W zIx@nCdp|#OV7+;&WeiXb#%eT_y`b7e$Rsw$bhWfBK-G?&Fy6-Z3)I5yTQxiOLuJYU zjUXql&?JGv4eW5sMz$q@=F}NQ2m7=C1w@J{Tb6bh6my{@Lc+8bo?O4fDUpdhO$Mz3zRaY)zA}HhE$hxiD1kX)+J0$J+Va`N! zI>Ag$o-$JQnpNkgeQ-R2jU7Z`s#(OAx1&gI6te-9h_cslP`6yplafNj=$KZggMmH9 zJ(=Z?pH9QEhA4;Wr399_57mwxmas$oD@9#X*sGDDMPF2-^2EE&(lDJETfoMb z2izNG2=jW$FOze_R#64+Y%JH*uB+mg(%=W%aR|uxm<95A@k-%|I!?uz&U7XfChr`- z>F!i*qvR%2`YU>9n*3Ps(KvlFWY80dg=KPA82+G>*4&uM+?g8{HpvxzAcl{c;SKuh zG#aO?oI1hQ>4dWOt@d1lRAa|d?A-gPPIitPY9t`9wKjp{3~3!!&2J}GsxwLEYos16 ztiwLJEeV}vAyKp+5PLNr0}~$bp-o%*kg(_Zy{ks-qX8T@1Yw}Me%|_gEh0H?CK(d` z?L?>alt7B~uX=STCqY`6EAK$FA;1RJPT>oPz_Ne%C7LdJ=$N9jGDk=$)L99!eens{ zVPGrzf5e}ThgirN#7LS&uVXt($ui-@5eGB{{O1C@qTQ4MgEaxE?s+ll4)xQEJ%vFO zivRg3>vsmsBKHBqqLO;xXQsks!+0`JnzR4;!SvigNpw1-9{Q_*vR_rj*$=@G&394? zBno?EpIUxW4sJ2znJEY7nZtc~x3lg!Z5X=i5shr0ya=@7}0Gwq;$3de8) z?+wrTC*)Ws{}-78n)4XZbZqA-kbdR_?Tk~FLg3kd@m1Qq?0*UAL}6)v zh$5aV>7yee6H%5kD{&@j3(EKLal*+;t!4haYq~OG8e#PQqb4^NE{wK;(sP_57otS^ zKLld^zk#nV0kA=`i|;>r{Jgtp=7ZQF8>nDJzjpCYN$Zbl=Q8~#WhTlg9fKAsme>J= zlrj?zky72z{|7sCl@UfTU`3P32ImA5L)|%_j*~?tYc~2|Aen8^|3ciw3_C;}G+cGX z|MdbW=xFSzof4UPcV_hivSvT`7@fve;1`HSm$v zqUF$ye>^Y{i8P&k+)N^5sdr-^4c%w16h}vE1f6Ja`X1qG8ZXv8c|^G^=|5pKK(Mj1s~G=b@}po2hP1RwHo<;mWi*p=+QBchb% zMeRFC9H7cQ5%RPz>dh{H={wYd?3p95(Vh$^*Mcqrwj{_x+K_*dw;X~N*r$chKQjO9 z3D)&)3yNr?eNju9TPc3<{0vstmWov*{r5?>0tQecI|c7re)u|}b1Vx{77B0qP9*R- zo={Ru2FMskGH1nXqu=~5{{DRDe?y3$J&`M#^u%mwSmsJIVwY~P!GC98>+XP3*HOo-cw7S)g`~oyk6Owc$L~tS>hplIC#NWVM;D>XVOhWQU3es+ zk%dmwJ+GgpNCIyGzB*X5gUqi~(J`4e+zyMS=Ffr+48K~cRk3$7v`yebwL4o5lk0sZ z6q}AJj-#B+OIL@0WDGHndnu*(vO&!5l6fi+hcy&DWYbeCl;>Pl)RiHb|+t|GTng z?Rz79b{rq~!I8Z4;Ux69sGw-A>|Ck$I z)hH6=ky?Tgvh&R`29U?!_G>L#qUAOXJr?bg+R z!j+Yh>6#Ri$8rxdp>M{0=pdcIKHGGc8$(NrcWD5vzPB??ev^(snWIfe=`@Q33H$30 zNJ0*C)}zI|GQ*5VwSC6%kqnpHGIx$dc*WOWyskN(@?oI=Rd{q=-+$A-WWmFuo#%i) z5%e-)V9Ws})JX&<-|mZlintMViI?kCuO0&zVl595aUpgwM=U2=xSopK7bAgtN`KTs zC)@G^5Jjfgjb)bziFmyCZ$|)AO&p_2Vqq|)wAce|jmXZ?LIpJ_J{yeh{QT^(vG5~8 zG5%6wAx7?4m`RF8$Mq81NLjAtMs-^!ho~IF0!fF<(S^GM9(%7X>?n_7q;K#=2qFfS z4aoR$({<#C$H8`j5XzmjQu)x?$i#DMlCYl(;}xpm4^|GBUDnnK^+qUP$*vb{EnRNC zxOPMl*;_3xHnUB2!gKPuZ}IZ5>%(!Sk@yaVqS||Bj&UvR$s(D}cG)Tk;#l+jSfqbS z?Gr(|Utv}`yJ@GQ;06mvAOcETlP zDJ8~NJJj*XFPEFWuGyD)d!2-iXek zI4%G3%2&6c(sIy|!A@YIp?&nA@lD(-&A$XZG3!8zcRoY&N@q)BaI8-efV1rjQllbK zEPnd-4hN$uDDJG zzT&zMiaB-&`>5yf7DtsuF}85*8wf81bQCc_DHj9)F%Ym}o7OtDyhs+0H%ElD#)8B$ zom%wwZfVJqUoiKEZ)0#>3efD_q20kF2jh<=Bf5lABh7raYEt65X(&1l{D2x2CKy{E zBW&WwgSk{ArO6V5ALk=nQ5rtt^0H}gY{?$+NJX4A$)Qwp2xa>0+{8U#^rY zcV2BRN=@H=Tv4~Lu&I*+YU4SmsB}`tjSXBa&btNp)K00r1`dW{&1@xyHDAh)jffON zZ9c|g<%x<^{{B;0St#z=dKZX|M!qfei>_EYVWU)_vU--!JKTg@3F%n&cC3Ek92N~S z(oY-aUL*0Lds|Tie{JHk7mEm}&mk>G7 z{{J90u9AbO{E-H`a46sN)umbph7~Rf-DVYtYk3WIe^O$H;6{|?Pm8u;e2>`BZlFbF zFHP%sj1puw={_8Y5rjqC*>zDu#kVFm?xTI3Fheu9#EvV}mqKZ|Ft9s$Ji68`a zi#XNWgS*JCr%|PKg7Tb!{oy>-_~)*v<$i8}W-4)oEiMC{OR%1nMr8ZZQQvWEslXe+ zFernjvA%_|SZ<{Ml2?#+KNq?Mw;gxL=rJ}>^tHdBV6YT6zqqN=8cN*_Iwfp|d2~mF z?$A0EugLW4fmSM)##&4k7Al42k2o%E9U-)qrU)BHHmdHqJ!(E_UIhf+qT~*0p}#qc z87_dvg1WDT`&)ijMQ1gRYW1am{i#QowuczmF3ihC>st#0ElJ-S?h3&XMG&PDD4*otlkC# zDazW|sgMTgo+9AVKQw8pxIX=!7ojoN+(+3CdfZ}MO@~^_j-dcD$ zR~t8FXH!HbrRziFh9$AybNi%LR@Qb*j}|3toYRnoh|MGdl12q+vUlZ!ePWhP+WiI- zhXmg~`_~sShcDvhQuwk~y*8Z!=VM2FVrs1p+um_kGFRz{BHU{?nWji&x@&X;1oYPE z96v%U%Mx$lvG^AWa&ghNq8cyax9Nwm0Q)8Rcm&fF!KY*VVT&_R=C*r)pXzO{+SaS; zTteB^Kd#~(<;;}x`O@W^UTNSr+iQ0?kP2Wop+XPE9XpQ<)a)&8zMr506_?X@1oSrV zNd6uuvsSNwnL2`w%uuqjNmmQ3dbP8hSVS|CPwh7dVo}6YgnJ( zLOLBYRE)pp#29ZyWm7hRCM#zQLlIJ_Zs%c(6(ET?7sjNgh1b&j(PFPiwW;kY9tYp{ z+NeCs{P%_-!DzPW@SraJ$lXYoq2|B}ic14c1OWM{*&lAI%JX%yS(Ao`_Sl0Fh zW?2w;vs6<0+J-#>@Fg}Z(m~XcN*w4}VG_0NeKN5<*d;8%q4MnQO=>rfQH!$y6r>2^ zL~j4k$-0RIILAR50YRq$XM0*1rnKRT=tqPq&VEqJj4D(3#SATiBz1NSR#Pr%L-u?T zafnMt`+-0p3tUk%{+fHFJBP_hGvUD91;|bJLgcec9(cPV*rBN@2gffVkKTda+mJXy zvq2P#mT$n*VfPi6wYT-a2)pzMy{i>Q+e^07pvL%)!`t%P z2DGO;S^^hGe?omJ)J8DR*Xg7k42i}VXAKQ-09<=pKR7hR)&L=|0e>(V1(nQclBj4u za$ADHSO?wi_IoHe`yx{6C38UbMYE#07rd_s!u%t|lU4w_Xi{{emO=SZOVavTaAi>& zq9&=e+nV&_2Cssw_|Nl1lw@b{a2TrCct=8D)SJgpnkN1J-T^~lfzGOaiAz7BYD*P; zp3)S#ZNf`nOJj=hHCsw!KHGcwrIVB)HDd%spwEv?6+bEARxEfd-MEqS2{dQufZn!F zqY$*?riGpgfE-ETFxK2XvA95{yVHXlZdc9Xx7I7J|1>NX|kR6=sxduIsotYF} zt+>aKRg&)g1i`!brMcV1RKC*~X@9wYH5%VC=G)TZgD1Z2Z^?SSqh?WRH98`h@IljHBogab$$ zoYRFTtlkoV#lOMlJ%NRP(Bcpr+JJkimp*jil!XNTVDH1b2S&s{yZ)&SI`1Ab+GqcGsXCXE{6QjmlZ591HQNKP@v03mV z=fv8^>)N+xz%2Vm?>tRTwf`UuQ!0J-HyCN%bc63DPF4EA_Nj7R!+R>J3k_(hgB22o z#QSnUcvDjILqSmn_A$17EuF{X5to=6Wp?Lh%nFSkppOi7-@JWyhedI_ypK78cGYB$ zUAvHP7TK2tZ=v_}qAJrnlsUh79=;#HvgFrg%dj=5`=B~LizD?aqsxdy?cUZBbNlX$ z{jXoY1j=OtC14xxR|RZ)-#$$1OqW54dbL2GJel@4y~KJL^SDa*;L=BfQQ`LM)mLSb z3OQESi+{2qqF%gkZS5OyfRCbv7-do|?Uer9Zm_sWI|+GhqBWM+A(U>U;qeommx;Uc zX^`VeTH5xTOM|QDdd{l6f?zJ*4P-}=#x4xTo_8f)HRQPshGEo2E0L@`;YI$c%U4?3 zd4`vI=_{ST&`1GNL-ovS#kMnjlctjlihaI3bYVh!0D@BSsd#B+3>+_!nEsM(geizHdH zB)D51r+J^GQV)(^VZmxx~bNovlOUKNqXlFMu6 zSYMb^rjdI*;F987m@Ls5Q`+LR)2iC0Qfo83ZT~KYqpjzfZ>2Nti`=-E^6MD)t~=fT znDvq9eT!g`k9$HJ&=CctH>3?;e?ldbT7#lu6m4tbjBk$yi_O@@gt(eI$4q=5vgdGUUb!t1 zGxnGO?(G7|T`89KYw~VeQ^kodmYnJ+6>~5RIdn-(J_SmFms$2} zqgcOo#B?v&U*cbs)g~Uvyh^k7rJtHvmU+u}lU=*~I(U`rC#R&&FWz2;?9S`IO4ErP zOhqu@KI_%KVd+Ftf0HoSVjdY9UZmobMf2Uv)yTdEaBWAQx4D_9`s9a^s=UNkJB~(k zZ}DgTCOLc)5%P0!$@uem<~E%SncktApXFq|ivrDkot+oeL*k+pnP2*O^b`e0td29X zHAKv-on%7(a~ZxhxSZ5oW-NShpQ1uzhEZZ$yv8}zTbO4PGC{0*hJG<6 z_*1KPmQRdJPo*HV{4sBgttTX+oQBxjLqtJmCSp> z#265_7_xgS(p8-lV{;Xn7Ts)qm2(pOW^;4%MRl?d-OP7xvE{?6Z>SM<)unU6F1A0d z7Oj7RfCXLsR?|o1l21pl*T}YHQiI6ti)B^O{_FfSxr&_N)2r9=strbw&+YBmb@Fb1 z;?!yy?M|v$P5mw>f1UEWl7-&+9Y+(LqASOFo2*yvyLmEL6&*jSi@w1~^~H0ax06mP zr&sd%)bl+V)i<|U(t@ds$EllRTv*RvTxpogtkFslNCg$fANZF#)mm4soj91Hq)CaS7c1YOnfn}?n(!%n z0P8XN12<1$&blO}Q5O4Kf^NihH}eujG(M>Q=x*7vGYOx8O!s|PQB;~33wttB?ezAM zn6Q~6Ryu-Qj_<{m*2sn>tivHvdwLA}V=(g|Y!Ru&q5T#`?3a9O$BUfvg@)}bQ-eWo z=Jnop`6!ci)204tBRPNADg*A29axm}de1eXqImh@U$eK?o5T~#R-QGp1>H4Xq+sL_ z@5!lSXTL~4T8+;178WVT3fHAcCJGtv^8?{PGf){f$Ca%b5&CjF{vzaf5qLb1f%-^= zI8$AG3$49q(tSmMosEUCa9m{Oemh)}1ecu6hx?zLZeG9UdWr%u)PTd&$+Yc&JOiT0Pu5v-u+Vg}JV9 z<-@8)|G>Ybeh#hvo_US{agd-iKe%1BpS6XO`Qy(_%ammAsmp|%k>?_7iG$O}w2n%`mO#4l}C zw|#$TY(a0J?rwUr)#PHmR=-9B%dqQ(Z!@kZM2_}9su%007E9+oBbnOp`E98(Ma~<| z;t{@SCxQTwP(`J#!Lf8%($~t#%7co6p)@T&(FuJi2fw~(vu0gd$}P2>9SY+AJ+S1v zQRQvLX>~Vn@Agn}q*(v)PwUd+VzaJnQ+*H)0(o{EjHWhUI$qo7QW%|^nD~*COZFSL z+A=UO@M3;Q>h?%+BvZ9t@9#Jh#dm*?))&qV9IyD`Rx}JeR_$`D?*w{&?XJFKUT4r= zkyclP;@;A~npWHYvK2+smGA4(s+0HdC1cYIcl0Yh!I8))(v=w%+{Q5hv z`1b7-H3)4UFY#B^L+a6@n@d-W8+*Caf*5Z!e@3C2`uf77DT2l%TYI$Tlx~Gq>-yy; z#y_IwC$A_n{Tp`tx6eJVyr7Kh&CV}gK$vA88W<#wNf!T%^ueik>tJgYiZv{`Z>8Le z1#ec8zAL#q^Mp*6In=TpZUevyf6L|X)laYGnj{j&6Xr>IbSxveMYH=Bj3-kRs$&%P z@M zI#{3RyZPEjvYT<|(fReF zD-z>O4cIHReq9oH2NTh@jwi5E-`hopK_wEeuYO}}B`OW52vAfYDIkOrdm$mA=t8xa zp)doDTq|E65I3>|dErKzBzYH6KO-l_t30B*gLgiA468z#TXJ`Fv$FW`A(Mx$6Bn<9 ztMpaT7D>pn!t(kY9v8@Qv*~`K1fF~f1YUr**kTl)WiYtC}-wWX#dvxN<9HiHtSxy~oqmtaR*eh>6~#@Kk_;@b4#+ee4RHfOJyVFYoeA|4kz#J19< zBcJu1H+>Tqs`8-YET3qlR$8?y6zgjI?4j#$&A`?9}hr2s+k>qo#EtCDQ2JE0K|C_YWn6Iw!$gtipX>3Fk;=243s10$-3_|Bf0-K3ojP__e`Dpr ztKPGrlQH#IapB?Of2)Y`pDHxmMoGcpc2yxw2J|cFhX=vJ6-N zNl?h*N?eN|LG?7gSVL*be=88e{p#qIzohm&E{71+izSQsspXj%#J|eC(IJNW=r#}D zxzT$8CNXY2Ff=r^x)4^KEzI1e_0hP3`1VlcTgT?QU_L?ZQOEwdm`f@5$XH=iPez0K zO#q6q8LFc#7+ZXFH|@IDLFJdK$*Dy-@c$kV>rxp)pN$;QUD&Edu5NO%1>6XB|5c7m zW;E1@eD=xH<2wX+M)?HA-ff(Vv-?-{V9;TZPmV$M{n~SW-+CgvT~>D=x-kIcPB79R z?3>)zsyshD+{6(ODA>X~fUy|!bJ!Dq(Ki1Ocp{s=Ixzy$3Vi8k<3sPeIzUWvw5mAu zDQJ&^x1*YgwR^vyj=HlENJk_6g?e7E@2jyhQj=}qJ^((rrNwQ&_#O?9J#Sp228>s9 z%SYAC#CF1ENEh?O`^xPm7}lL&4sK~JUn#+kl4;p_e?dQ;fj8SXnZA6F}wmi+#zlY*UAWxv=*~`z#&Ryre z`R0N^`_qG zUoLcxEgs?CQg>W*}CBRc+Dg7 zAvgb)oFlTm=!v!CvGr3R)(?hjpO1vsO5N@l@{P+K{-_*_!^}@M zO*oluwyht0nceIfGHGo%D*=LP$;0iz4eqBjc$Q9*Ez+`aBSM<>jSX1G!?cIymsmO% zHA<9Z>vqRQ3vf~Xt9;tl-xL6QwAN8#4^-69aVlTZzPe7i=w+I988gdw7XTwQU$gPu zvubACC#QzpbJC$oyI!YcSO!HJ&wZHPrWTLAn}!jH|C}9yG?dKZ9#fJe??A1q(v8`- zt_5DRDi}f=`jS#BCHH=kJIcC*e^#h-fNta?=PtlZ6knpo+t1CLnRtNj%^ zm&SI()&`V#U+8_SAkn1E@3)O>>Dm}$5DX%3Q4x-RfD8e_ux{Teq;HDbS%oP-|F5UN zFDxW~BDqiOo&M?Nidn}#$GNG~z@aek(0)VAWgThnx35Qud=~52+>v_WA-tY6u z2wOHC1pmH=DTw~zT%AU zyLkn_9-?yqWDoPoR}@?-bv=M)h5bfu&(>(K`us%zw=h_=DgZKR=zmTbL~N z_2mjJAsYa|d~pT4VEmrLjpk?h(y)Mi|4rawK&}?SFxI_jnCElTkHo5m9clA3 zzLX@}0a|B#394uIOpsP68{}>@^L^ylvCq#QGjdjK;oop0DXq))Mk`f-`^u+?{1JMw zcTug*)_&EbKF1*n9$!7Pxt0NMNnIYQ(HO<;PD)Uqp;m?yy74;ItJu%h&9@NOZ}iyv zc@!GnXN=TeO&t@!4n&RC=WA4)m8=Poi41-9D)T0Qi+Sqx?7;DS2ME_KY1}v=xDpC* zgMh;krT@xco`W|V=F_(-1K8)IP}z)oVd2tu&kRSTSIymiKcf$q za|-x?OmXRc2iTS&4XqeXkoWZ@2W0X3S)K7~NaOXx5f}H7DFa*Unp-edgL(TrcP($> zF~|t*#C@JuWrpj#xeb|FFfT7M&FCEicAQ{xqz96RYT=?^wn)8N9uROle|f5O@+jda zsmAOKW3pe83zi#8x`cw9jLkq}$FB0~w?o?=M@5iB5x)t)G{4^H4fv27v~+J>=yd_s zMAW}04+@Fx8QMW-9za-`ZOaCShBPXzd_%tT1m1f`p2t!8ig@_aejmv>k|EYJCw>8m zu;j3XVB}s)R6G-49i4>=$=GeSf!LFZ`(YylK zT*gM3nS)@XZ-dO_XMNw@`0b%P%7V$PR7IC~&6!PR=)42u%-fPgbm_GXulS{!eXscV ztE$g@Zg;|s0Ey}uHki&q@lloLb8iDKd2aerxub&rqmx`(faK*(N>Lr(ORShe(i!7C zf({u21m1kc|AS)2XfQ`H0CRz#Ig0)cDn_AX2^>pH^J7cz=a|E)8!k7drb{HsuYPll z^%vGRZ+byg;X_{|v3$bjcFm^g=2f22@{iPu)9&Pf{}%J)BFpy8K&>oR-av>0JBh?J zh5)>GYZTx9)7QWr;HAk}Ok=d!g}Wuq)VmbD9yJbft1e`oPs>3_mO1}{`TpJ1oHuF& z3UtUkgOQ-e;0d$mfoxtlyWhRbqmyYo;{$zr;c-xKhE|qsS=)4+HyZ^S{ECRb1t2>M zhYSMd@^bgfEkFYmS9o+;$HC*hbLP$dP6dU^QjygCnyua?kqjmvvL9R^ase0wsV$jc z&YAlFcu&sX7X<`9AMsAq1wBI-&gF1m7B_DXq}4qn2$Hb7fSK4JN-;Sk8aa#0@N#j# z)O8&Am=F#4y}d~<-sH~JcH&vy>s}^zFwZO%i7*^nj^GZw_m;Gx(Am00t^h~Opn3-o z-GIlJ`JJJp%zS6`-4yRlb{&pk^M1QN71+TIfAr65j1~I_T?_{HVZ$|+K?(q?{JzBX z7&Vb`pYi2j1Ie91qlXv3RElT;s+RX~Tw7bcOg~a52k3;yvVqsH?I-8_xCfSxqD=H& z=(R8~len*bZFjV;xv^T<(-q6|0rU5p(DTfqGTXQ0WM4;uyu@W(V8*FT2n-i+P_bU^ zO;u+SQEd?7Y=!``UQjDb!>wRu5X=_lZRCr* z;_bCmsK6QcxdyO_{dwXm0KC_pv(^1TA)}|Ns`SwM&Q@wXk7inGNICBUn4 zzf14f1vBxngWAUpQui0&Q=a4pfiicO1ZL#`MwwYFG!?1xNV1{)PD%Mm4dOEQ!z6rp z@Ecmn0}Z#~iH?nJo-J*8P_m>OzIqV$1r-nFd+Y(ZC6T8#~*QXDfO`}{WdY^^pw%YQ?=fg?TVr6fk(S15(H>@OBr7mP1``<%vq#?P1f!63zk;l=s$6%K?Fn2E<_1J|c} z$xs^m$-7^ZrJUaEcMMs=M`-cMeYTv&br<)Bnd`*P5I70ilT|`AMUit2O11r@X7maD##Bm7yfLkK*o>=C}T#4+%|$9h?bL zmS6gw8CRW5RM)Tf(0g6)^9S&2uI z=QZ!^t%+~r{#FD1Uw>Y}k_4@<@ud6lbO22J)3@Fd`OU^ii9+>|;VK<FtGeaX;4xzzzX#2Kar= zd@T_pqtOy^D^Te9o8jOF)r}w^Y5K9VY?Fq>hGNxR5#VopOzuZmma?R4aa_g$I_oP^ z+H9nDBZ_xa+z0T-A=%*;d%M7KfMn@9-L=;Mi2;D^qZs>jv|FsroPz@Wm*kg6t`-l# zCCQs#fK;i94qso4dS?XT?YegBVp(gtqj(qfkIP7vm~(z-pI_b@e7RWa&JE)8Kb~{$ z1F|ZAQdOPsD;bAj?ztw#m{~xS(yU1FCdACn3<967f=B5hYt2H!^=VYkn;8VVKc89M z4l!7HC3Ubb1$TOL6@Ql5hx5hsFY2)JQu&=s1(k1Kf3mkt1Mpcpa8|mKL$H)!2OHO? zo+XH86!o2T1($b~9}scMGJm(rz4`fSj+F)8^C{0gQaa=WAy*NJ=e~C_=kXQeU9+E| z_q}ewko|Ttjg)k`TBVW%{0XS56skRcew;)UGbVg>JaM8W!n!NtOqyRU#L#?iyuRrx z9j!>YquB9|qm4b5-;*n|?$ES6Jo3i(mZp2S6n9Z@~}sy)sdA}jtN!T)F)7a zD{@J$HT36$ZY)pB@9Zs);)p`y`68@Vs%cTo9S&G*n(ZVjxWAo&$PQWU z+tL_2!E~pkiX5$4dgeB5M*oKl%gZQUOZ<2olTxg>n3Eb6{aEe8Z7=2BDgPzDTK|E~ z?B_Zy;p7H72Ez$> zjYFr%4&hm#oRHWW*XXsNl#D`^W^Q$`zj_i>?Q?~k@OH0>+1-+QQl-wb2FhE)2 z$(JMNbF2dE;bA=hiWoJwnaXpCS-}>G1Ae790db^ax<@ttnS*jLaUpmNq()ac$Q^Gh z_mQu?PSs;N1TJp|G^_$VCFN_3{pllUK9m+_wjyLlY?qw8KmMZI9~;2(q4d*ob5(O) z{Gx*i}M8LB3FVO8UU(eABy;P(avZcvlLV(=6R|x2Hay`jaGT4ZP)g#djj%pIGu)k! zDy`s97RCVe&*f>d^K6})`o?*69Q8S*GG*lkNCwlx>W8u&Vh%)QACV9gv)NSwwzYjg zL)L$tr1#jx9pH2A4HGX-ep$PNou)2m^4O!Q*rTn+?KnsTkW0KyfP+6d{^BQr9monT5?zit~Lo&=z9j5XWakIrwa zUb}BBNIkSGBc4B_6Ti4?UmR#$PhNV0em;OM@;(OEQjysSP zXJZ_E)o%)Nu_?U-%ze2N!$Q%V%x{3wTD`)zP1h%3Deh+kS(*1y)$V+KNPK~_e3oj9 zbQ_~|@qH+n!-H2UcIP4S?OZR!_2}fMgvk&Gk;l$vcqRS-#5z=Lg(SXMhaZCJ5PB;D|G|q z*{2GtJ@PX#oh>i^t2#6$X;5Ftg>re6+0SDag&O*3T;iN1R<=~7mmvaA3~WdCzDBB` z!SDdn{w_dYq@M9tijdK;_*}Jz(4g~F5zj^PxYji zQ2;3K@FLa8`{3E>Os)I3@ddA)ey=NopYF+Hlf5q(7{WAT2Usj_gLvr*2v)YQn&R23 z3u>n|_u7j#g&c{EXjMB}=!AYo+|}4^q3z)Mw5$YOKovVC2R}^u8l|uq)Z3$6I?~Ur z?j-2ct3Ai2Zx1&7apiP;KqiBzB>wo8!omVm02M{=RY~^tb{+tSHwRAy0N(@9r6(ZY zS^*>}U_=4{gtqsK02CEVd-^=qUcu5sXYSmqC-L=s29fF!iTDs3nJ1v+2456yBRm6) z2-y5+a-?$`w+lgUflHAk2NWYvuJ~ zh6mJ?H(vTdQvxq#pBQT)2|z&hy6g5?9gJ7Bz7jM2p^~c_bVY;_=R`^gG8Kw`Tt7A6`esSW}8ZASPvX_>XooO!QQ4y% z^F22pGenk-YZxxv$lBWYR#e20)vX39igs5#`u8GVq~(3dAW8hv@8W2izyoXGp-O|A zo%3xHwr5KVEXms7))%k6x>bq-KrT<-B6{d!n;1$JktR>^H6ilXG0)e|oqdT3SkXRb zA%>-hupW+kAy@!zbthHS**W!?RIW6-_olz-kq1E&n^EI2AUi-gSM7dpb9QkLY7G`= zVa@T~hRmwRj-E;DaLiCOiTU1ZfRm%~@$vl+9ZoIA|h`e~D{xp`8ufpmBBV zukK2?=ggl?6Z|J(cl$Pvgs zrF376h+F*V0280>W6`Kl8x75;xckpSbK?1{i2%k!xOaYz0g&M$2}4|wcRC;(5cwn( zjp+b2*fy7iNdQ2M+G$nu>9vv3)-KM30BY6tnr+{oEB<0+Ui!u0e644=+4F1j3Oq*D z5P-XMI@gN?_lAasab6oF0^eL&q}{rXbMk{R4Sr0_F(Ze8-6>ck*k=l+!Pm|A-X0_2 zmv4z5nLI-~H5kPzWt-oasZMUfb2)A$B}HzZ<;hl{4<8_ufbzZf}3+Dtsd)WeAGE?bazUV7x?+pZr<0C4lWyYROP^1i9#5Y1=}^u84C z8%5xjpefF@6Ok`~>x=dPo+M2)6dRfYfz#WWKG@>bqi&Oo9pRb3x7w+8UZP0T;5WDr zgx84Z^LS2q(l$s6V&&)7OK#i&{GN*@VwNL;^1^cQijAer8Vh<>%)Q;ct;rquS`2(i zATX+^%*o0+nvn}tXE#JMGcyB>+`E-w9>9l59mD|`V5Q1Q2#bL9*B;$Q1@8HMi9&X^ z{eATIfX)@_(G-`E#%ld2$fKe3N}?AMl$a~p19k|4{-?X9B4p)~xg3mxY>?!ihHq(p zqxC}ekpyx*C)GSJ;M_j?*B)-p%fNtK>&=X{%~v3}`?w#y*5EE{XkpT^dLBun;ka?TVNg3%!I^MfQ{y5N*c=PxOvXg2ytOd=E)x-CB6PMbf-B~ zwsCVxz^__>QUt^?_kBIkBoM=LLD*a}WPEbPn4w4cOyik-9q^r=gFg?=$7|Q`+Or%c zYu7y*Zbow#qSOnVjd_aCgnCD>$)^E7y!5rP=Qs`oMo*uUXKTk-!gYB@N&xX}xoz@>AW z^ED>}6nMy^p}DPaN$men0%#0Q`YWzy4wtJnyk8TNPpVmsmXPMH75pYQ-!P`!hwk9X zfpq%$$Sez;s}m_MgZgU|xa7QOY9+tabKP&sHQnwv(B$4?kqWBCNG4LLkp%UlIkVe& z8N>^ipWd;nLw;Iw5J+PzesGu${ake6&OUyf*k8})ncly87Mql$9mnp1eqpV%{J_6<*!QAJWJou9_Dli?@5OeORC*p3#%H_-bJg;0WO@uFYS39w;U#$2GrKZ||T zjso;oz&)d%^ElFRD&h6cOiv%54HuyuOueGxq2_oI0Mtsx7bOKpjBh`Xw@Iz+Mh1a0 zAmvhM&|^t3S9NJ0q>33USj$bq@!6y5h>XvH-{SpxpcBIN*);Xb=bVVC#(m_XbAVzf z)u@8XjjnZPc|T0*)9xJo$W4(pw|@ny$>!WVG(AbF8qX~Ql6@AR7FfZp84YnP@)DX6CB+-8 z6sd9XtUj~ddDE}y2*a~$8K9USG3E1F#*%|4OE{|rA>o#L$Kh-*qTMUZKjW)ncVU3;>1|w!INE;1B9Yd)toJFmR6a)aZwc=PK{vlvV2I1RBgHR!ABQ-QDprWn#T| zFWm@WIxZk71z$~yI54GRirzUc0F7qBlid^~K?)ukg#!npvPh$f^~#0h9WBU)^0`$SBL>9x5gCI1vzg?Rbh zTeXrZVlX@OMBzuoNk0aHR?->NZs)2*RG^jCP^HaGEj`tMwQkj`-x9IDF; z$3&Xw_S5)+BIDg;lj9XFRHO~Sk#uF+8t0`6m|A~BPRpxoUbpkzvOBcY+vJDj6&OHW0A#RZRSwIBaZGcD5Ap*9&jjRD z^VL%Ure*QNO8ex_htqAGCAPQaG-9bB+P<9jZdP`bt;zu&91$q36=)$1p6r~w!y%8h zV(uZDUy@##OP+5UJ67nPsuyN$lE&z8%W$XiTb_$l;mxOMnc<3SVD z!)Ni;?K6`qfH?YH82pN)|H4fKXNfqEi~{H6_py25%`&t|pZE+-t06s)0OAzikE;Ah z0pM-8*4IjpO#(Wf0de`SZ+LVrITywynA9r8-=R$EJ8_WvU4iFuPhWK2YpwwS?|Kfr z8ik!|u-0xEXR>N!u18}W0R-^sB zLC^%nTCr(mj40%tc`r~>XHxmZA<-wxu!Fm(WhItCvP~JV+8U)jF=-` zzfDAMf6>1WH~&(Fxyw}14Jt(}q=^p*_b?``Ms zIj5>~f6dSPJyKd9a#*DH)?p15a+!DLR zf_6sVAj;8inySEAm-(t1kUPd^LYO6Rg_kQysvbb8R!$U&rMd=!Ea)j9v;vs0F;5KC z>6c0WoN60fZn~~ncQWaIe^xKx$gerUxC~^18e>^!Kt8b+R;j(oXG+gO$lf!26u?Xc zjQScdoUPi`_=iyvl!(JZ>6Hjy`9)YRme|(2C%l= zl>l{8I)P!e$6Y$lFSbx%X~&mCUcxFQU3+(rkKYneW3<5oE-?YodWaz7NAozWP^Qc{XrRnFGjDr^msASgHPDZO12n2`H z%Mvs|d7@zs%@Cfi@rQHyXcscl!6rM~0fm~kVMD3v2~yV^?X9m?Xlb+M-lAbX zw7*<_Whu8TP$ z6nMR^Z~W?mz=m0KQ&%}?%;-9g8&_`dRssZnc4IQ&vVoc%|GsS&?ZT_(uzlUgL4g`= zjm>xf{fS^80Fz_-;#&bk4x2laMqqPB6jj6$AVvZo2y20M+J(FeO9&&!@JN|*GX1(& z|1Hv;GrX6)*Xu7d|MGdA61%=m%`i{GF3=`1ci}N$mnaFPf;Pu*48XJ)OKsj&Qml*L&OiB@ySF{tB!a$y1 zNK%XiQTazyAnt&MkFLd{Bn^!?HEXcOuo?0yt}O3}uuRW`zvrE4dZ|}k5`|Sxtsn#b zK>Xt3_2T|kQJGAhvi-`k8EE{72Ku+}?&%X!7sa}Y5S?Ok252*1Wh$=2a`OQw#?4Nh zY;7~Wf#OxjJmhs->uf$KVWRSslY!tTe+CG`@uvz1o@e)FnB7=wpr%l^ci3H*H0;h) zhL4Eb?_V(10^G55DJXt>1_Y=|1NQ8pS_j>t)wO^Tp(VFNLl9>WN*uea(j-xuoUVw) z&n=fCWaxUoZ(6E)37Wi+BNI|wNL}#O=>0}Q1VvJ`=SfAD46@|2v%dp9pHsSUYbw`& zv;bYc5mbYvV&ZhKlf3{0Y6Nt`gjRJv+A@j;aPS?{82}?H@&Xv9z2gC=_rl@xXFuiW zaq?g4Afh}Wy+(t9+*Ez@YQL$@E=VFEA~7o-?Cl0ZHJNGWpD<6&^kejBucMlrd=p*ZxV-@;hQ(q3&-%cXix zpQ@>FT%ShTW9E6`)aBgA@`>;~YppXFWAAmy-VNHI=7*HW%O)X0v*_EZ%x@YJ!l{Wd zD6PHwhL_%ij1Pg7Nn}-viLT$6>Ysp!Mfncoykop!c^WxoKp_J)a15Yy1jviBi4pFz zSNmX_VnSu~Zb78u7-GQ_Ujz=H9iq!OcY2Y+>%tJpdkHZ>kNP@Hfx%R3yz_n`kp=hb z7J&HqxELm?<+Z=PF+PK2AC07!fMxDB=+Ct_EBadOM^uq!qOWyCU2Hm+@h%v4p^3n=SHm%O0W zBcT001AQQ15COXEMtCWo@oQOX+?zP;=p>?itjh~nSJ#;YC5*s4Sr^!IPmWK^Y8imH zMi=UZ!g|(Y>||7c)50RXmAvhL7yt{kwl0IC>kG=5cCJW zD8Ibwm{Kkp!3PN~z`8<03yA#N`_q8_ST$@48;W6qPFrZJTG)B)$7rzNzd$qtvc_N( z%(bf#;pB(qFPJ=M!cS*#QK{`^319 z15>RJqUeROw!bA4TNM;{i(jMN^enaPWWxx=BDE?S?5;v}=47YPrm}6fJizvXU_V-A z!D0DjZ|5c4?S83MANko{RZw_Gzo1J_J_k_$N^)%5?R2|^orApcI}p2EMjd7Wf6dLy z^W@R>Clheqf|x`L(tB=)`fImh;V%ZDTg*E99OBkR-%mW3Gc*nud#F@kY&uLDH>b4v zqp(|AfuCT7pRONcZgEv5C6(Tj&qH|cgy7-*q6$f=U4)(kVPiJCUO|O_sjsb0#0?D~ z49+5xL&_Dk|H%q}r-sj78UH}Qg&PaoCBy7RT!-PwpihQojBfq8`9%@PmSM919WAVZ zV|_7EzwcS@NMyKR7DUb?VW(ltN}p18HdG`9t<&cgz*Y3$35k43%2bf)(>ShP&jP?Rccl*>kd7NzScEF( zQ2??ICjB5XzgpiA4emx4~)L+sj9QL?xJQ(iy2#E?H21E-^ej zec>9rFv0W^Y>GvfAc9mhXrloT*A7iV%oat%KIl`$^2eZzt%5v950K@(gphCJoInBP zQhaA<>jT=K1c~{QGd!y7ZnhD>wq+^PUb*kqZ8sHwFw6?T+p}}IH?g+~9b=uV>JyG# zgf?NhL6yW9CM5L6x$uKXM2OL$$L{BB4p=KlBvj7eWu(3tZAMI}lm9alIqJ@T8aI}r~wcWYzxbn&3vPtEV2RoX^Nxbz$ zV0_w0Xjuw9T;&2Or6@1*w+pF!6OgVO9`+))<8K;Tr!*hr<}VU{$H$l9#QV;E4*zc( zNNlfak__VgOQ$c2O3lcZFk|L#BDw#gtomK)ili<#yDvUyr|REFqRo)xj0A<~2do+u zuf@mAe!bdUwaxrXapGY}eNaes_So&6c~i*P&iB&`rB5mMUV+gM`xqE0HSRq8aY-f} zPZ_1EQr~r6+HB22o`YtQAVL2QR_k?EPO^pqg(Ank_ge&%BdbUtoiJ|hc)}VTY-(sI z+A&X7deq498e`3;C|cR}GM6Iob|xA!KXZ7H}YIl1-#DEPK!3h4nmQfbhd zy`qxFjLLN<0s3E9D|7*3CaqqY0vJ>fks{*L*<`Z_&o=M(ZO`_AGQv=}C#3Mwn$@GK za1G!j&<@QpNMd`ZVBgk6Aw3{N3-?pGzLq@afig1CaS{^~vsLH<2<^%Yf-~k&TC_DR z4T_xmf%)VPb)I`4VxKas zU=)U75rtfv8y%&Q!X}}>p|~tIHk0+YIuhfc}rt-&u8fVjI1ZU$W zqxlomBRiz7TVAA{y%#kw3`u;UIR`a@SC`8c2WfM8CPwb5p~WQqUQG2JrQ+?(n=v;$ z6*Dy;`(!yNkHB{}b0MwYdi;1g&mqkEB?8Pu|?ud?#!y z)OOFu%rWU_KP{1S7i7m4d$|48lVlj+~bTtrX>g!Ywr=;;ae)9<-+PRuFTGjO>wQT0Jo}t~Tn&ddqAy3XTE5=4= zSL;`OEK5sEw+nj_gV~~ZI&Pi_1>U!Uf4*``dbc?QK}q<*FX&cp7rMfYUm0 z1MV<*f4OI3EGxU6ukpi_g|Tia1&a!$aYc?d%#JOF*?IJhv8=cMWpy?Ch8Q-DNS&-U zPx$~$?dfK!)@O~1*U8ueEy3h95W5TUK<%GYWYREti%!q+9i||w{WxebXeHT73<=c z|B$L(LBwv{I~pMExy3T?VdZFVGVtSvsTaA)dE;kDk_*8L$o8lvW7vj%8NDE;8l!q= zsZ<@6%juq@s!ibRnR3iIt@O0Ze*0v+lUmCLqzlGA=$lDqT5>P6O= z#hBC)$L)=WrK+@#4gJ8pi{bInqCV!(TGGAxJkvA56lCja?yDQAcU#~2IjwnB%t!l= zQ`{6fmYJz5LlB}tCc|EkQ%xERGH-SGT!HEdB^CB;x z)qRn8kuFUc>EtzpgNq9?=Yz%!-?^D6#xD`jz=XJy{`=AE5-8CR7M+F}lfsa3BbDj- zzGh<5tQ}~=N&enE5|JYMPY)kpnf65YH9v^-_D=pR8c!k7jn439yW0Eq3uX3-S){j3 z;(>CBb}FBEm`SI$+|k`cYMJ+(x%0u~>#ojW;6(hc!xEu`Gjo1lyS#o=4Sq#F^Gf6m zL$JjtD2cC%-qeId^Q#t@!?Rqd{c`8w ztd#FakUyF$lVMzBYIpn5%$dvMe6FU3j9ZwA-_^pN#q1!oB-?l{@R@8B8~9wGRYXJg zm*^eXldJ5$=*Lbh2 zn|aISYLsJ4%pT!;F*YVFshzJ^sq}z5nyefxsSRy^2#?=ajKz!oMBj(Qwa_6pfnl=s zo=LsIlcmnt@&$SNgDlC|Z`K*c>_WvP9NX+~Dk=>pbR2i5=@9ZDk4PW=EW&J(?qKs^ zUAhVakMf*Ro_ixD7PB;3K9IGLM&x!9Abxq9;o_Sq+llyc1-HoUHjKb>t~%vl!>fHA z-KW%L0z>k3Ot!(AIlJj}q~Wx4+N-WnCywVS?$41q_HgWgPZ;k+YnflDP@p-y95 zBC@j-W4g^k4bg=l#QKf3-}|JV=x_0mpLg7 zvIS@~yza}L$W_lZL}-gZZCaig$bpqWRKUaeEVA(_ib0npO{AuNHKR&L)_e9Q9rB!> zzQG+nS0M*BV>`Qq(X60%>uah*Sa(se82{$c)Z=iL@bTkE ze#jz2{f(re3-oztEX#RZo5Lr!zT;~7ipf@qoG@4qi=m0&V2iy3@r~MgjY?+LNZZ{<(=$seShu5RL+c zco?tF=;EeRr^6z@Wbxovq;C2nzio6CwBk#7bh<-5QIE_H&+0xLizJ97i@>?67gON7 z(ODhtL^b&2l5!HS%2gGtp`!Ioo$a|u0tqG#<^M`vq*# zHz%{}=uIa#37I|^F(t|YfifEF#y{YwIM=Z-XSokki=(p0-4@#}*iy;Ii7o8e{D;zM8N9 z`t_@Nzc^>pr43zu-T^W{H|s4X2i-w1w5rAJPo5YLRbSb?>?#~JmLVO;XhC{}hleT* z&HwHMGW@6Q&TW?-JyOn9j`ml$@q6!Pm?E<2o%WFVsXtGJuevbudx(QC^I}TV{kwMz zgCv(cofF8B`^=QkT~m{X%1n}r@&nNt8MKA|n}J=9!^&kjSaS@*b3Z{fc_DG7iO-Dx z_Vqcc$%@4GgA6Rwq3hPwj)E9(yupMyzN!~OjJkQ|gKRY1jdACsJ$M7ik+lP7O~=_- zREipppFEjzd;3V|C^8F9L#^WV-fBk~OVIliDW08{hfI`0P?td-GMP$WkbZu!HV#5M zUVjV-K?*kB30vWLXGC0b-kz>6J=`%;mFngdoL~24)7Uh&219ldwYX;>-HFu>qpqkX zCm%1Xxk*VlscUR2fm@nA*`1l9O`5ATgP*vsQnFvN4C6(2^*-iDHE|dOInm0uL?#)= zq=w~ekD8@<6Z=Bja~p-53rZnIo%DC%I#M;{kMI$Cg?`oJHuE7=NmxA8BNt~(O2$lj zg@M!mzO5W;m-Y)e&2`QF^2lHQ@jy5zm~cL%&h?3zM0}*8!+oSLB)SK-BS*#VjGnSS zxRH65w-YLorcx){72%_CY9&0EqDrs+`4+70o;^kEcPd847`4=DwkubV?gi6pbAI?3 zl~P*DOiQf#p^?!yUBGva@1Dk>#QyEGqT|Lh3$>G>x{L0oa@i4hx+WU4+EftFlFLvoRz`^9M{5+~SzA+_|f`a1k zmuQQted`!SYsV8((teKTq#Lz-sTB0|^rJ`EzPVl=_|EDs*-c!yzMZUVu8yXoDck%UTIt1lFD;kAJQ`6ICq+np9BhpoXn zhudkN;=2F=zA7rR2~cKql;mkWLO)&Yg!CUE)njE^s3JGQ^@C}bpx}7NYoB;!S^C>E z{Nn~FBoL=y7iFKq#=)>7k|G+25J*O5KIO)Ii;_gzDj<$%$7G~f&C9%hk zAG0R;P+vbqUGJ9`w4Uht)o^RDQQ7yYdRr?U^A+siMdXg@V5V5G(wZD722y?s%#@#R zq{47tS3B49JHetSR`w2i%V<_)*;gb8E81P-jVwsH?1MOddAs5g83CT^6rE*(>&z0A zUSqQfGw*$62NQzB^m9(GsSVNJ=Aj)cqWR1^ge6ngr1553>FJg+#y}$%ml%t?F|-cb zxk+t5XCQ**E<2gxKiMayRVjJ|opE!BPN4R@KiC-v6gWacAafO9B2LP>JKvq{2aycL z)EX>=At})pPc3i<((v!)wlBYva3fDTd~j2P<1#+cVDLk1en`+OL9w-Qa_8qiRX_ho zouBScWc~e``F>v}Qm~rsGjZeB2H-i;2qj1i7T{?S>=wv;ZQfU>eqUVP*?+UY&$*YZ z7Jqo#V%9%X?!f1wbEj*7AqGDPf}lq7Aj^b3Ei-cZIm=Q_P-FyC)0R#ME*>vd$tuB`7!?9O>||#Ks9EXuC-p`P z%#>N5p}=gDII*kE9}8Qz(=mH%R(#sIaWMvqCOjNQoZ@DJfm5J7aGU~4IW60# zgFaKxJm`nlfuY@Ko|jv1PC=ZX){SAiIx|uFRHR$Sdv&zE7V74CsY27AI-7+|($7uR zcNZ?S#m;!!q+frwoB{L6Z5N|4`HscpoItp*7X70jR$F)00?SH6Sy!9LnECixI8{61 zNr}p)C+}L3a&nC-lWx+j>w4zI)mBhc#ab*{&DVU6op;p-iA?;zib*6ctjz{95lzl& zsNZ~aszz^uB+N1#*(8paNO{*=_jM}|v^?QWme_#Ya*gQ}$!@*@k?rul+Qc`r|EGm2 z{o1br@HCc(Bs6MetbCQA<#ze1o^4$shUpsD7bF`s7NZDY13lVp()or(MAWib7nF(5 zhhG6n?Lbaf^g`cZxBPXbHlMVgg1O+%!&ha!p1aIU!KX^-d{*n2gqDOy8&|KWlII0_ z=B%SP`Va!Y95vmwNYp-B%cGbB-7y{TY@OArPRJ4gHM%AS3zp@7yJvvj*wA6}!)qmp z-as(pJX_Tzje6RJu1pQK(^H$QG@2O4z_2YcHThAQFUOI2u)UaTTy4OL((CdI_0@zW zl6Al{$@QxS3H|(j(Aa;tQw^#O+=0}u289=5kXZerUEuuUPp3CmSAMpTlJk?3-{?no zhZiNX-dmE%FJ*=n3PUhT3XonL3|!)7n(3O zA84p^F*a{hoNh2As&ldI8BJ(yjgsLH#btQy`s$Vaqtp9_x+~-J4o|k56~_zio!QWu zwV!xi0~)0Qi0tsiy?U}Vi-wD@79(ITibUF-@@ITQ-&{|Lw!mDVp@f2r?%#k4{o}aU zy178Oh`7F;P1q7+Uso@hQ7JsT<44zMLid=tv8y0I`TK9rQ?pm%1qdL!{0`5AtFCY!O?vk;fuWa^O z+||`JyD89#kh9Bmz!AmAeAG-hr`&y{=s=i|ONdcvLfQO_x+@94R-b#=uz*^HF$qv1 zbYGf~>5U^lnXEJu4LNC(idt>$H*r`iMa~2DT@2d;LXx=>RjiJ9 zN%7$3UBaI{@_)H-H#zl1yGY(&AJ!I~Fknj77ViTrq7zp%Q+=8i`jH1a6d84O}z2Pzo26vCZ_>qPEDE#6aWXUjQ+j~}B- zl%r9=Z5F;Mj-~13l=4+-=col?y8lNDKy5C&v>VWM z^1jhz&76bh;P_jT%auH|e)!={GQ(-5w=h44O{bcKqLQxw$<1gWkXw3!dJ4Y|PcRpj z$#eM37WebDEbG;W|DIJT@kOVncg~hS*)S%*piU^@ip9`~_i$1L@dhfJ;?U{5$1RdW zb3!vxbbW;YF!J)}X0VUI-k%GU$(t!P%guPB*ocjb`x?Z;JoPI5+ze`)$%jek^a!*j z%q47xaLm+rtZTuC&*lD82>i3X6d9=z`Qbgq_ObgZZ=D2w|5w?y5b@f6wfMUlOpCps zZ2$ksZ-E0nm4%Ce5%n$As$F-~b7It%`n^}zNOWPD2 zlYLP9JKq_Q*UQ5s~Hj}gb+S;t&{#4l$(a@e@)a@@HAWr zy#7|w0^y?IiXX$z2Y)6%O6~778T>b@Y78M8=EVpP8Tu*GW4Otk8ohu&2ktKTuXXFL zlY~?9)7VOqLnww>hvy3~ouF#|z9{zf&jKd?_ZJd>`A+y%67<%P#a&LU^odW}C}Xky zvA8w2{~n?YCfpq>Hw4!9K)*wiHLecsk{$ospKCwn{qInaa^gF~#@&Q~|A2y+Ge+TP zcSP6#%l`j;cp5A(U;S?w&musq2xrRTlSy^z0?1xVz0?I!-W}GWLlLDvtsrEPyWmIy*lbrd%+t2-1KSE3leeuf4 zWPZ;*4dnmqv>-Y-G$e1>V#v;=tqBZZDWWJO0)+7oc?UWDc`#vYjBEvqmZz%xWYi=6 zgv%(%+rJBa0KT+XAs={s z|F>D$E3+(`FAAnv`dX;MbHR={&_b7V_D&dr*6;IR_G?>16^x6j7#r9s7|q|OPe(uG#fs^_>JyfGN=r0>4_`RY?*3<4J(>9b-WJ&GIKDZ4 zsSoOH&!rY!^`7GPOGZY0{htN-eD`ajV(QDDFp)AXD1eGIi=G{p5aWomG#*(bh_2$FOqhr^g3+f#-A9-HEl-q9aeQgI(& zlHTRk!*I6< zK#)jN3VCltQ(bNDsfonBRxI6{DMwvaMEAj*eNdmc83q9~H1VR9hVU42ga^!phc&eCRy{%hmi7@`Y<7%AE3V^mZ(|M8x_QO zy@%?ACQ)MwK%4;H_nBJQ6*f!?H=aUFIB*=k!{0Dqe;}qH$zs@g(;t%Ca+Ol$h=7wh zf`|c^H4Kdyu=l+cU>2d%9T5C?D&wYxu1CTA-~py>pQRpkDQgfb`06LI&&u4Ibjc?l zDH*VRr|b_26zkb(p6i+fqUe3|sQ3S)h3yJnIgvKH9_X zk3pf3{p~M~V;p={noZLzVNP7&tKd6eMjV)9DI`#4(bAqA-ZZu6z__fr6aKLfk@mkW zr2ZR$L;xolY#3ZzDvUHt0$chZ1?Ta| zL#oI4&Xarn~@rrzksJXMtS8eO3?lSQ|30|yhy*uviMNX$8=@&(}G$_+N-=y`3`yC@e=LiWo}S3UMA;*iRlgL0-7$omeoMH{c4TMwE&M5o!rT8OA2@_!X5!?im}Ir9(|iPu zBX{2W^8}Fno7Z2MCvd=cY^A%jxp0!3UU5Fuzy*kJ)63SaLCQ__`tc ziu=X9!=MMJnYi0o@MH58d=^5U)$_N74Njx*e{R1tSi}bWd4!e>_B{fy(SArvPc>Kc4MEvoIV;Vnfp6lQS}Dj~^ZZ~t_$JDvz1}PEx!)ru>Hqse z>-F1pef~Xf6#CLPjHmx=`u=@~0x|UOjsItBfLB`P|G1xj|Mlk&ML+$2{N(?6BN7Ge z@A>}sEXsO+=QIDlkqMUp-Gj8F+wd)-B;-Uf@B>K92N2(Jo}?F8C2$KtydVDk?En0+ zMgh(fps1o}n=AURMH-GSMc@fHS5P^E0ps7n=ARMMF8&fF5&pkd`}=q(xc|Rja?4*+ z{Xdt5ga7|LJIFbksUL5{M50u*3Aa7n$HTB3SiF7GEc&uu#}ez@m8hEe!Ofpl{CkB! z7O80323z;Odf`j085!E~+5epDe?IBf`vs-%|Mf;>rsw~^SNi90_hnu^ug?$W`Tzj* zQP362$WSX)^5f(yKmYDH_4(a&t(^d%=GTNr1tp`X#Xc&287=m~77N9}lpw{CP2{?j z6%i51HIy%tbdrpscWQM5=#t^uaKLTtvG{nQR(JNW)Fv^f5Hl=px)oqGamk919f8 z@%A{>+Th}7RbBuxN$mtmdwY2}zi9B`#)`fb$QD`4Z`6^B$MQOa0a03@D&u_r+pD}c z-BAU?Kwu(ztiunyE1)n^qD&wfCHjcE|z>3Z(ox_B?RS}|tQNDFP9ElH;X%$gFW*cYQ2(yS2+(DtzV58ug*v{z8bA+> zT8(~MFPa&-5`tvi<;^|7#2omz`HC#q;9T711aL@KM|CAUz#;bWqbF2mf=_JDL+rOX zEfb!rXEtdMSEwXFnAR()z>_)vz%k5!agz}3d4E(#pTzeS1fnSYvV-|KKG;iuCwsE& z3BYV~S<6DjFB<{=G#WqN9=7D@kFOrppLXtbb#Ux(uFjSC^h8?}*oKDjwDw*sJa9sT zfods?x>Y)D`vKW^JQtfEZ8(mFM^P9Xh=`05K%_~R8mt(qfQWRJ5<1ce-HL*M zBot{0Do6(<6sfTRhTa6}ASLwBLkLN}ebAYC-hX}ndcU*Q%)%t+oPGAb@9QqtwG-Oi z;Fk)?;8DI7iY6=*5y1jdQc}${AeKq1T@vnCh$T#U=!QVu_^u|PG8CgPIK?;N8)uGc z0b+e`f0?tkZ}9gdZ~LyiqkOG%BoWlwtH6x27n-qFfp27X)+Iq_JbZps0zK3c%3y}mrdC<`EL{+suM-~$1Dhr=QM((vIK65L-^fEJqxe?Oy!m@^Hg_)VQ~gOqCPm38Ma~7EC|7a9r;GRgJQJ2A@~O z>A{v!R+lujRzK|o(K+XOJuD3n7M)_aLEw%2#FeuUt@HZQO3Yk8Ap(%E@9!;$S@L>w zW~O`(bD{)3aFm<1Q?zz&IyKqkhu0H|MooV%d-|rcW$zNyzsYc)mtsYXJ@lQ5S-tJ870Dssd zc!~1*Vn&Wh3wD@MHOGcKsTeyEQL}rblXEy77_Ec%#ri*me-(xR$PLc?6Hq2z*9d=y zprCgMHHLRWPfcpkX0V(*%#B+O@r5t*86ZtYjlW>u0Ao$GOn&+D8_H0)2rw~z_nO#> zRha3{wlT}eYqK{|KoD||m~UD)VmXg?9+2(xnmSY*#By0%t`&PJBT&DduuM?w6qW)4 z3&38ZobW&e0QF>jt%4eKs0fW7HEvsfNRzYbV5K~`P?Y$7Jz-)$u}A^Mq8@Usq9_8k zr)3>y5WKvYpCB_GE-Tm&9q+LqEr86w;dXoCI$c(DVrr zmrmeyQok`Ib$@PP^;*|)G!md8jww6BJBQG5j~+c5UjhmbTsd`5UEnGoz?M_mpvL(H zQt8(h6@I7q1`>Uh0jTTLWa{({SDqh{S&RTel}6Jmd%)%jXgwx`^_RQIC|G%MAtdRi z%;?v4>t}zH?sE9?2&hv=UY7D@4S!HPc%_3#v<2t5@^?iTA%gJ&=wORAfikOhnJf37 zrH24jt7<>ER0P0vHrEs1Vil|!R{J(KHqwr?oOGR}yWOLwS?=(C7q>6mqQ7*PH?ai4 z`ntwYCV;8hUYujGpL@T|1ME(gT&RNzt(h9Mk+buDNL?J-nY7gYRm!2JkOslp@~20C zrvGaZS^pHN4FZ6wz5sfzhWU1U4Mthopz-{J=&QgR%!;!eZnf^*^mZsPTN|T3uUZd0 z86x1s2ge7D*u_h1NH=?mM|_?G$3t0z{XZQa8^Q?VnfnZ8V4qH_By`Ed)AL zpq^6zrNk&SnSdI|QT&aSK!GZYXi84q+`50}WaYf3Wpd5a#ivijCREMAR6|Y)t$%Tu zl_20O`U5l{>)*O{45(Ey!EXrM$TE-fIC>UD(2qEaev|6Edqoq(veJ!-W zb3g?Cg+{{~gQKR!YB2x+48WfNIWKh8sBV?}$Te~YH3Ea`FfZExUa`^LSWZrScA@d~ z1gbVXVPwi$FU^NhcO%a<6(BUA(O%4($rpJ{Uj$Gl*6bbNGe7b+qGGu&6QN&lF(YjP zaHk#}o|QK(8jSNU0;;CB+FBF@{xMLC*foa>I&ekQ)z&Ugy}Kam(4GXyb~bT6%N4+B zqbG-We{7KZ1X_ZoNBhrbnDL+1N@#v;^H18=Ao?#dcThV{L2}8?S@}G(FE8sg(vR~4 z8ZPHXVcays@w?NJwkiOauYslwlE8tqM z;SAJQLpK|TK~cQ{5@3L|rEX@M9#{xCg;FY#v+sD|DOnyR6JVhZ5(u6aaX?xCsxuW> zR!gz3<;0RQQ_?82(aMB;Ry{nC*dh&d3XqO1z<2(3>jIzirYE1f`}@QpjfTB~ znpf;-=<~ElG87y{>W<4RKhY{AifYk~vi0dtJ;RTPG$1W1Aet)5#aHvmZVzZ#9xC9h zKYMa!oHfw9c5P%jpdhmu)hJ?`=NG^HhpclSW`QA*$#6hrnxxzv!;Db;=`M@0E2CBS-vms zJb?<+rL;#wqU((+b5Mj9s=0Gp1ufsn@r0=KIYa8bF-EJc((EY6Vl=7D1kaxitXCJX zT#p_<&H#Q=hd{5;!V)*T8=*4xyf1LF)}fHY(NT=^X6WVDB}6fDVu0K2b_G0}ECR5E zx~MfFsmP1gex!(eM;N1vNrNE6XbK>xi*i5Mjz22{fz7H96P zR^2-XGTH<7I$(xB%smOP4*_49Sdk?P5rF53qk#LDL#vR@@7caxfxv~^N+#t^v=evR z7LdRz`OIHQ=CJs{2*-)x5W?S6dTKTUS)07%HTtPGCtR`a2c+^_~rc!EIdJa~kA zwUJZ^$#!rT0lne_w)()2W|C?RTG0cznXRs8lAi4)UkF}f+g2Q!>ox|qg8X3#K-R)F zc<~A_ynWOId@p8H8J{Il?>+nNfSMmSt%7a`f+Q$d@$345-#7RW+6`r0`}t_H8hk;{ z9GU+jxaEM+qJe)JG7+oPZI1!5>SWEH8F_5ED}; zZYoR+`A;#(62LZum9|{NEc1N398U;7TjtHAt21Ny<3y}tW+^<)8?Eu38DyHt3`})o zrvE(HD3N|V8i>P_dlP4Yq+sgibN^YHle`MzhTuNRZ+dpGf)RBztpItvtwU=S9H`o& zg`!43cP1?Zb;=)SQ}PYo$OHZML)1{B^*`cCK!(_XQhefo?R|fBt+WGe>xHb72fEnK z!meC8ste8J5fw?DM7`O=$|$F3z_*@Ttmv}vxUU_g9$c5+V;K3}&AZG1r(`8DK+892OKxYWT}P~ z$)~=~uysKT8(*J!+-h~6dk67q{27z*_cB~4I^z=9-2eo?r8ma*?%lg}&dsNEJ$^Z& z@~YlQRb!Yz`nC1o3F)ax`d)T+Eji{Tp`i#MX8k-%2u^pYmnn+dokkJt$xy8E9@})L z@M%VnTSvoBy7&P_(cIAc`KK#dv0}Bh3IkvIJ&ghQeUv3$1=aR-hX{NLXpn#jINP<| zxj*U=bpQNcFXG|vKNfz}9O1rw>KxmT1ncST&!D@JnZA0Sf&G&QcH~1ynX9L!Ef;Ku z-*Nc}X)F3bB~aV^&=){zYipnEuM7|tjTeK`A?a%Tjazb#-DjJZQu|BcgLdMFPx8?9 zpA7caq^#|T=HQJj*AcYs0}Vk?%=|oJ4ODo&)t+Xh5uOCh#B|Ih!$`OOBR}YDNMufT z-WUDmXloE1Me532_vyTM9K70m#@k=S9+2+Zn1(iemf&rWT&IvC-> z%Wa}JwmuFBjkg^^yW7I$E^+V9=tu&~46O)uW=FR>z4QgC$9*-iB$hpmEB$}9t8!N#Z^ z`3@b+eovwTlYo$*Y19k!<@mFAdiA#atp(uF-hKLh)W^UyVWdJX=n#X4HaK+%LXdQ4 zkv*$B?EVeyex+D8#qNuM|56c;vjN)NH{U z>Bz_Jpw-cNqSdWd62sKb^Lr*+|K*DZtH%q7o{xwa$m-d|ELQ@-M&@yLcFtx`hn}eX z6PjaJd4Uph|AnL`Ep2U^mQ|#ASBB!))nVT2qs|a)GjZ)z%k92U2R!{t9PBO3n}gSB zml(|d5&V~tVlLLT5HL6H74NRugWKtPDqA!kdYtS~&8N{QtK(OEY-KuV!yu77c=R1Cj93c&dV7l zvGJBYPRQwgg7TWD@{QIE8eUIN?k3oG(dVNgu**T3OtwWVu6}zZW(AbOD-lOTG(oGt zuC1AR(B!T8HbT?10YPJruPc`ZT%yCrs)7B#h|2Ufs7bjm{@m^VwC$PVNFU7EE;eE* z4Cd@vP{$ZX_GESbm9_@y$K>Kc;aJ?Q!LRbMw3#>SCczaz!M=#25#-F{5n_f>rfbpr zE*wXGdgt04e#08bX!axZw<^A86JR$A4H3Q%r&zs}ltrb+&5#jFI&%7fM8lsO51jwp zaWGEs+68@{BI=*LZyvr1-Ea1!XjjA4w7<08K7VlZ@|mK8J4|ekKDx**J{VgdOJl@* zj`rw~b-{QhjjvS{c&;@t$|-cTs4=D!M_w5y{=+*65%lIhr8c=^)d5egYh+zNSJNm- zPd6mjM&L4E)kX58e&Xi%#wfGI&dkj0$?v^K$nSLfn0A#_y&Gmm+>f@*?kseYorgavgo zhEkJ(<~n|R^7%A+dGyrov0>(dkgnSkt~p{WGxxUhnz#J5%J82d+SCru$0it?`L$W4 zmwR6(=<`=4zkh=eJLWbOu=G~idb4={T&3@)hweAcz4PaW$>Xo>9I{LZc9S^X!fz!Z zD&mHS-#f>cXdNs6^G#Y}rndSB~MMJB*=g-rxV6-fDO9c{{jU{l~s7wd)&?9AhQ?1|X% zb~sg#_MzAvmS*d}Sg64De9hdkH?L|_X~ja>vu^b{&)S7gemx7Sym8r1RKeL3ti|dw z!l<2@f}@)~`^g%rWTJ|D;HQml;*Z>24xw)s*PSFM2NkTukFgfsn#KL4vrMgYJ#);= zjuuxm5S|=l4QzetB{_yxA$n_KyBrk{fz<+KIM!{^}2~_ z^DE_b!a65r^_}muJW1^y>jq=JA<5jU% z4tl^)&{!O}`a+deLqkJ2j?Fa3!4T1?s$i*qj@kU37$;Z57!<1R4sffEPn3C^>Ayaw z&2aWmV=jiE$!n}hXkx~qha_JTCo6a-pNmqOq#N^pq$?huWgK)H@92zfmih8T-aZ(O zMh91osVUCHu5?zD4VqIpVD_W&NDntm%Su+OW|0%-;1w;%dOn`Mv?8XyQdzc_x(O$Z zC>HWz%oA;TX?cnYB-L!yH7*#}(XzMe>1$5dK;M?xM_tSUdI07Xk{Oe}_(L3KKW1la zG*KiIEqSak&l#V(jwrei5LjKl#;)V8WK^$fv2PvEq;*}Tu;&ljqWJJqZ?1AZ=Wip& zdQHg|(h>Ks^g2nZVMB&|ojz>{nYkoP7@L-4nb*hIUvp1= zp=N2hsUXL(Eon`m?=)l2{)QZ<{GO(1Sm@2POPES*-u2d$H<>kmETRFZ<+-#PN0|3CKR@01yTU*t#oD1S{xrGj zcnh^K=4PJrn5;7_?M{P10DsffwI)Rb>3i+7osb#4&Z_F#0keOD|Q88>-ZreGPYMno(m>>i7YoA+$Eq99=qc~1Sy4P#?6wVo-> zUyXR3R@(Eb9yKA?E#io)XEJ*Re42Of9&0Qtc3ekn0&u(^?>z9bou>^|_~7u3#>U2# zS%kR}=CIXpFe77&xv|r8db)lxG665Sxi-7}xifk)ZN4UXMOP{BLL`At$*18yBP4;i zKR^^QXd4nqfT>?fO|ilI&xGiC+>I%Mmj2yS0HbZokvbhHHP4y^8`5c;9ifligB%e9 zI8{8_Dn&EE2_u!QdY>@|Pp%zyf!Xi8x<5p5Cw(q;W~Lmk*k17Zbf&rAB_+wBl1~B6 zFW1qjV@Hohy5aJ3+ub%-D+<|M1~n+r-=49}znJz8)H~@}mto>EzozwKpM73#tFj`? ze{tc#()XU;zu5SE{q+e|w1yB5I~HS~?#KMBtR@oo(2JVXBa=8I?579MggyzY_eY0BdP|VzAh&4 z7TaO-OB*9ufvQ9$J9Vzvw)csL|A6IxYeCKgU`7_<0d`Eh>K|ZI+8U0smdaqVVaf*m z>cyifGZRR89S^tmLpwe`D3?Qq!F%4`iF^mpY4TZEVa`G zJhpZq8p(#4N4lbvXj{8$Oo&xg7KT?uuUlC7>6seJPF!?aS<;|nvMkMP!TRnlvEZCb zo~J6M@5&CXt5~Us@a&vGaXiCaWx=kpsxf-J$1`~HYENa=q%Pr1c zY(ubXZgS9Auq2ZThKIL=6*oS}B+d6Rf)%D3i92t!;!;JhLN-lPF=)zs&&tovFVfx( z>E)9w`claFJ1ghdv6dr-P+F;@EtzG@7c8y8$M8PQFy#F?^>0X|b* z6wRn@~8W%Q5;hNjy{SbQ+5p20g!TmpkswWGpxt*;FW^t zO#5e$v)xJ;pE@uN6RW@_>IF@_PKSlom8+31IG7V=xidR(FUFVPZzks|H83Y5BiLZI za_eK!9U+DJGgUl6$*EK=*8K#rt{ULhIi7(&M&B>aQ;odkMtr8S&|Ed=?hL%#o=-n& z^Mk(0{<&Ce3vbG@2g{37ym^>Xaf&;|!^Y9kaq>76uw)882n-M1>wIm?qrCZLbvR(Q zJZZXSkuVsX_(rcf&E6zUFc+t)j5n} zI~VNMF+R*ds?B5n$rGvL?LWVQ3>20oc#n-keOBLZSNlK(m*8%g?9iG+;BPC+N7lj7 zYNTGId<60Ej(7jzMXZml4m;%rt}>rK=!@@Ph#$s<3|>_DAx9<=z`V37p}8<{Y+Xna zGr%pCRn73f;4(JUZ}-u*?5)L>D|<0JBBkcsd?)9IPs9QwV;wis*H4rwsFLAjOrfqc zLJ`-aNe$656+=1N6}-A);rUasCp|AO&mNtYkyB96(o0l4!>XcmKj;IYPlkJN`JTU6 zxz}FI(V2Fq#I1#&W(Fp`!39ge|HfMrQhL*Sj)M`Wc+c%n^a`Vpzq3@nr^zKdmsq$4 zZj`L@o;#DuP1QdNdw0D7V~(|X<3G72MZ$+4W&`sQ8vi-+CoI3d9_cuf?JIKgPni85 zJ(&)?_Qb_CLkEPeM*xN~cEc3Lbqd&eiuF3pJyqDywdlK#;{4BKUT;&wdUVPzIt_*8 z_HRuuC5;e7u=@%#(OlAYUEfZW^iQIxk;eNRlNo+tDd>sR-8zyVUsKxI7QTh51sqKo zfNhpg$ehi-Mik=E8g1A^xSS7hG0cd>TTvm_Lg(>_b7}k>cBNhsU3cXLqcQ zH<8$$67kBwy_n{HDDXFjR2Y8Rc*8lM-}YnpSf?63DTJdueg+R`8jvJ)8`5L_`Jyo*aD+gh+WwV_s2a2t}i;`TC z%o89bdH3{~>T-48o=T92XEDI{yL#3g^-X{Mx=6q0*6V;)vF=yapElC>jvX(djPD&Y zPz~_;v|-R#&<0Z3i~v^ZsN&rOofW3?7j{QPufuSP`$Vb(@mAO&_|D_jQ+z$B+r!oD z$5Eo9{iu(EAxO%+kECflRNuVu?XPOV%OIGwLp**o7v0h)dtS!B#t)3jxe0;Lzp;D)g@p`VI~HkAF^P#ZcUs*w+*2(QJ(lx7MM=bFSJKT<`+A z-`=ClC&~L|KSFV;z0xg)%v`&E!KIqQI+rlKb~)aBlNU_DJ&Q_eo@Z47o-?vNd*!F% z#)iz~akG#&;vVzEmfu7`sNp;^Pbu$=0ZTj9Lp9q$RwB)+iukL7@RAr8+Lb+p8id0a+ z5?K8cOZ}b%kZ~%|-22mNwBRC;*`{vzI~@TNlpgEM+jjmj+Z_#ZOw>p-mReaGOlOKr+s;A_EV+I zyVfD^nvnA|<12*vQ}tX>mICHI!J67H#9w2)A=Lm3yLmcc7zb*~xW9TI(6$I7-cbn& zatuTUBd~0z=Ww&}M5ojn&#A)J22esKfPo7UIbdye-q$>Q0lp@BdSNsoenX=ssN-he zuLaJqBp^pn>uIGCZU9(VtIaO16iiGV&wz7gmd31SA7RCsgGNGS0TIs4IfnKm#FcbgWK{#)&(0=|u(OS~ za^qu?l9I|D=p>-STpSOJN_3`tj^YYh}z#kHjf$Vb>Ehw^M`gJ}u+2myz7ps(6 z1?YpM;ll$e=h35awE5jV>0QE-H9{hbVUro;*+F|~sIPDGz=qv* zD-++PIP|7RS|>Pvd3iY{m^MFMGu~m6cd1@zm>*`}31UVn6f?|UjO+cXY}B>hf~?GY zDrsDJtxH&#<`z@*@%0?DiP(PP)~ZqFYBRxV0ty+LYk(eKZ5s2aAGxr*1Z3Ja0NhBR zChc+V83tV>FoeXM922XkW{?N9s;%Far!R4^S6LZ-&r_imhV82(656AWA3kgvYa)Xh z2f;KYY@sGQt@Lu)NyXV5q8%f$^vnh6G^wl6fs#bUdzD)t4`p{8-fX$5NbjR}7poK!2OI_~L;n)SXd$7-m!A7L;is z<7HXp)ZKdzTeaFWpwNqu9xr|Dh-0)KW;Mkk5AUl}7;@}?-0~lB()hD6&*eMH+<|(6 zBnbRH3n~$;vgPA~*Y?QP%}S~zV>y^tQiYXVmk1Uf4UZMlL1*O($zYfsCYZpy+QOp( zhca*dB6Tfax*Ydp5g|(Qe04dn7;E zz{FxxF)5aML4FujLpqHYdj6)K*IuTF)tx%jNa0s1y2Fv1t*939+W-6kJ7S+;(+Nij z(eyCw$O5e*4a|aI({A;>L7Sv3C@=7qugNQ2-z=XQLM2zbud^qwN;o_7$*&ebIoIx? zSzK}f=yAD!FDaTaofW?!Z;w<1$Qtz{`yG!evZi|UZTZhaJ%^OXTvP8~`DP4TR?j-8 z41!jLB4fEfqWe63TKJ8}>VjDpjd|yLNq3_WRppI4=rQ^j88Q7DV#>##TZ4G3>}ztG zY_6PsCX#>^dfq77is-eW4|)#@(iTG~N1nTZG)F|zR|`aj(|P#ux+Z#XojcO!n)Lf$ zDYyMnpuwItm3Yl%S4=-Pkib*eDMhl#CekJ&;hb{TAkP?$*IjOemkIGCk3R#yU)%c^ z(q#JXj_YES{VX>QMlI(u=)ZZlba2k|vKUjVqlNoY!pWwUft_0a8e)u6)?t zN1oPT-9*W>>Wa^OmAG|`zlv_hK?kRQs&wP(3ND@9!Q(Y6Fx^cshEh*=;BJcZ-v(uZ z`pBMnAm)ggIMfq^&FJgTfadTmv?FUNxDuWqRDPZmrt=|$ z3ilPFEd)-c;?n)qJYk_flM_LwHAgX|J64_pR(o%?AQ?4-!m@8Ss7?em@Ed}ZQGdmY zQhuYfeBx0$px_mu4bHccuL)*lJ(dv7Q+2N^JO;O9vPNW-~L|Zo6^bdx7 zA5XlazcL!&hU$3a4%*BBD0)9oOVK}H1thQfC%X|0`;0a+gY0!V2R%Kv%f7&+fB*>6I=7rIoXE!vPwvGcc*_tSslYKHy^I^E2!o^Za^R0Pr4cM*9v3I~7#k zG1S-tvv-6lm~qxjVy7_a&2Q9o`pLl?I@u#dD#V^hwz0?LVz;&ueBJ9aqD``;eUqgOXi zf;K9HZ9L{w*-=@RMaU8ldTfHc(#XuTonH&N-ga3T)QKLgI>zIY#;JG!!$;-MiHZ0B1pruK0eN1OGH(X(p{ z0W=G}bdZ+GpV?V_*-%&yl$yOqYZ3!oE2OCdUba|^Tx+s~;&j!gl|18CoCRvk8Fa~I zKq0aJynm}uBL)uTP~98rTezP8h*Mc&NnP^ICzEVe_B7!!;~&r0a=x0tS67Kuv9=1Y&#ELOa@}{y^qZHNcR*6ysiKu^U}%WVvo<62ey${z%HVaUPaT*ImM&tYS z2=8k>C$%P5THo5t#8xEJi8-DLf*wQOoPKS)VQq&}Vr_=~XE=puI=@yU#?r zrI+qqZ&S1);>RQ5EG_9%q_17LTm1qg1HhRS_5Cqtl{#*W9CA(i(B}ADZyA|=2^QHc zLi)LqYNSMYTWYdC+J!r3=9j_^6T1tcNPl_M|?`;!Dr)3u^o2McM#a5@~F{}ixCcSXF% z^1x*Gg+gS_*8Id0_`U(UmFePPiwGA8g8}A{)2!Jh!|zUs>aaeB6)I6$L!7!9+*i?+J~Y6= zO;jek#tG=DNn(YgTKfyDUmpBo)e_)F#E}lyO%O^MalL^2C;ia{6^)0Fd&MHc%cp>`zI3nOb{`s})QVgoaI z3gzTU)5ro%mre<<`)8m0tp$J;%V#*IcvpzQTuec#Q1nTtngIUO;@b@K)Pb`q0R(&E_4|XkHYluDHY;!iVYC2Xm~u3e{sTT0 zD*uT@0Bs(T@4i1Fp93%18|CEYuCxs*On`Er6|`Ap{Ko?nQHw7O>H&1Rc4Fre(ovXa zf-TU%)p=i`!C=qC)rdH!1c{Q`6btJO=ogg0Td-n3Nfm}YNSzP@AgoUOFl1FBTKDrN zMFy`D4hijqoe58Z5Xh?QF&As8@F zc3+xHb+25pjln`A1)rG(VgYdbQt(aDz|vTn()oaD2S?hp4t^c&TE09m5Lm02sA#>Z zLas*qjNDplO|Ydt+~k(xgFXfZ={k`CkqgC&m$0jP%eQ5>AFHhakcHzE-@zBvrMJX; zEM(se)%8ja1a!t_7ZgZb+xR_LJ~8*AKnj(+an*Loptr;I|K#XlP!x zk6ZsSG9q|T46H;heSNe4++`&9pSyfi zfyl{Mm2M3XYyE7jPTpRp&^Dp<6;VwT>h}ZkK1uP^uLocBhJ0`PNaOe~lNv~)LCm8B zaSpq4GX(=$3bKDc&uzkY7k|eBMz`uWOX4%*nan)IDq;0kIUh1tpdc75Hmp5&w+LG!C$8=#lkL<(pfE z((VI404r89x2(9@gR+IVE0AT$2ybHw43>ob_q0fET(B(Ej|1`9wQUQu1Z@ky1g8c? zoj(=fJ@xOZ-u-uZa_^D7xuNAbkYslAW_-Ty4^fR2FI|5?HOL769$9!c#Owb$(nMB= zf}=rx{xy)C4@{^02u}!Fvc>K*ct&zVUQ!JvUgyt*7Af-$wc0!`Cg_IHph#v6hhBgz3xeP6BRu2ve+}QIrdgL(s}^Pp(Jj=nA8)(1!4%y7 zG)PH*ouQuVxkV`y^Zq@>X_p(ce%r#Y_rd>@!vC4}->-q6mHyj+f4@?E{2!8^%l2`%mcYGe`gH{5GY$xbadrLT}j_Bd5u`jg*=|W%K(w0Lueau>%R| zvnhqfddoL3;#%=gsDo)<{_oE?#~~N470vY21;Ei~NcvawwjW6FpBV=yn3ihEP!8LP zVgfUtZliG8_!FXgT}^p8?u%3k^nUmHwe-=rxD4bj*$Cjcb^uQ? zfLl6!G;UriT;FeGWR#tA_QTRi``Wj9^s26dp{H|_ z~LDF6%hpvYu zCc=<@PV<&cY{KtIv^^KMx7Wr|)pJvrX6F90ZI4CLcuio2dnph%Om~2fT=%k_uqqW? z*Y@zi2x}(nnE^d$=*;cIG)fEOY@)~L>ylTv=sC??yT8t-6nh%76TzZeVNq86Gy35t zuH*m5S{)yM2@m^j$TG$VM8xi{@lwYd8r-~jbLNY|yxS?JZbLdLkD4s!vhc?5;l%jjFz@xfdA3sp>vB+<2};B?s5X44^|yBDgL zmRESz%an;*{@HGMFH)(9oJY@YUH4_sI-qEkZLMDYUzYjtwOcZr+-(>lNs>U?aS3y5 zh4fRruT}U^OrYn9Xx*Qji}nGPQc>$c;aD(`oFc|uPq|i!%Fmii-qLfd0Qy>a5~|0N z#kT#=57c<@PX$nVJ2N7xHD5m6t#4@fL#2{|V?)&%^_}kp)vSVpX3~;73R0u3(&Q>V7t^XXKX)QA;$?&4 zW?Rk)hlKw~>ZmR=Pvpk)$x}z>P9%=U7>w@-ExaW|$_LzD2(Wtmc;{xl{-&8VN~C&O+ojB&CQz@}=5`v;t% zp!P1=vU<>VZJg|l>$#QromIfv_`$=OPzY5@wrwjfK9k+_1Y>=Glb!&a#ZpnTYg{Z~H21^sq)%HMPjAj!( zwJ~hJN+Fo(o`0|qjs!kA0c@+NHQs5m#*7&YVq>|VIuT^Au}a5b>So?xhGw%laWdN| zxv}q`Q^$eQ(PntaX#$dgf)dp#iU{Tty-`DqJ;wuRUvF*9mzit?Zv5%#?W!P@>&oBg zsm{C3e5$ZKyEAxOBn7F}9m!4^wy*ZA2WIbDQ&cl_0ECaWB&4g3fmHP7IJ{q&R{X2K zp7uDg2T|}l)VA$wF34#B%N^&$@-qe9u;DbhMzONHH|gD*%_;j~q459PjH|Q%gYIdO zexuVGo=YE@JW^W|dzvY2?+txuw)hi}baHMW1IluX(SO5G6mnVp@5lHjxlW7Y1Nh-jNjQ;z^@ir=#smkl_=cf`TO#ugPd z{PWGU3r@hp69GOYLDc%he4m`>MHsB+r!cZ5H=z2MN%iHWHNA&$J1Uf{+!>Z`71YLr6KV%8n1L&V871tiqH_j0)rP)JVPo)_DOy{ncIS{h7=vp(Kcgb)Z8$r zV2*?A=54Ti`30w&fS+DfTzlX=5YP{0+@LfODiG{h%ZV^yyI>c+HH05!lZ*&9MM zBh0W6jkv932NyJb3gyXKx(Ff24KA!yinWW=PonSoAU0m!xGB*jqXI;qr@4ivE%X=_ zik{FILLa9A!gRG%&*KipNE5X8pu?U=4d|)Nr59g9{_t=TNEOKS$_v;xx{8Rw0EzEV z(eW}m7|BtX$=nD8JB3(qGag)74ye(^{K_q3+t~FGNl?-8 zbW~EoJ~#|SD6sipJX9?+9gqQ#$U1b-ObqCq4^HaiQ*9{lLN4)x(9MePCZX;d98Vno zDl||iM&bv^g&BV(R5et|{@!j4&M7qA8(Ll{TrN#YMP607$MVT`X;J-)^x^ThUv;+F z>AL5~6A`Jt9w)bEBM(>-NH_Z@Udl)`L+bD6Bp|3$-^Kz{RnI6bkC5M3FbkaVOh!Ah z#o;rf!7yZH4yzMby}RTF=2c?I*c{7%e*fDb(vfTNI037oK>pP$DprTYr9fh=@c&Ui zG8bOwQ5pR5kg0Qhu0{Iy7!oB&X}{4|{sQQKxyK69JTY-(8A=6QLzq_8dl*{u>qnrB z5Fn~rvWk?Ukj^z79i0kbh7pqO;#yvmL?CJ~(AahRAc)!j4<)MDqniI=WEVj>bo~Ul zn}h0F61@Ja;bm~ozC51J%!xq-OA>1+Sk+KSuL)|sf-M`QN?fjrkOVCjuusUK=+=%OUpRlOIIz`5yjnOTD*rXLSmmo^p!&v zE70x$=mdUF#tV&(Z->{4$xsX@y=f>`rMG4 zpmY}2w!8%=@y})x6KoRTGQadBus#leNzHDxaB>r>r5!0Dc@Y46=uJvpBl86}&Og0N zs%W~qAJwyy-a=4gtYp(#4Wj{Nd1+f)yIfrcRAuXdR11%3H=9Nm-$u!GRTW4DVtCc^ zwt_{l4|8Q4K|bDp8#~lX$--*JKJ9h}g)9wFx(4;%Xdx#}Q7dy$?Y-K9AOpV7cB7Hy z+D7%n1j?iD;sWMAsZf7BEMItiAL2w6f0mKuH|g|jjg#Nx$oRf2)fqyA>8v9zLmy}* znnur-aLWKm zGHs#1B%n1gWW{AUB8aoqf0#9TksL6EOJ4bUi7K(Wx!W65w@pBVb!6Tj_A#OR8iZ`o z+sMXa_Ny1%_5@Of1&3Vgc#qpGZ-*+HHXA0j+X>Bl7N*5#jmtEsUf#l%li!NU0O2R( z7wlD(O#Jf(zK3iREwd6W-O6)u%uFi-4DTofP&DS=x_7Y7RGijPRrc7vTuGHwW`Ii^ za4|VYpdOlm1R^S|uU{a&-mJ^Vuz1(*yhQZseP!TH$mLw?J?T9?b#}nGHJ%K_2e{Ro zEv(*X`h%kAH2ECpN37A)iS-`6iS?PR>4bEuPo;v+h!S+kEgD8f1}O5l><1x|N95oE zeIq$hX!}F~W6WVi<<-{g{|t>~_pXL)5U>0U2q-^lob4GnSI<8Inoy({;J+X3{1S^b zkZuC8P%X#;6+<2)m4Cd9Y?W}-*uv>P6_S32Z?X*Wof2YwC9qJ*5-ks7j4RkIqgzC0 zSyO7pates&qlgmUuHX3cYqdsHlaXt4qFsxav7PN?OXB3&=4wFI+GUs&oG@|CPbsIy zn=A6Xe(>$X7W2c5Ud6rgk9;pE@O9zzSZ)hJok+L+Xn}V2rc(h&0b2U zCx7WajGSK>+^g$8I@fvfs>(=XtG_2}fp2J5waIQJ{OMY^I6Ynj?^Q-JKXsw(*w7of z%F;aBwscy$7TFGq-ceww(z>yO;%P(iNp2R2dT%}ESabY)v{S;)ycxU{fs=1@e`al^ zs`IAXl!=VPb(D`Ay;;aJRb`c%LcEC!ev{dm^_?!CXb1+)G`t(C`%&|+0F`;h{WXr} zYkxoEIM17(CI=7FH;BT&P z_i;jcdBqO)9HJF|i%~|@Hs1KyieOU*h53 zAIqxsLSm7}M1%?edPM=;k{L|j`6+?6+@1e)R?IY%fgfH`RY{B(ZZp)k}AuTE!cFj?!J(3Gy zL!&bpD<}HP9yU7#|6~p-+gVeFtG@_a4BL!O9{v#E*C$>-@-cb8U*SRO#Y=OgPp)0` z4_UV@3NQ6_Hh1y)oZ{9!=e1>TQ?z_$V_@aky411#vH3T!Puyx6wZ6}e;$`$61bta} zTr^o<9tesjKlYKg(R}J_o6X0X9v*zZ0p1quv_1}rD?&}*D)+s;o$X>!TZK(6S z#te1)d$%71HQX#f7LHn7FSapZvs-swZg`n!AZax5I3Xvd@VZpdhONM*I_=9>)!i1#>O$QK(=uR#V6?L594x56`YsoquqnBG zL@a5XHZY)iXnt%K|8S3ZUuV`DeO%I9wh-MJ^E?fI-Rv$S#R^fPq6QJ76+B^bBKQl7D$TT;#UUM`2)7>QKg zLSkpC!q6;oVe4`J@v%5ka%n2vutZnDza;z8;ykZ=-=&8;P1c(eRO6=+w2CB<9hor0sNz^_~?SMd#bHSvqug-(B*X zFg@VF8vPUW_`duIrnoDPJU78p-bTK?5V5|oNxpWoW;Q+~;r3`=NYp@8=gQ&ZH8csZ znq&C1(rLuiH&UNYTfHZ051DL?ywTU@>1)nwMxahAaUQ$$kZT?opYAsa+Kil&)|zpW zkdt$x{XAQ=H`btudzAG2RbR()u4_U;K|w%3NeMx^y9`hf7?f@hq(n-(K~w|;1f*L^rMtT%hmh`;?yhf-KF|Am z-*5gvgyGJ)=bp3o+H0+SFU>GAXUqIKT0L%`Re2@TVyUZGYxgLs~jJDFrMKUIhf?JRfS{sp`xzCskF2 zzmfE*PMD72a|vnY^Qd6?;9qkef-VunPsB-`wx$pqP3qZKX>Inc>g7H9 zjqZH?uNNRT`Dj!-R7vopP=$Iob*6oE0vWFOA>?dJ zmmcTyA`1f&3nA&j2eW-|rr&5h&oja#$rR~$VqnAokEu1~s8kBTbNkpbT5K@8{52(l zmaC_ygGyqEb)sBR;w*;nzmxGdsD$_#OG&QI^5L2bc&!CK`_Cd(hzO((Xl%z~lqgyr z5|}vL!mLmbJ?I-a=MADZLVO}>SIoUT%!;ME&2fwgqTcYqLf(^52gA<1|$Mw16`E(~OJV7GHh1o^l<>?Yr&RCH z%;C39D2EUTAhhO`ozS^YJXQ_S{ATe+|>G?qyXPEGEbyr240cBL#gE@E5XJqwOhc{bYcVqc z5%)B?hHbhi1irADx%&~Z0HXWoeol$yE#?tMOyCK)boI=@Tm3ZkwVio6LP?39VEUz` z=oQ8R6Z$IE#{fQ5f&)HLHcCFR(Hm4LaBSrskkF+*Uy(0R3pnm%3-tAKecI@4)thQV z2XD_9BqUgg6+I<=dGN4v2Ee@)SngWz8H9zI5t(ok!yhU+zK?ePC)c3nBHao-U-a0< zerl3hQulH=W&sy*ukb^aDX~PJ=fClGj2mpH^q#;oVR1^Mo*NS*{XPxpAaKnCkIPox zE!`Ypy-$sug}T=ayzmH#C_BsNC!?DD!&zkl$Bshz7NeVN4z2f71oJ9C#2c)}hLx6; zF`6L=q@(92T}@TcFuN0_Tw*#r-drG-BRU$rb5FL4jW^pQ&uN=l0R*7()-g-x=GIP0 z>j*9K=lG~Q-Jb!w0>>iNXbnDbTG7ut>4A|={t@m=tqBbc>syP*VH6WP*nq6(2KHEB z8iV>IAXeODR`J_beyx};ZFXuihnR7orIkOiYZWl!g8cup-+VQfB5-Z8HGy0ux~T$> zVlkKEe=mA^<#z8MY2O8M3Hw^JeB%eA;ejO*7*zIJvs?m+*xgu;qkR78B-+>wdQ&$TEN7W^hWG^&YLvqQ^@T4y|vz^FMzVw~|4=6#W!f zV?`o+*)ctEb@q3#Tc+-oSm;OFRE18}rR^;>oQQkop%jwwcVS<-p3FZjD6Q~ev?D9Y ze;wG4Zp_)-7}>N#%HGxQzj*Yr*|9iNJ4ElrsewSY&Rlc9|LRD7_-zC1=Q+cgw&bE- znZq{f2c4gO5e>3q=e}$@Fxn!`=x+kd>NC$}u-amj$6TbFESnlZ8SedW?f?6lauqA_ z@+Mgt#z>B*nn-3SZp+Os@lJd-Oxp%qLUW405VPuy^dFbYY8a>2D9~uLZq1_qMiajj zt={8tEthgA?tSII3qc=-3aF<{4IMMp>IHo%o!HXx98(?EAMMPfWo>suBV#JC4Hh%$ z<-KT`+LR?TiC`su(phu7wN;y$wUW41T3RYd!vZIr>#~w_x_2TBB|{Xx#2E#kGDNEs zJ)6c!pJ*3_h#rZ@S={=o?JoU(iU^KaF8@>+=!UpGt9CM5=_sFp_}pXiYPL=4&19*c zPD4$i^-7?0{G&N_Vsi5KLISr>e%u#=>1RHVD8gG{ExkRh%@#zhFkyU(mH%%^b#7g% zzQl|{$w`TEs5^zxfw7JuAvXRmsI%QrEep>bf|&WuE&bzI&@Bc;Yx{+ry_Nk+0UE%hoC^-3^_Jp=9w z;hyQZ7Or!XXR-VXLkLdGwsg40&IO15{mZ?(SzXf6D^Njxv~`XnztHj{+Boca3guPI zH&I9~W+Y(nuKZzSeG%()Xd>I@KZ|ynKTi+9=~a7J1gm;M=x__EcOBY&Nyl429+Xm8 zee~pMxms=~R_BDEI`&V}p3qzV7EoGRK0+@LeDSTq;oa@tBRg8E_c29#`Mh;#*xnjL z>8u_X@vGp^pK3~3>hVd|c%Y5W9?LtZQNgIE-`*cn{Lz9G zoW#*aSbk_yUZlCzI=gaumo`ng-^vC)og$UpllQ<#&!Sko%8T_8!;okxh9L6Y4|klu zg}s=gnu&<_8jdkF?j-go8Lm^o*8NqwuIe=FE<~OJtLnXdjP#*E8;uLk5@i z<-KTyw1?Mmh&}3-od6FAd2Dl%tFX^3ZlnehQ3HrJMZkFA#V=y7tI^t$FRwk>`UrFuWUILguK|0)Io#Mlw8 z2tD@y1`K%_Hnp*@0{76D(W|_cRd%T_WuoujwGlIm#ack0#4HKr630-(%S6M%FhG+L zXya>9dg>Y|DeU*@Y42^$wTUlZTYdtG^2+&dtuH2a2SX!)bhE{X~TC`hiF9TZQZ z$VW&B)-zCxT{}A!@r!V0l7is=B04|JjNu2`AQWV~M{ivZTW`7#Is1LPJ3E=XQ^E0s zfXXPRq)f6m8<+y|m7b5@6(vzcVXUgY=dFTr!mAeF)jL?AU~@lV+3^s&-&Z26X%~{^ zpTQEK>F{cyO?!)ENJ>hI+o2cAYnV~1l@a3OBFh^aOPw40r|+Y4imlYx{f*^m1viai zBY~%zSW8_|{ojeT)cZ$wAyyh~?-$AAbWDa3rikQ7JS}FgCElSq$P{cOxA1MHQxf1d zGD|fOFV-6Mg`bJiys+1DA<}bK9k{sdS#GbT3#e2h?>>hf*7GZWKAR4HyRS!_ru%wZ zgiQoRVHs^uli%vu$-0EQ`b;&~D75xMv*MMwL}wf!V|a~~b#uqjZ2^IUn~N;8zN0k; zJPEc=-rv8MTGHLVhJ_^;`DE=e8_}&LL7^RzxeP;(Mi(5zp|grN>N}xC`GnF{pSid` zFON>VvBBXKLk1?)U^(C;>5=4R(v<_ceqe z6YHnG@anG+jr*6$vt2Ozs;1|;C`(_N?Qjxb(NtL3qV650K?f>s{L!7HiU5PP%6)Qc1WF~$`%eoQm3fXH|QpvU8xPKqt{t@=}blWfAt7|3%>-OZ%y9CNJ zqwCz};n5p=<6N9=I8banDjZ$7Hg}jJsXznB{4hwQSyL&VMVBUxeL|L`=1pt-$)u=g zA2h$E+c+;aBy~jb@*+eTgrmhq-IJ}!cly?);-!FJ|8rpPc3x&%mzlMY!FG$+8lDvs zIGW*n{`I91V~vaPR3;RYreEPKIR$-Tmn5ac=b(5hwHNZNjTwZlM7-c&d}|w<79KY&?pGbM=k-mk zs-?GX^PC8ZXdgvDxox3cQ(x4MKIUjk`B?n(9R`LGTS}u2+5NF2)EkFw<{R`l1w{;f zpFHi(VjP^V>b^l+-|)%LuW@|b`*W1rCIm|iDH&7}(CYgkN>k+P8@O;BR#OHe&=kmy zb`N|kIW@EF2YBr^k5ed27S2sJ-=KsV)My*a@HQ?1y`(kxl1!hMEJ2i-VYi&uW&IS` zRIMBt#XLyUGosYupB?W*EkQ*U?`XKqV79L{$D!~p)(HoWyS!>EMI{ojRK4m(ueEq- zvpHFusfg^5sx(5aMtZ4_o*#*afCYI+34+3{5R+W=qp|_cx^9WCz_&gbT>QO3|sCBmuF#Qsi=T7GQ;v+?x*Ucqfc3=1Pwp`x_eLy-YO6*S8k9| zJWVLJD|1{=QP*sWzJBYxU*BiK6Kr#&F1YY|iR5+q%J6t)~qZq3S z=zFqny)cAczdl*?S__nq?>&h^oudwPfClWl6j+^ZZF$ONxK9Dtjup-iszFjPLSfZo z4Q2Fwkd3Km%ZB6l=>k)R_9=Gx$*(D`o9*;tKB%TMcbp|^@v?mW>|{U7S@ zJ{uL1$(yVHk-R!~3U6DV-3@jF(Z;A>5XPpI)%WQm+hp>?0M*slRJDB5J$)41=zDTt zv))JpdQ|RfEw68PosRkkO}7yEfLRJ{!u4B^6rT*09g!j=j@4hU*+p^{AVXI+QjaUodtzKS}TP1BGWEu+FvP#M}7w>n*}DBT+-`2jeVe4S>FEE?db!=glSuLA{w2W8UN6q7=<-MMk)u=q68OM^p0|-y#)ji*< z)o$KbF-7h=X~BvHhGYKsbQNpViBOgJNl3Yz#wg7r>5fyRkIkElF8ZJfw^?cxcM0!) ziH2psgNzdo( zim}!~|Jlivd5uh#{7Gj0u8g*Oj4>miAw7VI`n4_r9XQ6?TG~qz_9W)QZgVLelJsT# z*;*5O0U6fPr#Ux#gP6GW*TkAykx96^W>@9q zBj@3SITj_>rj^5^MNWTp7kz|2Tt71s-0OIStz)#N{d+7PeY2fpTNB+%$q#IrJ2lrf zW9;QY*Vzxq=$P3!IFl8)@t3d~dSGjNQ)W@l&}5OMm039CHx0mcI_F|Jm7ZY11TNqM z{f)S$svb+e_Yo4IluiS#Vzwci!)7)?rVAkzG7Y>dD0{V}4bFt*BfL{|(B0c!2F{@T^Tt)3r+w6xm^dD|zqUAZb5 z9~+FxosNx-9nJZF_-#7YCLQJb^zE6T3n5R-b>51++6Epmx-^a?jVcC2TZc2%)td{q zu3=#t(}oDYAFpYLskgBL0;-tyZX2iJw6p6hle1hP5Cc&;9!UPC0`cmF1UJY!dZA@f zz2BfjTDs`U7^~h2QrBz{m^7Sv?}QMtc02xaZj?i}P0ZY!!8T#-$o?19n1-n~ciePc zcX~U|BH7#_4j;Qdadkn*6xU~brzlC(>9{(*=)+{4Dkh7khe9Fy8jsNeuNcx)H!9{2le zi8>G($jZiYsdB^{+a~P07VYA@rG3G11PEfa)eAKvDFkm2$!*}^KrCY*sQuv#njCZ$ z^R@0S*PIuljxMuqC-_s|rCMXVBD+E9j<+fU=n%vgE4@4ErPh1jh9gmnXVf(LkEq_~ zSt1gib*lKA_cTI8FZ+FgYE-}>h%smy0Ekw#)yQgm0!((4U@p<@Vve=K0IlbbFS~?# zOSk4a?rZ$qEw(K@4#hwHM^1$oFSZ7r1#u4sQ`6FhsECPs4G{kcf9FJnO5}YzGbDPH zxm0}|?r>Fp^y2d{a+;mqDJTWx-rS+_0Mcmem#|Otst~~nn(_6wGJTEAm#VnAp^(%0 zse`;4b$2{&YSf4eVpS!#lL!qt!6FV`Wvi!y?ks3;M&=;&>d(B>-Rja`+G$Q{RUJCr z9r^yt=Mwfrqkvi4{_D@af!zK;wTFBYikq+PVmsYyfxN(V5yhe(@W{p8coVy`)1nZ| zWYGMMHddfbTY#ZQre(COytg5GIwfMkC)UzkX3Edl{%&nOqN`Y}}*8qVDd92PyK}f=Q(K ztXwwclE?$B99gA|!S^_PI!Rh#8gsuCYxOVaTuOM{cAo&~;6S*-9{O!Dh9e;0AY#O_ zCEaCrIGZWW8YjWGZg)7CaC$!a_O-z4rB8+POcv`@O0H$%Q1&Kj8TPFx$RK^tjRSd% zXKnyVa~E-%J{)Q~kc|s~wZNfmn}eO5z4CdIu<{D;H?4UMQPrQ7O$UpXx;1SFeJ%OU zJ(+^!2J3)SphWlvsDvW8`02xJ#@_hw_|!t{XET$n@8zlYG(~^3ivH2Gi5b4Gvpj3sW~l*I}u@; zC8r|xmS=p3Oxq93mBUF9>bh>9=#U|>THt24!H~Q-&2|7px8e>eg3*ETRk$c@M*;ug zWhJ@bLKK)k{O;!MC|~zoA)SEEn6(Lzd`z}_spFF4EGV5#0w1WeCo5c9SQloE-O0>f z+e78LAWPQvF@Y3gQ(?~;CapTOAf(XfNfllUz@E=CnY}mvKFJV(_B$} z_(vmi9yneksrg*fPdh7XyQ0^h{rz$KR|IB1;Pf9Q_V`;Ph{WBk1Ry^QEZ)TXoi};K zPh2+;G&Yr>R@Lvfl8xDnx4&dti}UzH?QmenVlruvE2a>3={I1dfw<#fItTZR7VyU) z4w6EDY5oynz+0wBH(wb^WsbMYeZdp41*Zv7t;AV2%8xIy+Et`#GOZzkKt{YA7t?$ukn3^6fcn&D*$qZ(<+;wl8OMp9 z(ih7QCN-qa*_k3=Dh`+1Grb7DkRX3GnLw^Ax}paj|LFU5b@-ED3-yXhcZS@WBd#%Oq}@Lz zM^ml#^ZfY07Qla6*}eL;Bc;^s>~$=W8kI}l>$q3Qr7Iw+yg9MEZ8^x+`i|pqD*I;9;2NV2&^oxpej+KS7n$dZi0d9~F}!e}ou_%d2Cb-gCL!6oVac!{k`MGC`&`l(~J>%1VBwvVZQon9i) zQ8SGgmO2e4yu#p0K+D%K!9}lUElg+FK+n-Ip?z<=32 zG@=dBdUCLqC{ysvDE-m9C8ah~nc}E%6Fq!@X+WWmGuTLpUNJsjZ0MY^uvk~h9`9x_ z`;=mj+9NN=HBlzSzkB33AR2K%Lj(_q+GsJ~i!SE#zdTu8XDLHU@6u)0Uc=*GR$AJq z`8`G>R=hl6-BQUI3dFHWd!ah_9R?3F%buEF22g17r0lGq1d4)UK&@N-y_205Cf0=j z2BL^pp#&B75FL>I=Y4pnhiC@^z5wF(4*Vz_9_FTq({eugaCJ@ONOI^s>QL2G0an-nQ)akV@UWLjjBlN zvq?r~?)7#_(12X3e0q|QR@bn+AH6MeJiiGZuqPRTZjKo%EslnTg-DHhsBLc#)?fnU z<~1|xEe?Hz<0Tc#BrNQQlvt|ckm%wwYmXfE`A_P=YfXJs_UtB`dbkZEev2>1q5dW1 z6@J9_M{xp4+QpzhX3% zo9Z;X=2~+V7$06U7KLxuh^mj8mSTp0v)4z-GF!rO8j7nQNaMcz^@l#Kd@C&C_4P`H zM})|OlB-}G;idlqg=t^H#wF_o-5L(j&yG_mtWAW#HI9F|Q_#Xeze$or<8{kGe`a@Z zHu4zkC3L)kU*M0+hzL!bMXALC8S&P9`&5H;mv=d5yoQS$1n57B)Ok^i*6>W6hm?<1 z5m9W|ynH&v23yC!Pe36^_vg(;;YzpAZjm6WmM@8pIgi8wf5GvN+o#lvZPg?C9;m|0KeQ$8~9zuz<-6uC~e@2~pN-+`tst5I` z=lKQRGP@}FdDT9cwqTT88aXjYm>J$D8KL!JvsVKraN|U*GTe2iCB4@ktKLgH630{( zJtFpND7eTT)SL=Nz@>sJRVlU-PUWhhX$&eLLkUlS;6{|mp0HM^Ip)(yE zmv~4f5YRVj$Qs%z9w16T-hbWFy(D96%q3p;nogTVqDd^ z2M*#^$SfTrZx`5pHC{GjdS00F$i}&5!}!|zO^2Fhl+kwSR9Khe3=?@xN2Sx?v+v6> z&jVmU=n!LI4er8J9P|wb{|)Gfp+|}z3G6Sjl?}E@oCD(%+!0~I0jsfbDN+E_=4TJc zZ2*}S6t@+TaqBk|ayuHneQ0FenZW&dGuOphA1t;#NkK=Zn}5S7Vw*Y58?zTxbQN1_ zH7zBdTm{e%wbAVOn1VtH7?Sj$j*OMCdk;S=1EK?l(1no6w1q;AGG@SPyPN7<+~pnW zm!xDftB?X|sUPPq9@tTgmw0>jwOoOtC29`F#f8(?1$eNd{M;zbbkaD`W@}6u^ga<0 zHtBazz5mDB``a$^@dqsIe7C;W2G zu>It6-p6^n$nnNH5T%Wdr;AmToEZ%aY<3>pQ~35-&IaKd7vu2~>UFIO3O(fufX=h_);Bfv8jS{8FV&k4ut!;vSdNv`0def`@bTYe zU__=@o-}a8k;wK5Sb&pe);;`{msG8A5KZGS^x$%ilH*89GSlFv)J}|t1%qIMTS}YR9^~zVr@o$*gvbK z!Jgl?w8X%Y-QaOF5Pms8>WF?1a}M#!m6sF!aJ46)6ELx4qq|Xv)fQ{5zvlA6|1 zj8MX*oucal1kx)E`pmqf!G&wogcpXtf^C_zU>Q7>Rk~>);f!3^aTj&RE7Ec4TYv@y zyX;G`^UrG4V~`?_y#iCgyVek7=b#in<#oW(6E^H^8KibV?v7Ouz3G?Zu&f*m9n`RU zdOSmWK>#!Jpkkz$O{aY>?!(UE{fR?X=hyy@pL&ug_@(jL$VM`a(r5_TSeT3CN@34`i=lW)dSUL?NwJYFs2&1YXt=OSLAQ+V!T;4bh zgbONw>gOt6C;~qFsZ}KaucVPNPZKyOgP&r!*DK+NQD}O3Mf!OVrJzcelVOZgyx-3f zt8V08Gr>u*)htSiMC8l;(v3va6FCip-JLd5kZdIRd+q4eL8W<-R6J>}DdOn=>F(p? zU0pg>8Nx^Ifb{!q`^5>X;iD4VKIv&Rmu+vHE<;tV^bxkoV7#6Z&G zfE(F0|5ej1GkRXZ?io2gCma&PvC4iZ^5pjq^l-tuaA>q_oT(+)u&h1U4s8M(NO&3` zXT^0caLpy1J!i!COG^rsq*YMwu%9B?By#MZv{Ex4z2sY6_QgOr8=ltU zgL$WMbbVm~F-@4-8k~*>2(wAzi3PXINr;d?HGth;tFtnTX<;FII$h%;b*QMl!-#J) zyL`94VSRdL`5CB5Rhpx;BK(+&bZ^cjT2dV`(*gI~>;IqM%yC^|U9&fMZO zbW>-xY@3)CipW>(Q9hYMZ)ZdAvP@K`Q$&!HB;$JvUwT{?Y_JIM}rM%BJI*f|hf5Q^A#|$m{X? z1_4#`la0!@9ybxf)!7(6)QIjEYdN*Xvm`8S?Qm&(OjN56gF+45+p~dV^z?M>ZF zu|i#OiKCKFo=iuHV}eSZ0*uMm3!jNpi;A!P+kMKG2+Px{(xRJF^jNjL@Z$)`Dya>QFzuHJm}YC{HQ9Jpz_Qit(CI z8%De>WGXI5S=eaQ5*|2Ws(#Okbnb$vA{{S4|Az!}%R*zF7+^PAVdfC%Z}_EJDhPhH zZ*NkgrJZZUiu|wOC+nVIp|Dk*c=fpus@3Gk?(ol%)#SchM?9xst658PGojV-El|w@ z4un}1^RR%Ed$uclDgcNs&rL+I)P;O7M~9wyn`S~iUm;V;iMijISocEdpqE<;%$`XO zF~U#|hU+C9>O>qL8u5vJ6nAGmd`k~pVQ}UiCW3l)F1Sid(C#bXgm1~oR>1SRth)kd z6O6+#2$JtddZY^kcj(3n7#++Zw7+0iKg|zL*L(50dSpi8Kztu|igQU;dl}JH>gJ^c zI)TdxF7a=Kc0$-xCj_flG!jPACtb}zWY-(tNs%`2gzE~|| zQpmp+W>)jjfuv^6-31NhSOj0yD`Z#@xFltIv_f8|Vyj>@vF;AzrKI9)+0+V8xlDQT zVg3aKy53xI;t}1JudaLQdhth2C?NtL)LP-LJx(;{UIasS@K>i}rI8cBhJyyjO>6l? zJ1D432FW{}d}5fFPT+~MfHARcg{jRuAL;@IbxUec5M*0t(kTF zHJzxC!u7IHA9YbP+6w+0xk9x9*(S1GY7u{s${9=pJSvE6W3oFlM4c?B0uG#ejT;MZ zc1CH$3Rgz>dJCgep)!}}>DDY{MeYd-^BGeM>o2XT9ueX?7iS*%hT$4pt=48=^0%*3 z8XAGtBU^HAt{xAT6NfiOP%BEeVak$!&l-y3w`BYj7^n{l&lX8nI3zD4OFNVx;&@_I zBp9Tc)*-EN0Iup&P8$pn{wybj?-5@@=9zmy3iAtRjY;8yNRzj@k_WaZ?RS@tODs=! z67I#vZA%{jwXg$W5-c=|6)$AKfS_j`2$d6~X(ucU)_A^P@CN6rnP7bZPk{6Fi+2zh zk{TKi&HeZ}o)88}HC;6E&d_Q~yT-K}EzlS~1* z$z|CCnoz>CqY#zPO9vK}gD=i$@0vgz37t=v7Zhb|UDkSo1N2$9A(Dn1DGnd*&_Y1S z8yf8Fj7wW9@1CE{Yd!XGhbBkZzurA2DR$}ZV2S!lkEHpbb5&LHMdi z(a6`y_UI}b;r|l)2&OEiv*sT~{2^@HOT~9zu2E2$nVG~P6|i2dW%n0gZbWHHmHmcjdzzJU<+c{~Z7Px>$xnT` zJI)NL`yTJU>|1UkvHbHn2pFLe2Wr{&K(~-eo=P@KQ0-0Wj;*GDzsNXtNkiTrWyb^^ zB(YDvjX1AJVj%0&fl(>U9iubmziy$p{#x5-oi!c=xV8`3NzP8k2aNyCCsR)u@h!5f{kWM#LY)p0~R199Z(xNw`2vyl3V6m)BX*b-v*%~WHv|GPV6mnPqN z@Q(!dMGWon4nUip#@+=lGjj+?p4PS(h_tgpwx)Eqv%$?@BAm8O^H`$1FtHc8J2r)tV^~#NQk`y^M_nrpmBI z+?JA;3gCZ5rpxveRd~nQ*w1RvVmhbrqkG)`(2uK!?CkYQ{8G#{dFKY@49ZCa5dV-~1-L@ME`C17&hU)5 zDL^I=p{L%~-aamN`2bBITN)X7{73Pz^K(fx9f(Q(Th|JY6FES7Dj2nMoT;_Q$Y}uh zaO-y-6SX_{2O!Q0(QzW~(PkmqM$Qa;C)b<8YEK^{(OA?NGh z_uJZ(MK*lG_FNj#DKa5hL{J!wgqTB*YqNlIblw3n0L&yZv5}xAZ0w%C$E)%I=<_-Z`GX5nRoAT1O5 zR*S9Y3*KCG=m8b;e=6hsHvxHgdzIg3!ga&J(BvZS?xe7J&}|Izo!C(zXC^vNxk9}FcFN*(LXhVyoX#jLwSQ& zFVtJ#hOJg-KUJ_@mWW22JsCAW|7k~FaHg<4`kn{O-Gv)mk+9Ce{}c=0Zs%Z_=+tfh zlE8VHy$Hs?eg2Z%{dATUkd%7t4)Qw7?TMiXngdu!g+M6tPYa?01d0YGS=k@k%8t{iuZ?WxerbB9S=u3b%b~0SqFAmk$N>CB z(Ca|RxUfDAkJu{?sd;+UXKrdbDxU0mwBpu0)=iExLKr6jm3Pf`HC%SlyeK#_ zLR%}pp3+`xjn|&!xD@dnhL36r2lnifS-EZ6%4RJ)N$0JLIpJ9GGznyl+6O={jUvcn z;z^KvFZ{>IOO8ATpt-X)`9OZ-(zsCr5;sc1P7nxf8?duAl$Xr-Q1gCNDbEp-7`oPx>I{)OJoF=mBQsi@}(`S3` z$O`9XtA+>YB-LVe07V@Ef~5n+;0hzDs0iM!BwN^eN25Q`!ckDYQ%Dgu2MO? zv#>d>W#`X1@&!YeU1JGNYXngrjoVdg^h&OAk640x@0L=A74EaMECkgl=~XZonhMJa zC-x-gu+(1Cqq<6=|1UASpjCccGT9XM-OW1q(|$z@%>vzlQ!LN$G7j2+Mbq0Gioxb1 zXL34{l5;gJS5~nH#EwS}?lFM9;XbH+w}lLTXb;}va+98k>-_@V{$_)eCsK|4VAV~8 zs*Gt*U)eaFR-XvYv2ewwuYZ{jg$3Ub1YKe#5nAX;Icl~ww z!HPF`M4B-b!&jkb6L1CJU~5$xg&09a&LrCbllt!YstmN0S}d;8^W73LPSsxAINegK z=t>|oJ$p=xGA)0{N{hKbV9I&PK-{F4`}uKcr^AD^3xfiaqJSqLtbYB2I1`#n^9}vPaG#ef$SDmf8lVB9DI-E^T>ynZiM9X{~ud ze_3E}Na_OB?R5Zpv7j+@)SR(SFrDzYW`Sgg;I4(BUvBVU+e3zPXe#T5ZDqo>e%aBF#etgzwJ}=)L)hEjd zCC`0t>DqXl7k}ZCSws(1PZ^@>y4a9RX7Uhwv`hvz6?G#~Kv0cEZ&8 zbH5%9w-w#f`iT)L!K3m`+-3V7lpUYAlQ!pq&(a#%H|Ch4%1sQu*32Tp_{AF1*%pFp zs832P@6gZPu5rKM^Ja9j^m(#$>w@C5BW1aZqwuc08QKObb{w7}*eae3(+RmV#J()Q&HaBzeTV`$i`!v6hiSWRr9y;_RvS z0QJZ@y72wlSsyLYGx_%hAD)HVsLi|?W-eM1cf@eQ4g2&voY~y@?L3=g+(O)+{(R>2 zKq@r7J)})112S8SHwI{7^e=pi3 z1xv5N5_d`H4Kr1|&WkSK>q}(eu?dT6gqaTU9>WcEiFcb5j)*WMrkb9SafG}xpcUD? z-c4yDbu-Mib8rCaV9jzrYvsNbm3;@SZT(XzTd~h9LL{}vjl(sb(ViY1^*5m^7AeJM zMIS+r@_bwSR8QhrESL;XFY?x~k{f*FMM>(56Shkd(Oqs&x=YWVDE%B4)FCnkBgp6g zd$RW4!_&>Zdl`hrimB31HVAZi4uUZM9U?fg?fNNJDP|KV`)ds$9Xdj3S68p=l5yZy zoN9}oD7P0#8M)o} z@g9+J!_MaJH}lfP+1@fmBV8F)c4zg@!qLPnqnxdf`3!|D9UHWV599NW7t6S=OVn}R zx;9p3eYYMuR%K>@ML4iobS=2EGeD8@W?mzh(73_o?b~mP3Daq3iHzuD<=J)(jm#om z-1M=H>S)w=)^>7!dlF53$g_G$JcX%;ZbcXE&Cz3Ch=pH3L zP}0&KHyJ1ss5!NZU)VUP8*aKg!u9vf(_7EkJW& zEo|~nOk@lWbdn6cWXjTWSMwujHTQhgXph_aK`LBHPNz?K&nC$)`*Xb>;1CpHtV)RT z#-x)7vY^_RS3p}ycmitCHZhaoNR31Lhz6Oo?(>^S-G`NU{u)k{7CKd5FDNCh++SEN zyUlA&)zu|^VQ^6Qz>8p?=-B2K#m!%I9yNjq9!>8oWu>1GXAH_0;vP%cQ8v$A@U!cm zP)zXc2p@NERGW@A_4ADg^`#*7M%?#K1oNEu&fgzWkT9KX3te+2gzoHLMe*QI(HqI0 zNDOO|yzlwgynH&UgWS`M6#4k)M6{ZuokZx3ghvUo!?L3vb93*78s}&WxAfy0qZwQ_ znT)>9)}>w{?b5d&zZjNGlne_uIHZJf&;8HBg2mq1NBM;}1pC)X2)i-{%$qCuu<2a+ zEC$68dC$Jt5E~G_R-Upw{iq*y=ko_#2aHL~I8KJX>L)kD3>&sERL}@iUiqFQ9>Pr- zmdKtH+(LKtvrbjiEW_DFcQ2WarInU*xufoiO+#y~fOY8g-hu7pZu(8e!JIPu=vgPW$nGh?7!(bEdM?uDUt<+Wdh$#+B>W^OV(s-^=@1+ZC)kxl#`83h$Oo+8y!= z{wg$QqOn}--H;oNbH;DzV@Yz8Z4y^VdDd_yA|Q8?=Z1$#^%#*-5T;6mJL^m-zI|ZO zv(q-w)z#%Hs3#k{;4l9|$48Z;*)hKR%MA=ns!`gMdmlXTI<o_8XWyA|G-s`EUd<}rUbg!)LwMv=X@3-JDpEpRb8xVY zK-B3Q3g%mipn-@#9q_JchQvhl)3!SU`b30|xI*|F)(&Kk)qeqi^JnM$7i*ZvA)zPrcZqhprOWE+`n}qoUuG?L@D|2*=_7=sS`W zEEXVO6qNZqhJ}SD<7K=>A)|HMGwhZ`vKY4Gq-@R2TFd(n?x1~z{!~Khc#KD0N4G*v zGzm-SM`CJu^{{R@m5~u#-LQAXz600)>MYK~tJ55WFKY?(c6M^sJkQRL0g<9!Ay-6Q z_P>VV*36$UHC%N(?f%I%yfc?PnEOM?F+DymnFw-IFueuy^U;SV^7pJ&8bcIrk>Vh3 z%hinDBI+UfdMzq{dSRifz*t_c1@_7PS~`zP#T01x#y+s%F||^)x70Du;ViRXG9;8v z%M?mp+iXFoLX zlGxQ;Llc7c@>p$O*&@cfLWfeMBhWcE<_HMa@ixXkPM(Rt59;cFMVy|k^X%oAJ1sVK>g2`Ld3t@^H#Q#L*$Z36I!h{kFEJT3-AfzX+GW=+2H;ezzj z&Hkq($n#zunzw9YHj&J7<$@gdayMhFMNc=-(fG(q<~!dt&GPEH`Yqepj*b}Gu8MUm zKl`Z49&5D9NLgmPpOV$UQ|7$&*>rTwPHm(F3xPnOY~|zCb&X!soUhvOjYt!QicG^y zD~x7~`2z-f{xgvEtQ8bIYHC->e_i<~yTN}ty8#gGHiGJh{9(!id=}C>zZ4U{FYO)F zFA-Vea>u72zY+^L;Kz$y=cgR4nU$xKI1QR(Qq<)0fyrv5G zCf#2zFOBf@dhVMMl2A)rrN5KQQ*!d4w{WKV3tO@0D2!5Te&`}{AvlJW2406-jC%J5 z?sTBZgnU;6GWFvdR-5psI8-)aX&UJh+zbm;PniHegw;(Y2sHA59fulI^=_OyvrjsX zUwP$ACCVnVan2yg>wRy-{^Rphxs$HH{^Er(F!HoGkW!q=PgZ1^O+9j_#DSrBF}^3k zppf#T0MHFuw|$Xx>GgE9`}a^9AH7J(xtJ*5z^H8nnkGKHlhRlr=^t=Rr4`sZQ0 zQ~FZKcECu#i@E0ytWYAT{0MNi0p-=biG1$9z_)yWi)&n|M%>#v5;NGqNlt{~j@1`g%Q19%ChikvCh*e0T)&&I14T!y?m50%rm&l(MV3|a6Yw1+BUiVFK-C-iZg z&XA=`7XzchQBTf18Zbkcxn0Tkl&f?0#QC`N2au-g-Fg>!K>F3Ek;Z`r_s6(>MDl8; z-|C+kP1USq?qIFt{4guf9Ahpu_|6RhtucmHqF>p4W^P#NQ;kDaFL}Y^e9+Sf07bL1 zLT)I=E~}xVFy9DWTPMZU4(`$pp(=TgZgY>*x$*bKVXN7RvPQcVgPLK+*4cau*|9Yg zP}0Cv@4U>Y74BAu((Rgdk)_(Zcuxj)%CU&cYTJ#oGy%QhX{v5ZKaJS_> zyzceI*eul&i8G{dQfT`)G%2r^If*xURQYg%%8rYHAp|(5L+RPfc>UKXB3H>NuU2NL zU!7t!?gy8n48D_p&_H7C3EVj+Qx<&up~ANtLIa6KMJ%JtSCJKa5A`lEhA8TFCYs}Y z(AkR|1c%NfVq6jizO21WNO=*3iWj16BHiXf#$^n-MEEpIbcGQAG{!`X(u`G4##GYM z8g3}XryAa$mHLNqyPA4Gv0?cnQj_vLs_kPPa^SiLksieG?)DV8dIm4ZC*5qg2Jxr|RLTv%*tIuNJ=5kP8 zds;+sjwMvpdd%;+g!6M3+PUs=IfG&iAhO#ebN)lO&(#7`b-K@%IOgg)TU-fIwxrMu!h(5<>co)Q=S6O9J>FIX!Q(R~3xoM3vqJlN#IVu%iX z`+VrwM_*pJKVC*6u=rd%)3TcO#@VUV3n?T;H12y`;N7-0AHB89WzTd7>?|jD^LdW? z^&8fwl8XjjmaKKQFC%VYd7ZRgGS(Kkj^23#uRE%A--q~9zEUs)?_6Nz*8X+&()L8j z>g&4vn&%VD4yV(gk=P?&LnLQ~^jBM^Yo}7HR+H$u)m+79lVIF$%bzqCYZI#eY!KHc zDBr=oXgI#aIkndAE|B#Zzix1B4QD?G>I)X3?QE&a?7g0_ua_M2TVhaA#kieKWcaYz z{OUmJv_#iH*7vUIbOk@XcbvX^Jv@)gCjL$iUdGccj3>$m#K2&|5*NJB_H55qInj3~ zd&1Bf?eAuy*lY%TzQaOdgyg-R&EO;UhC@dZclTWM@1RZbu}%b$NmZ9&C+%rhC3E1czqF>#R>Zt7z=vkPg zNMhPWMCU77$gw0rBaYG^>MSbuauHxvWIQXc*`BFjYCZt^nFS<_=C1DVACu?HQzxiK z*14|gHYBlhl+9&ML4xl&&v{+MXQydKqmvG$N$V!GMMpS+D1Am#OZ!(kI#c~ENnnUTC zEfOqsP8{BG0SzNi7lnzxKknG0$5I58u^h=v|F9S#wiCQDz@FBpO?c+QNFOe^0>{id zoW$woi0EY6Q>{!BoS}7C^z`GjDd^wk>Th z8dNj_G9g74>Low`I3>38M@tu;q&r)SeXd@yW zH0gPkCDcMO(?}V&Rpdgb$l0raGxx=FgzwdRlRL8?e(WEjUsQPA)N{Lf}ATXnNw64fsG1c!V8!ZNwa9QOt%S!O1afd zG^jojVCAk8xCmx3T@<(NNZf)QkrKeg8ZTO;nN;fTKP1i6jN#de z<|P!(V$!=DwE6=PX-Wnii2AIS^f$Ap#DcEFfzPpG4e+r|hFbMxSZv3I7RK8GZM>;% zzF-v-Xr`)}t>*Je6tgvOg>C>(TeOywm1+`)Su+S-FyQk}BMA3!efTkb?}KJFCd(W^ zoChw9y1LHYa`#J0YSdkUIvlo{@W0p!9~Xc-0hzo#L`T_Xw{M}kFN<6s1sj5r&Q8Tt zTHvUsIgQD0@YxcjgeCMMrFcIb3KN8Bis@;cg4-ge-olV|vj%cI16HF$jE79>LMnzJ zC!s4*_;jl7zKvd!;d^HbgB;&j7^p(bGirHD6HY2V&J5PFD0Q#N#BT6*6@FJ+bojVE zbp#@z{6LwZykdE!MQk5yjw)e*($k8p(V4q1E5+8-LS?t2gAN>22XicZ655P_ePby? z!IQg15ZQDTLcMa=Ph7oro)%Fgx9(=Tk%(pzOBSJo`rf2JIck&!TY1*Xz&#WL1%;i; zj%2nr^p^N)DwDN6i)#j{?UGL>_A&d?T7KF{K*~4=HSoqjTjm6;QpK#Jg`+}mwy8$B zBe{%|&O1#Y5OuH2X#;vRz5%JZ*720Glm^v!Be65naQ2D91c&zvLRQ0jZYZ%KBjcW8 zQmi(;Po+KYxWCE*jExDC*u|849W+G1l@@;u&_g4f|s51lP^)OOA z6Y#xw^ca*kIYLLqL)7hAoPLULRzk`8?0~h5AXom3d|L@dO0=?V#Z0yS!Bs_J_z^Fq zBz`Ds&}bA^|5coBHTi+tyOn1D*T3RTn6Gm$lDUZFin4DO=DPcCiN-gpiN`cEI z!VZ&2Q-q8oXM`_Qy~W2i#b$s3)z#O`IozgZCvjy$@%TIo{HuAB@&$GNmIU$uME0C4 zMptD{gbN9l4vjlt2hC_+oeEc3uq(blg^+=@0I2L?1F?pT9Et4vJy0)Z-Z@&mlQ@93 zAMEUT;2*CDM7d=JdW)c5@0~vd4H*L?B1|Ak1veyC!UPX{Y4`I-0ug;kOqN4ZHdr08 zc7#curB}?Xk8e3#h9!S5OQ|e!T&qS7N(1qhLHqkTOM=F9H+L$-$-(?#v)RtgImEA0 z3CRuVne0A03u-h?3E02_Jl*4-zkaghPGC0pTJJbdmx2K8M|U7?JYdUe9EPfB%`7n23M9at0O+)3Y~~RG?V5 zY?sTIYD#`dGdEIp2@nXLoOM~*X~n=?1AM=Y#-T#3-%W2#9169-*1LvUjO+}Vic>Oy zA2Qh8Yf&b4-8=I6rJJ&*+Yr$UFd`WQ@0!#b>PXBb+C#G`c+@#t*k=YCh@o z=GtEVczi#Wp&zUmcH_SLP#({O$I+{b8A^zXbI~tOhjL#lH>9vle|(t`7hli z#}=B=$-VSLMM~n6W3)YsHZ)idtPkEie4;pY%*vy|w)e0{t0MYy=%kt;wbf+^D!y<) zb?z;-i;%SNu0~<|fMgy&)HmPc?f8Db4`2*ppMb>zO?wetd9k)XOWR&k(|A3LQe1+y zKa@%~RPps}@<-FeMEp;7pD$kh{XMgdja}XRyh)d+CO=0NKc436NAqk}toPI`VT>O) zLb#ILd#;@V%ue)uw6wIVJ$D}>@Q*C@&n;G@zN5T%civ0ShvQ}werSg@OjMojmE5EWpr z6|S~izUFc1Qe!b|IYd-)s|=D|4QB@Iizn9w(yYbY+t+hGy?%{ci?{PS?}UIo&jgIp zu<7_`d*!*%2qKkqeT!KJwdu0GZK7I@SN+L%*~_*(h$bqDeII5IvN#=x1BcbnF3~SG z$Ymp0Rkkd{yPFC4P3#~vhts>d!~qr33@WTN4}rNWyLCkd^o#L^i{g0wYc$Xs?ZW^K z2$>!-DJO59Xew08Vb?`xag^iGFLnDKIFKKQTa|2W-+K$A{va^C;5avhRx#T+Zx!CK ze2^DAAnug^n26xbQh4q(g%357aWH%=Kq zO_gAbTW)SbcD`I`7-rOueAx`Hc78Fs4>1Q{)gI}x8TWoqQ^!WW@7X*q&sSo5)QH)K zHotLk$cN^Mr8mM0pCZ6z<>5A!ZvDZKx3+4)sYz{Z&>&AV zF0FF7Eyccm4&9eIJv1x?L7{jJI-visw_F9H-J$^}bco9&*^u@Xf2NiZRJcA#IZG|G zK}%rvCJT}y8^8xH96HL4J7mqbkO=c5!gN@scIR(2Dk}9HJ~zl?aobCezRkSEqNuJU z;!iO0{4rQW(yKBC2bI`v1Vj&SAR)>K?&0U37hls)@PfA5utn>1*Imns`C#k>qCa(S{SmJ3sOsE{8h}UZQ}hv1vzJ2H+(^KekEMHGcZ$;;V@=dsY)DFRDlz1Fz|Hfk)!1 zbO#VHq_5k34x5nm0hE#TERHIf0741OH@&xde#dw8^yOU{1f%lDu zkKJ@z>w~1q?E+I&RHrXi06F2BuE$#YL#gx?;U~{4sx>)c3J~yVs@y&UeE5z%lcbV0 z9GaiD?^o2*&L%OvuM}@eO4p%*JNe7MLla5b9IUGkr8!K0`dk`_0;{mDmGy4pt?W<9 z1R)A-q|kJ^Qn})SyT8mDR;W~yCCW~$AGJu4VKb(r(xJXgVyN_!wCC|Z*S5E1CXXK( zYO^wD!l3$Z4qi|}gX=x16jl^PT&QI7wOC&A(qwC?R;}ykCe+1RYo#wVH}l3sK1E|a ziKp7bHR`dnb3oD_P@o{gw>Wz-&!+c%$hGkkuv(mXb(1}r8->A%F>wh#lm-WD_u-Hd zdHte>2CmRx1!WL3FE-ZKUz~zU9~6^ofi<8K+8KATa+WnWv;IMsN)8Y}L5k&damXlW zuMY>p)ozZon$!?I&&$N@3f8XxRO}WV5Pw?h$#x&K+~etuR|DEFQpgY&#I1`FN7_QS z!k3k~y#Q~57?LjofQOMfzJ7n(j0Gu$CSCM6s1D>R!~7GksWI$hN?$-som#6)FP)OM z?mVRw39CZ~&~F^ixhTLbF~QAzf~+Glg)s*&0YQqJMnkcgqy_6&d% zSx{Kv1(1&KhA!qj{s6q;V+sdhB_0H6Uvqr=5o+U~`CXWKf2SVVK+#TRqvHy7_B!^=u>(V~wVh0SRpMTN#|6#!*l9zRw&@v=R`b+OS#B9pB_ z#q3*H%n85S-dYfv3+h73vlmVC&n7`6=?UoQZRftCqL)JzrKKo5yc0WGk~4rAyeJbT zR)m)XaNN21Pw|qKK8q8g>RATU$qKGWL5|~<@-6)@pR=CtO$_OYpICPTI2{6WnZ|h= zUu7!v^7Pj)wm*X5Y%D5I^G|eYdHSD3CIR>!E@^84C}q98WM1f%GA?~%fXmIHTl2Hf z!eHPzsMLpN0!9U(0=9>NthZ~eM-0UGG`t2-zF}62cAPwkx zx-Y6jxaId0pT6hw65=)bN2CHCa$5c%Cb!c_?`OZ7;zypV;B3+L<7QHrRgTtvg3n(tWM~c~Wn`>jj>A%!7{5nL8oqc~ObO=fYL(^B4s2bdNLT)><-1 z$6lqXZSeHpbj*bVa5~|%79%;e_3pMF810bti7utDB?>!jAz=N4&|MRtzDJ${V=9r% z=2W&+7e&Qwc4QxIjHUh{FcoI5`*IsimDhQO|OtsZEv+u?~=C3*SsG z*DGer+yR*e_&Zk%@jl@XaE-5dvMA`a8~dzved6~_WnbI4?Z|vT=l8S5y)4va+>M50qK!M5{kw^?zE7E7j8U!Gn65@v@uI zsgWJ;hK%*5zR+V+FlC91nqRrtV{dVm06e*xf&A-3qN4POV!5(va<{u zv`Nx`sQZSfJ3Rk(>Sa5&YT6E{QKlq8v&sHP1#imK_6{#@f8NyJ&)i~JOF)dTw=bN* zHc@4|{zP$Afe^tejc(3qZ83Iq4@RtwF(t9@;L+)DDWt%+cE|0S>;Y&#=xr@yU$tS2 zP38_rzvf#e*>pPHZ$u)RtZyyTO?7>QQoq7EiZV_joARuQS;Rm~Ipbl(&u3SU$dvv# zcv!kQ@Pxk03t|3nNWQN`+{h3H;Lp*k7Us|Ygk?G&BZOrcAOL|-0)<_}2ya0B=P`6($-f|mbNNNX{Cvyc(c^5GFxZ)B@Z{ET`8m|@twFco8 zd(plxWbn`Z%!ECXJzr7l@bU92f)H;AdZzgP#Wz&q*(5^M3&T#A%o~lpCvbdRpkIL1 z$QwBQFJEK`219+@L66xRi?5$G9zIJuMm4>g7@DcesQ2lnrMTMpXW8DnAMt;J?;zdt z52a^*`AvXSkc#?~fG7FV9pmPkl{_kL8BzgP zZOJhwIYF+q&FK1YLG4{@H;fjuEWEIa~4(sRIpWh>RP`b&Kbj!^R2*p`H$^_-2K zHhe1ePo+P6%+Y)M;^Y!cZGfa`P5dc6NI;F@la<9mOFErOGhBg~^PaKjqC4D5GvwZvB1B5b(%Ay&{PK?+X?g z0_@-X#RR%1N9~a`I9y$Tc!YF zty3>@eP>8|eEX)+#hMaOkijO<*CK1~A#n|NQe@OALg$JXDv=8jNYROMm%G(qJZ(0g zLo&RW*+{uC$Tu66g~)N-O&=vb0kn~Pv3t1Pn@Qdgs7E>LnFe!?x|23HbX8B)WX2WWst9zgC7>Y(36Kx2WDFoybjlftk0 zG81EdL|cXv`jFYL@e&YPu!BcOOb?X>+pu}tnT%2h;ZF({<`IZUJF}LI+gNmpTkH*eiS{e4K76QKcc#9M8q*Lz3>(L#owXs7y; z_}W&Lr6Gnnb$V`OVTwp#Jx^{!HG`_-sr2f!Z5iRfSEaojY-bq@D?=&|7Q zRQS;3=PtKas!)Jz3=|A`W)SVS`6UtZ0zP%9ikes`Q!*fY>C{(85woD>HYxDHscLgx zcJR{ZgQI85hm`RO=SN`GWq=fGka~B$<`P~s5L+4B$He5g!TkZf{(T!14jBT%O|UYYelUgJPz!BdGc(lz-jZs`TzGZz?511w6wIcv#_+d8~f?OYfu3leEJp)yQ;$YeA z%SC>u1$^^LbNAIm*#V7l6x(5V3IvAKCyj!@j2kecT_976;yC~3H%_Y> zj540NF8?{Ul_L`4sdV=l5;ij-Cr!t&6^e*E>l_0_Y8X}O>)a$&5Qgwp-a1yOkOAuc z3x>A#cl<1S7mcga@LX@Ae!CDq4#MD+m-vx?c^ZHIlZ>#3Yt)A#*!qc3gxo75KU8oI zAyw)%Tyi^mJ}36Px%=~$Y{`oIkkSZRNKiF!^g@QmfRBIIN@#iMOZ371vAt0oRw&3w zWiwe30`77PxF0yf)_G|YdGYl%kX;j2FO;?O;%$%0ZuB|3#WtilnFetbfOCMRXmxmQ zkl(gbvlRV=9_$YS_UBHxgM?VJ68_cl!q6Gh^L~+D-l2!!yj=zq1_aKnKT^sb;+U+q;5G~Y zt_KubJ;;aXADT}E>CtP9N^kUsa3gtZ8OILX>W3|d-^T=-yiiM|;GvBGSqRTJ6MFa& zlP=M-Mgne}ZXb_M!XGyu8aVYe$v1I^pqRD3V}E&9&A<5DAf)LMYjxBCeibs3wsD5j zkHY`NP35;~U?jWz-AfdNHnUh}j5*37g zG^0!PiWwhH#({?tK_|-xv0tMn+H$+orIO=+cK)%LbKn;W<}ot zd&l{NfvV0&AhLx;6)@E0u>+UX$J}QC&y6v{Lh6jl3K?=*--zik09EDw@r}F4wOsiI zW0}G{SN)jaYYQ<9ypKwZvH;Mv$+3n1x?HSS2eh`Lp!8@}I{cWOE87KA`nlH~4x!a%N3bz}Qughzt_z=mFEz35p~3Z})^iyp{ptp6QEV7_Ms$ zrorWKyzvu?Cx;O^$R9Hh6pD|(y#>1gEP#wZkXM3jj7;IAK{}Yx4GTlFm2zQ;hQTMi zD^wt3^u3&R6M$8DYJ6xwKken|PD2of#lL`hSMk(FfQ(4c%KHnrez0%Od$6+GF zk*BHQ{z5wV*m~Uvc!qAtIZbf$@_Nvti)0M~y|2Ug(LS2uLwkHITdiS#mg66f@%IB| z11|`$$#E}H5xt#cc*ujqsr9h;-xIH*x19T_2EB3lpmdrT` zHV+w$kK91*$*};hFCfTkbpt^B1f!-v6~D>YQC%O*BaU?wjCRY#%0@8iiE1gh?FVe& zu=QZ_r0nF>4iS9$tc6Le+g9bJ?`6JFQTH@fJYdDasHK6)$f<9BP|MnW?`v!?6fC)U*8 z^f;u^A}|P5#3YruZO-p`7PlT85()OYBly2e# zW8NmK`cD+}qxhNMXp=Pqv!3b$H9yvi6Lq5g4TNJ4s1x4!2fHr?6itXBF$SW|C-NxE zNOX`GKR(~un6=Lc*SJvM|2gnNPR(k9&53XOukeX5LnO!}f%;PSpz3>b(DJKl8Z6o< zM**dH~!K8e0es_fJ4BW-R3FCD>kqVCTBnAP7e7Q67` ztiIgb9l%F+giY-;aXtQ*9eryPCTkae@9KaFZV&GJ&*QB-sO2s!_|e8g53YVp$m09> z;BOqz{?R7?aqdM?rg`qB78wt+0pzOPZ@$m5{7{>4Q&SQ8%G=@A{_dpJK84^3!3SCi zabOa<@Z$qq+}&YB__WQ`KLE~ujK5vk!zNPS@OWp0woP0lVw?yG^7*%{b`?bkeNKct zYraRnTojO|aIJPH1Qa%6vyi$@Jxgg9L6~=$kGFajJc^i#JAjAGIwtuiUizi;{{FWp z(FbVUZ-B-{Xyl_NihTZ9u;>x3!RuR;rUjlv8yliF&@dBrNG!6Ts*%W&%Ii_>XM(FK zx@!t=gec_QK>C_S};hgz!_QOKgQ(Oiyw)dB3>vvfPg{&AV$e5fo2K$ zpuUcMe;Yx?@OppUYF>t@ubLknwygy0_)!-mLdR}JL;MK2?Z;SHlXnx<=Z02R>Ou{B zyttF=ZsL8!9E7jQ;r&Fx`2FyNemG61Ypj}L|MLcElYG5#Cou%~3{L{)pGQ@d;YaIB zi~n>+Q9HY~z}{!kntIkmkG`h7@+YSQ^D2&b4z6zTUR&#~<<66$lZ!EwM=aDoSKF%8 z)XodDL|AN*s{B~ZPHAnKE8za87!ZBO>n267g9DVBpCG0m2R?mnokSuU0`%^vflQpB z%y7_Zs~?x~>M@c6yc}*HVF+ua_U{`9y(@S1v>-i?Vd>%j=Q#a@q6X(0XNGZy0AUO! z3h=S_#~}|PqmbN`TaT6x#nBKGb}L;7v9AGc8!7yoyfCFdr=^60WoP}LV_Xs7NMvup zbPhZ+6qChd%|S=KBoyZX#)xMr3t(Dg0gc9$%uQX0(bnn ztJul-a<^Fh`QQ6LkoYf|b3O&QF{q;o+++DQ^h8v6`-JoQnSu{YQMFu@M93wz-1So9 zD_-i^K5QQowDE}fM*&hw{tY<(-WBoAY~ANm&im{j4GSOj{WHpf-lc$*}mBE(oL&buxb%>ZH4aPvPj3yaNSM#`2;kGdO=5x)zBlrBp zf899OF#z?)O?euN9BXXE6wf3N?Y$bVhG-M`XamO*A5 zg8-;Av3qIsYqk%V9^#`a!6*N4U?7+5HEQaVnWCN7=U75(y0pFeXP6@?TR0mK z{%ZPPzb2VytySIB!0(3>hc_IcX3l-}uss7Xe zfhwRxu#erds|WM(F%DMnZ&<0PFWXs}{tm(&(f=9*6*hcSOWn%EctfF;(@=VqP{|l- zV!&plo3$qcs(hUH+3&Bqp*bSnk2jk_x+ZyBO@dJCTWW{)&*VLR^^g4h7Gxa2Xa4~3 z5ukD^m2b2`McOo!LTFu>VDDk}_V1L>z`#1{D1;VD zjJ(9%c7K(?y-)wF;osAx1A~r?Lw4K23d`S25qNDrd4ewk+%-Fgv!Z`a_n83AHNh+a zEzw@@cWMbZ-@VWOb*kiA`vnem@e{+j(-V~w7iZ^8P=exlePIN=alN(m-@muasRCIy z%G_aPX|wzCS9wr+{v(vXCM|Mo7I3VqKAcf=czxs?ls|GbU#`C`QR`J2&bR2jD<9AiMyv;vDw! z_jljXiFmPFar+h$o3 zf&&AQA#(Wi-JjV}k!?Zp%%3CZ{r?{=q83Di-9i#nG_;k8q51Q`7tgl=n035TQD7HI zxd*C*Fi%C3!KTR%c_jr6pVIa+q=za=CB&z;!+h6H+HKm-xQ*M-O<0SNISk1a=MOS)q27K!=Qs_$krhGfPbRairAwvKX{LY((l4<67QO4C-@v)^!fH4 z{65^imnRbJ9t(+Gng%h5Q{W#1x9QJxP`!62(^JsS`zv@h_tWh!K06V#7yGZ z8o?agUzr1s*D3Y<7^TI~TOKH1X?$Rxu{|qTdA8nyQ$V4v@>2!JiCE|{5tf8 z&?Mhdc|G0;i!S~Bj*%N`Km6~ffB!eaXip;k{ep~N&lUIA(1wz0|DQ`t9ZC5VoOw!Z8l$3CXQMGM`Vq){N^_>(2t+ zhHoRm!b7l<8opU0wrrL3Pv%o6R2P?sM)rKm94IF80}BzvQ5o%g$HVD6HT=Aoz9Gju z(`J*E7K(=kZ)&6_7e0!BYnk{lZI=EqE@FNgzi6n}A~squEG%STxbi~X+1dW|Y%WR= zx^*lGMK1*niA19WXDc0|$@iw66$mm~L+N9q1a)d13();7UF7hM0-3YIU+K)UcW^b^ z%*dSbJQhkGYqnf%j#um?(XF-(YizNk=3{G~!1R51uz~h_NZNU5Q~|H&R@{N`RXMAZ zqEGS;nWClc?Tm0Evr^ujemk;&TKA1Yqi_pO>nAQQ7;Eo3{lV{#CT3HVyLYZh1%_8{ zC4!v{Hb#E3D-|e&%E$#In$HX}-(GnA#Cq+Tk7OUmXweuc^ZrmyGB)%D0t7PO5IV>B z(o&|Z)Q~K6cP4ZML%PA%88xFNG&lB~zh@OHVE5c7nP+huUm^gZ@j3(iTZTQivWVs7 zhaY^*%IXL1iizQv&nI9aBrCSElmha^;Lp6mZfYWG!g6$!b8eE8C!x`nwVuQAjYj3( zHYz3r?JrG8tp(=jt1XB7TRmUt8V_YmZH=uz}SgG<3h{yoeh$An)p*9o<) zvL@@yZjRc-;o1mhgE=*_{Uu1g$AmQ5pEFj@P>f6CZK`1BBE!2FJM*KVbcz~o3$lX* z<0t?ARq!W~ije{j;h2J#BL;=~-CP=FC+~C~390J{HK5Dgh5e*Rn6r!|X_z&cS;8NQ zCfcjZh&{RGR%PSoM%PD=G2UHO%wiQMK~&-_b*9`LkZYnL0*6A2c;t4dHYEpJtEcrVoD^6REB` zbn_`zdHy#SK>OEE60O($9h_^zf1l!XHgP}u(ABNGeXM`t)t~EwJ@`hm3ZVRb?Q6+Q z>+{&;#oyPkNA-9AG2Z|F();H5RDTZ7xZj5!iM|j8 zEqjUaNolb7)wZ*WLR_inKj--WPehFMU2%Qcl|Pk@O*|gdf15$WFq{%mHt=12dqjPZ z%_QLefApVczCDYJ|C)(^-Um-a#KGzQ{RYGym)ivC?>i>{mQ>iA_F*JZr;>EL+hl(} zGSBc|cPG*}ATmfKi6MDEQmMV#?$5`Xc>g6>u=jko3j;IuC|54VmXe}sco{MOe2^z7 z0ZdxQNP&dAFv1wSq7iS`b1Z+-`}{Ff9@Iw{ItAW zyjz9kq^S=f$f^d<-W*;cb&Uy&v`T#(d8=&EIW*O-AJ3G0Bf2I>ItCQvLlS32H-Y+P z(m46=7bw~G`F9TwP8`&J4TZ@2gP1ZMNrckd)hA|=86{C|e0&f8ULH&q6F1V>oI8fa zDgsO@rQEp@3Qc+sZg1>Ah04`&!9GWZ#&mO%1vGv9>ly1JM# zW)W|{?{vBsk3pkn)pEj01rb}QOfP~A{-Csrp0Qz9h7YPdPWa6-OpR*#uD{ zh^eS4*RSK}oWL*K*j+~y+yL8H?X^}x38w1>P+)W_X?aqDYE&Cr2Oma=laE%*yK7vy zPgB~Ve%}u}xAyjlAifOUlpE5LqdFNfQkOD+Ro5~B5K580K?Ma1!W)OM`@d{#ADgwU z%T1MeajD@q?S3c$+pb}7eU*nxxyh8fzvWbF#15h3QWsV2s8-`Py`(~M)a#Losc!SB zuQuW>M4cs~z>N=QoUm^WuQ@4ufAfC70tdBP zYum#i##z|LcP~-2$yPYj(3%$9nJkma#q%j>c{~*p7Z;bqiM_bwv{{M3cQOU%C3Im` z&taK1c}7GQ-T861ZbARcr9l^RzV2zv;?mM~m;LrU2{C`wi(sMTZ@V||a}`s@*eOx= zZ9vOf_cV=&QbUO-Tr1uJ(56#;yS2UD?6#oy{)Jin>F)Tq#{Lw^kx923gpo2QekaoX ziVrai37B@bcGoWhaeIie>iM}QPxj>WY~ciFc3wNVz5Z6`b!cpgJKumd$2jnVJK4n< z6^HSa_}uRGkh$>nsO(M2>(FNvHUm)Ygxg0S%U|y`dh6yHsS854k2c3Wit0Q)*~#p> z?g~s%PN1>e4NJ`I^9tZuo`m>X>c7d5;{x(n@K>MPKiZ{5hVTYR4qkCx3QJ7xr84|l zX!Jrpw^rqax>|d6!#WlX@rGyf+l|_nTk>9P`rq6I6vVDvtokCf)}TBEp!w70P35H; zX<|7!({8f2My(9!L^&AZg7k!%j!l#eZlblYmdoPUw~w#tDoY8Y531^@^v<}BU&7|t zG-+3VVW=G=TRvg(Qoj?=8LbaGwlhHZSrCeb=2M)nEh;7=hlS@N?;wPqjebHppxG~+ z9fKk)cQT*%k%O|%dP3mDR9&*P4NY>$;b+9othN`Ax$kAU#W%sJ(W#p~Ikk1C-doc| zu+`&!KN^eg^y=P`2?r3v@?2G!==Z0ipzHI{F@eiQp)lv#+er5UGj%KNQV#4WYCK%` znSz;ZI7qb$jbw|}F^1&klP6wtMSr|S5w4bf2FNmzHq}VUp!CP%0)*cqnx}Snp)`YD zANkl~rpjIt++qG}hpa4%Byc^s;3oOpD80_Kq-115CyEJu%$b)O9u@gx{9aQ}fV6y3O|uj$w;t10w%}G+K$7a5qAA>MYoi6F zti-|((^5tmMk2jxQP*zlwo`TXCZ$sHuEl_2%I>?f{16oW&>iV1E9Xu<$H^H{0qX}5 zhn6zF_dW*7$i$q_P=mIx`E4I5qfk4BzvUPW_WR8fyHZ7`8FrfR%^7GC1NtmzM5oX% zBrI|ASvYg?YghLOtd1hg=lc;{iT?x0{@Fju^dn8%i5-}#G=~(Ql{?=A8 zxThB@8$0RWI{0g_am^ikcjuF>2(HXkWs@3psH4j-?ru?|ZhS>(v@B0-9Z^OM7D$En z5ALKXYy@~tMy^jvB~M<$1Jc6cw>9RYhr~J8FK?9AAohGN;R5%O`!}HpV+I!-P`XQH}i11a&+E z#@;tkKO%!o#r=%3ey!=(s-9N@NyaKWZTSjbI!e#0T9Z_Bhb_tEZBmp9&qOwmc7!U_ zvhB^!_oHFvBxl$%bspXyZ6XYM89eHB_0`$>a+c+zAy)#Y!*OoT)bcAFT7~J|t@r*q zWA7fFmzth3gxZq?#Ef6kE z!2;(c6_~b%Sw-slgEwKM_gRTb%@0gq5mijKT5o~pt4Nn)l|8NxVINqI-BF3Y;OP)D zf^bBXnO65{xqD5phTx1CU`z+!aVM*S{W3}n(RU{@zdB@QcXx~Kbit1=E^g+4OP3m| zR%O0mmMT2NwBfK5Do)+?2EW*OZiW<59@QL;L?Ia1clU>gbezXj`?(sEI2q{u(|@`@dIB59$tvjxX{%eX{? zM4q`i^ENgCW)IwWhb35Cx)4jVPvEa1+?zfjev7Ald^Dg!t1lKd5 zy#v7wU7?SjJH?}qxk{o4;@+tmp&FT+bzs*B)6tS0_bq>}%ab+6PWPaD_b#oW3}_xc zVcHg6SFIe{jh53&rt=+Uo6|0V+7=vUHz7idC&71}tgX+v4WK=C?$;A*R_KTbr~3yd zL(}DrnH$pwg=fQ=F`c@5bfe#LH-foMo^v3C3nZH#7`+fY(IQnY92;IO28t?2C961R z#4N9X8DpeFHF=~Mp%$&3F@;-k$Njj{<7@(GkW0%$TTwwWoe%{L?)_MYhl}A!OB6GQ z-ZD~l7pC`C<|j`fWtZk>INtn9`rL(E{n0NT5)#L33S&da##kgjGiO(X8n#JmEJkqr zl@77$3{PYTS+IwuLQ#xPMusGM&oBE}Bzi=XJTj&!Z~6mCH`{%N+8LuyLLrGd+;sE$ z1lJ{Ox>(XE~^IBHB^nNy3ai8S}h>FvbKKB z1YEBRRtxweHos3?O$#2H4)+wUENz*r@66Vy1O){>DZs>a*Op%MHvPtJe)5s;#7$7y zO)91^FLDTvVDslIOx!}h#K+Wh3c50nzEE5_^YTl5(qoGs-rQi)sM~P~O>AIk{XTJf zAB-C*gIXau#z(GWrX>FSx$sG0fjY33@1xXPe``EifUkAVbhfkmInT<@2z~U)hgY`p^*Avc1L8iPGc3@%eh+NR zTJAHB-Jum+B(rVhVsY*At%TdLyE{KSV#%pa?U1~>J5_&bt*A+$UCk%I#8!wieO<3b)+zqd3>>V8B zRWN|T2B~e^I!GOTIb&vNHqOZ^;eHehyK**Xd?%kZruDgjKOiRdE{g_OxF;L5W>ulk z$C83nUpEfO~Yzbz%q?y?$Ev>1tT_t0nvn6+>D1J{ImGFSDBt8{7mB64 zN|}N{GM+L@9#N^+@((IY%1axdIQ(64zYrZ?j$G>O+EA#gqzlo<-$;!f=uR4&n~;FD zxD-7ix`SU7ol%r9hFbpI;gXB$-~@$b7=(|5<V%k*kL3ROQ;L5mvrysls7j3PpodBiC5Kb<64v`d-OY^1ed{ef&naNB{OZKSJc zMXqT#NM;=+y#dVko8^Xj|v>Pm}vIZ;Vc`1I{unw0Yz` zJrf&r&x0BgPYcq>^XEMFoY&D{Q3MF3R+}7o6DoUrYgY_Nj9n#q!JmpB@t0DHZ{ti_UrWG*F6`5?FSCdHE<`ayptoQzOn#>xf`qAunjnQwLcLb_%vj`r8zOo};Z zP4>|J5QEi7#wSjeayZtiPtOoV8NWV-KsskiSl%&7dc!^C>PM+{n=udsrm==SCSPsl zCBMgJT{yu z_TEuVW!?LD)KPR)n0XyVLBK*$X(~-RGmIi2MOr8ZP>^0k2qh4RqrxZx3JTIesRfBf!Rt|iGm=bp3AKD#{oIX6)3&O;3oaEzzo zG5xa&>*K3&t8?heCETk?i`49}iFJV$?Y z?Om5{jAVk&f-jIbz+2Q0%5DlvdMn;2lNoA}>EcoDF!_D$V7jjxNDo6>Y0L8$5S4!z ztIu^|V;GBrW$&`1xiSz0>h zr(y8d!y@)K31i<=e+i`nc$I<-1m?r6U*|HgUWWrpvn3LgUtyK}1I;tPS;$3^em*Lm zdJW(t*+uS|9{UNly-&|`UaXvKuqg}_5tAN>4cOQa?>>>#%m7$wqIuao?_zu&1D$FZC ztm(z;*I8kr$FRcEDxW+d#LGwJR!T(mK*s%7PFGIdZ8-+et%)FMUBeLK z%N)1MvC>{0lNWB5zCp~G@+Q%__Upn`Hd6wEDW5!nq|aA)(A^0Gt0!v7Bdp)oq*=wZ zu@NdY%@)i*D>`j0@|kM6=6z!W3(cG1KeHVOSkm6ZY*&0J(&+QGpmM?DoplxjHq_Ok ztY1GL7|sCZ?pe!BP}D*B^$3O%Ko-wftZk=um6setD`^g!c;`Qhi0CYTKY(PlMm10) zN@wywd|aq_5au{|XjHlLhHw_J(n0r zrM!E$vQZ*oMpSz-5=U?e`PrhU{R9jnec_BF9{5nDP?A!57e;%|8E4$La*yV{fAefW|){ecXGZfJC?Hp-&1pVwZx8XI1;hY7h_KYZg zbVj_BtOFD=JqB52Rv;hJmeyiBDIJ)W8>|-_PZd*hJ642#7|8O#rw)!Zgah9h@N_c% zhA_bWssovR+C_|Zbd?u#@hZqom1>IyfeyL^=RYZ_3S4_r{hARjn|sT4RUU-S?K7ix zIFLcaz80HA5&F(P-Om*z2qDBXa0#=4Lc)ztPCP2(;FaAbipJ!EWmGa*^&K7P)Q=xwXMy z8=*02#*t6Wr{jg_FMb>OZ+@i%)jN9Y`XY1Cj59You5;M29p9A(kSO5q57z~wKJg$) zQ!h##&5Lbl@3EF;PlSmijZARd!S@Cziph#4=O1pI6fIY~Efe(ap|`6g;8br0MI8Y$ zMAB4m5v+L6!sP;&_xFebBcyY3@m=ct{0j|qh;D&@Vz7AM@nHMW(b47iicINo9Nw|T zM^2b>XTU`^(@)1Xq35-O_?pYpV?m7Sfj!M29O}Zowa)_Kd~AY*{rb|_uklsujPHzW zx8iQpa;%$E5A{57%V`Xr=wSN+<;64<-zX2iw-r~t&YQPqA*59{;=EB#8V}wDyivu{ zWSRqa<=hF_shEqJ3@rmb-nttvOL~4VJ=)AFaJba|+y%#!FqT}TSWx8&$ihCifz0!4 zN?tJE9mFk!j6+w*<=7jJmQ?@;k6Wr$L82D$zeOA-1YQ+A)}$+Y#i9&i2n_6^qdk=# z7OP$8uj0k|SUTkww9N!t4yBG71L(Ahj4DC+_^o~Cp+e?4+nwm*;WPd6<3JS-p_*6J z1K#X>gN~}dVpnX|*DVfT4H2c{PT0)xB+$7IbpxR|v~aB-Pe5XJUww*ORHqvk1&m7{ zZqYKh@hpAVtnp!f_V9$;UEl661xlDrc&P!>ILlIFuheb04@@mjPM7Ukga|XhxX!{` zplt+Q)+ZplqkQA#m}@$>h-1l~Erc=Q6oAdHRd@Uj-&Ap*Li$bX80QY0L(J6udDUsY z8(+JB~uet6*Eu!D&v)n>E(R8M&rA zv=AXHhwG~v$ceF=Rox0f6F$w!Ye@<+61kG9B^z%=B9sobDl}#faXQo#>pw)OYmk5|oDynbdfY0mBc|pxH#+N2PEg8h46)>blBMFRSMSMP z1*Q8Gff-(3t0To-Op8g%LzqG+Y&wzUI5_-PN_R|Aa0hV`X~LHbsf>T|DEmhjE@@GIa-K^S8K zuxDkgkZ%P9PJRqpt&1K`|y#F>wUHv1ch=L7+nf?8WAIm21w#MBK+e*Hxsf zsysvw^Gg{DH5z{z^QzFJSLz%+`m4lw$0=!r3xB{RnCY*x>TT@Eoy`6=yB{rL{Bg%aO_4w(lu5!JYMsU2V zd1e!oEUs})8VTl2BpVb)(Jbz|X@HE(yGQLeWG(LlL z=Ma?c*lv7~)XYiqj+9Uk`xWL-idvo}@>iX6iwDn=nfg;l;zg1 zvuKc(0F1pO{)lQPmKh^6%ali@EI&L(4hyZy|CFr5pEthr ztO~yOr%CcNAq%6DKVzly`S^~e`mFmH0Jx)pnjfB&3h;wIC30gO+%;+D?cVsH&J>?a zi-FUg^BiwW(1dZs8m8X~M7t$Zqng2$psuWPt3(sp#m{Ga*T+cy$zq)x2W7MVjQu%V zMKvh(4a%e56o5pZFW!*Ugz#i?9{GCjLxdP8zuXy)$aVX`Xr&)%og=0N}#t@Ic-C^BEWAVasE^Gy zUql#y3rtr5v7#Up1jd&B?$N3I0RAk^GowEG6BJ3Olr$dli^MNW}o&cWD`b z_%gs;y}}utMUejv3-5??pEyqCLmhq@s!gSpaUZ{>CLq?6@_S<3H2ATW22`24`&1o` zXwsJ_nJzE+d_YK8*lA)4&JGAI^{fAimA&Gh92y#mB|BrO^f;DbXjr%bz#IPapZ~lh ztG12IN3SNTc-QOWoNmjRr|I3f^Cl3y{tc}(tOH7ux5@ILdeEt@E&}No2%TaResLTJ zB9GQX%J%;@S~H*g8{g5>0MRsQr7v+^hL9s$+4xSnkK6R-B~V21^WzPf*=4!{+$5A~ zwQTxbHe*gUJHxi}w^F1ek^%ed7=({h7T>3`7y0AWclJ;NI1^f$<0rDDv z@}Iu*?9+GeqGn6y$JT-Qe72}=?M!l=>3k>geBcuZ-9UNG^kjlK2su?)Ztx7w7V}Y1 zv`g7|{F11DGyY*QB<7DV(7~v%N*(c&VI>OX_VFmyh3BAlcbCjIo?!Q7e6rA^7IG?| zNNC;%YGT$|P|uancQN8cE@xkT*ZwDD=Tpsd4|K|?R^;sHG z{`3K`{j$$HJ`i-a`e+rkT#|M!L}>SOo@y;dQ@D(~)@8+W+d?s@X#o)*{io}wzH6H= zBL{Enft{*)8rgNN!(5YZb5-GWx{+ryW6_>A7`hj#lYIaW| zmtV3r58J{u@h`nHC#-}JFQwrI9Ga|_{rh2fNs-dU zD7jPT)Vn3zZ*%DQd*A%&ejKRqI_hUm9OJMTRW-6Ij-fRzJ}d_N6<5vb(syV1a_sx7 z<2)!$0n2wYW@3DfKSA6oJ;P3ND0_7>_x3$m-uuYHcW<4I#`xkVkAmM59C0fMN>q7~ zrv&H_Zdpeq5h@7h-4!oFA5VG%+6mB?nMcxqDAS_daY6Hw%gIi72Y=niUC;OJ6+B$n z5gH@iu`_FHj$r#;r<~7UaKwbM0yT%&nh`5*&@oyRz%lVA((>hUVp@D;sWy*rcIDd- zyI^0>$>rVZs0r6W&epi8=U-#mF&w64_wKV8%$3L;8JR!fw0g(pvaPGtCd{VYCAzmM zW3gTtz)GHaIVj6;*BljFBMhWpnd+Bss z21Nn0*DbqXr`E5aH=bJtW>kL~7~)Z7lw^qapA)bm9wNE{`x#7Wo`C}r?els3+xbVl zPVe{rT&yj0KTQ2}A1NQ94xI3_)K$}vq&Ow_FeL&y;kg*{&fB-k(`mPZQOsj{1&Vih z5*c$Cz_9s~wn9q-s8^cryZHF3B=oQ`R00C$9!ksC&lN=!XNqxE?c+X|Fj9f%!Ao~> z&h;iuh>1kZmz9g!0Tx!rJK^URW+*p~ak;?U!?1e#XDw9AwV+pNH-XBZa^-*7)u$zC zp!pEL<#_7vKt+z6w{dCnvW$2^S0t4EoII~(U|}}+pgVGRq=J_Dsp;UJSI2-6hKgf* z6l6(ZxFB8>C=FtT14_?ydgpwB7yO-ijF&GR*oY3oO8Qa|kJH}JSJzi7)w~OCuLTg= z34rBZ{R%?UmOnVZmAOL+sHpP4avnjw!P{#!xmhfg9*V;m1;6`lR3=AslzXdOLiq&}n7sDsQ1Q z3JI_g!pfi+NVud7eU1lY{eCc%j?|t^cOHPaAFFSPJk;pmKup3%7g=Wz=Rpw9Z`?kT zX03qMaxJLjPlA;|l(@IGY;P!@ya+r;}utwh#Bz!$5t))x6>y$qaDKN?Zr- zs}t6awAzIRy~X6%4$mF{v}w7ncqK;3kq+P!v*NTWf6c;6mgJqEo_O=ZgaIoG&WKDZ z>ZlT%R^N%{)Gk2qw3+%rsB93Usqhs-Zm(!N?TEz89B?%4o&_315!9VO{wPW+)3elJ zEpi~IWG;4kDw*P=e?I0{qd!z|=fS68xIdb?AXuB+2+Ad&qWC(2+L8tUjsZ5WD0WVKJwgWm^OoJ~#H#c`toBkbQq2U_TI~n;3ZnP)R`D z{cbDX<7IT1Kd|FLgLOmd^EuR7EaMo5rJ<h92nWfN!3YXKV(V0M?fxSNx* zz7@0?jjsW&SS7&pQdwY^W}9==hpWV1G>QtT&f*0a+^YGyH!BO!#ALga3238a-Z~g8 zvi!QaSVNzds)>Q3Ciltc{c7f~UwR#}a=s=yt*pDXy=;F65in*cR!|4u9uXt``4XTe z->WQ{S93m4)v+5^lmKZE$PG_W_dflNTqo)+?-F7X)sUtuS#6gkA}r|e=a9V^Cn;?# zM%-D9^B1M=)Xb*e+p32W));X zo^KU&*({MKrW-Iw4x<5T9d~ik-w$QB-Xu4>P~V9#24y;1neB=O6l8<&wikc!{K?Ue zsRW*HE=M3_oA3Kw+<%T7F(iBjph_37GJhxF4jdwYGzQl@$~SA-*fFz`*jFZv?t)bn zC#rauf*{o`i<~ud18}HH6%Rf~2*n-2g9HodYH68#<2V+CI@dcDR5#1bX)7}h9^_uP z{C7e`Ov>^#D2;uhRe5{ryeRWQ~xBt=RQlYeM7;kHsrbj78y8N z{3v7;Ab2+zfm?oP{M$?7b5h{?B!^RTnI|0-bsMO1d8}N3CS?{D6OHL89m99wpiT{f zY=?>0?}K;k20#~G;Py=5O|=#zDA&>*qZVo%MAap}boPmS8f9Ja)^{hgU3(>f1r(KJ zBTyJT3LRW3AiP;%K}1VsF;mh zK14@j!-4FL-v&w%6i~rmjIqPB4h6%L0`M8|4+kPDz$CH6c8>iD;eP z;KGPK1xEIs1iKVuBdBu^@;yb7O*|=tR%1=M{462IlC+sf?+qGC^?GIE0rF3O}>GHPJXmuG{I z1HrG%_oso)HVu?Jn66BCCo{bC3b5mnF9n@C75@YzJUMSJ2Ox^&k*fjnf#?1N*k;sx^ja*Zmn$#iOT=<^j&NUuT`e;PR!#6*bd%whFqLt{pM2~0M-)#R98qRpad~|e$&jyZAi-mkR%?j&^B&1Crza| z;d!C#@^XCh&j4%&^+r-_d{Eo;Xoy%|Z#7vB;v!>MUArhz`|53DI6 z{I5lB0}zLN86D64RuEt5HD3ZaZ0&%yWkLot_|EmE?li}k6;3TFx^C*aOGpSg+2_%Q6ZF#PdgF0@4C69<4eOMy9(ezns;-Ty|0^Zv;JVP z>w7?0SyQogM|d85OoSglqt9@pieD&BqJB z5Rn=4^HI@kOiDl{pqT(t0knf~Gbogwb4NePd+yf3Q!_ySA?n>>-^o1yLswAL4PWZe zpMMoI@aglPGk_ZDs8Ci{^DDK@**dO8+;nVLSQ0%fnAl?i2&lp{AbWDCU0kCS1XK^q zklgyU0C(#-pt$OK&3rZnRA(J*>(b%^>5-%f7C2bPN;fZ~G{_iWTdRCmxZ-OWE3-yi zuzRn4HTMY3MU@z6($rz~l-+`1B^^?tj^yox!q!8gg%h0hFlAHO+_mGVkVCXJUgdBo zQ~VaU>XXhVJ`LA|3yDW{8EWPa!C+(O05_xyKv%|i@3Xi%sFJy+st279U@)ihWjX8{ zjdC(t;g7Qb8!`4*ZZ+Zi9v(Mqqg^3*3*|Xtf2idQ8PM^b>sf9dLUaP|=iu7C-z!5h zXJpYvQImNlmYX$Rxt&1mb>gbb0ZU>UxG~+If4d;e4JRK$6az!I-1}t!OUk+%oOcjb zUwBOGsh9VDnD+^Z^F3NL3n4Q3r_^g>vyf5!9@{rEK0Lrr%NUi^?VNEx1se7 zhmSqzfD!|U@5gW()Q}Ca$vqF&0hCH)@Iiqo;HMp=P76JkO>czX3>8rn#_a_m>+KnU zDt;^ow7ZWirqwZ^!y43y3=qx7*H!qB-AoUmW?Oc4qe{>|N5vM^u6_Ke2oGwq4kT71 zrNSe$F8BTD@$r{qh{pmD;mgXP}~>Y+#uhU@NBsP*?xXojY;e7fi4T3dHY~NwfVH z^Zb67ubcL*`MUKKiA(oQ_%7|n(l_^$Y4R;t&lItGVg zS1Qx^w7$?EMtX;Hz-$d43!F<&jZ%^8dbq^>rNH@}{DM?$b9e>q55RLUM6$#Cne||W z>WikT?rXpMm*#aAKJ@n*Zlak;ar>o|V9Bm;py)Rvx35>Zi{pwxV`*#l-M-1ou1x5t z6+tihE`{M}Ts&M$@fEuT3V0nPVyo!ojnX%7&j7&+1H9$uLlP-(gc`BF+4m1IPxbk| z={yMdgC0fZtUsdd#nL0Y}q?-|8pW;xFKN?51QExi4V(_h@8+P5d(vX$ZLg-QXbO^5m1V(9;Jh zT-TB^09bngo*j(sc1u&x;lBwY+{RCzgw!vO10@<+Jw0ul zaqJU4RgM9fYhuDNj5x&2G_QIAhC4QUPAwSQoAMZxo`(x&Al=TrCT@(o*%;(h*nabA zxu?YopU8ckOTMUvR@Lj^7|`N!(aMRLXYit1LUe&kS9va71*}~!`iK>Hls?G##~Vho z10FxUaIqXyy9k?J@U5HVLn(uR&WY~D4cNzxs`&a%<@~er{oQ~m01SSVm0E{qA1IU< z-v7S$r@M^R(?F#QEMznXa+lpi|0x923qxnP>Wb+Py)_lYr$vDszaK9V$?pNof_!u+ zJMG)!w?6jDC;MGX_%4`Q^vLwwSy1LbG_)YA435bdz4P+3uY(oIfcg|T2bJ}__#t>u zjakNpX=PPyVXdG4$*9tfK%2+6G_XxV^DH<72tic!N}GePWOX~-GzP43C*~<8aCA&+zl%YE`z~NWDr!}miE9?6LezAJZ~B77d$xt%8i z5ukKB_L!h}KmOBJ9JC!11dQswDFH8|Uk?7Pg&Ml1dc)vv$P!_ixJ9S!H7$T7F`lFU z?dE%g8YBSCH)%fGRW%@hXFve*Ps}>FTR3ljx_WoOMa}K9W=8-xYxrE^y%s8}GNt&T z>9?{pq!v%~z`64uejHcNMRSAauLgH(hWxuf*zuAp9D~@omMP4+V=`9a49zp}o%oDiA3BH~!wg8;JJzUo_qwZGV;%ON_h z{*!|WZ=Ii3Gns69Z{{5X^@Q29p$*o$;%5HXB$BJ|4PY?)kN@)KuQ!?B{Z8YX_Biny zDmvW;zYVge;q)c?&vu&wBYJ0b9_arn>0r%Yd{8)8?l*nS=C)CU{_h_z{tkX~rWCvY zynE%Z`HI*6H2j2V40*fCU_Jm^m}aw5~e(XI0dhdlys8g z5f`X$Yt9qUk==>675qQkWgZQejK9r%O^rUl25&Cbf!q=XTWVGzt&tFR3$NvjxuuoQ z`RgJZ#Q1q(u-65mL=Q)wL3?7V6zCN5cs!d#xR%58r|WG$CS06X0etf{a~6Tl>OGM_ z$U&j$kEpt&%`Dw7U%}dlnUbx1T=Nx&*O;u-)!DZKzT`G}Xc`|1u?pV7^hu)`kuLVU ze)3%e_g}P{MI^!pkW#C}Y=#4JKA3#9xC_kWkjp?NlCYUmwh|Y^Kd_otQHeDSSH)WS z)t@!5Aa(B{L$f|u(@sh{+dbI3y!s6M2@^X5v>k?7vreXN$TFW4$C%K1zbWK1hG!v0 zi~4$3UCWHS<;HCFN_y+y1QVJp&9_rid3w6;kP&p4S?m`dEX(C1g+hJ2J>fst5>xN1 zV(5<^Zb4N-Q~VW<@VlBH^y#4gkZQ90{dg%|KgZ3{GA?(rVi@Y)A<&On9bEC5sXzFk zy#uAtz%HI<5A1Z<(nm8rpn@2ou?*gzo<7UfMb>;5ks2NE9_P^~FnABm?)JT?Zn8df z{=cB+q&{=uZ@hrCvMGem*POA14(cBNlJ&kf9($0{P%|qO)eOWLToA})3}vbEbT^nD?fB0S`Lv z+}%$xvwv4AM_9Z%@a-Wj0^d5gJ~vd%8ZlP>)~2yN$o+_0%Bc)G^>1o(?F8rvc9Fa_ z!j;FVfF+61xH9sZ~ zjRagZ3G1KJxqZHbMo>p5iS{{jG2#~8wF2vDNeds~C5?PO$)nJ2VPD4}X9it02^FkL zXGP}6QH7Z%a;bN7T;YoR)Gn^+dK*3JJO{rt`)TZ3#jZhW11^kNncF}mdwrX=Bj)|d zx0Jh8s^%)-8cM6_$|DPUZca{4;Ro6Gg4<1V*z*JbE2bI>DCQIW7K+y?F)E7PD}63i z2qH72mCBVwpLDHaV&(I8h_cp&QUI-kuBNBBymxQN#F57YT5{`2|6~s3<#s;g#`(EI zaa?pAAIg)6;|lZf?)XE)yru^!r&x~whA zO8^auPN{>t=jG+F?CIIJJ=xtH{|h)K=(3JNY*d6Qtd*0{^Qsajo!5_wnymDQs1h<& zCLcHMIkCe9_+C16JCi-_=&XlWDePU6C221y3g^Rlg6(E%#@MzL^!VAk*?5S$d?aFK zz&*%jraPC{IeDE)sWnIUH_Z93?wKqH*_`Qzm8?Ny*G)rOE|yiHP_5vG**XufZ$~=i zi2px&TJX`ebGh^G>R>&1AFvCO70k_^l{RK)de^v<{Jk?z1{rPot&u-d0!iUMQ>)1f z8%f{lTHVG?ELx#0S@2QE*gYrkZm_Fm?0dFcFhZZ$P7{20bEtfIMAvWOCVFFI^%)-I zwT-CnHpyL5mfxR3*241^h(h#92XP|J1*}2p>n*PVyQl|+e9+}K%9zQUg9MTzWz|QK zasEu1OyN*UI~$>#T_xb#b`mnn8$F{~?$!cUI`s*O(lEwuc+qO73#@sW8-k`flS`OL z*H|Su=kYry53Ka#&L*vQ@GpE9k&}^;se23>se0=p?eH!i88ReyW3o;TJJH1WL8Kq( zYRgm&3=|Za^qUvV_1jWub_;eT>2|!m$)t`jJ2=CvIrO$|ZLykffs^Mo zydje{D!V?ku0mi4sPtPU29`oHx883^;>B?^6*Pf#-w)0m6zxsvVyC9R2I(x{qJImCPgyFb`*0<6hq#|~iUH@}9g)~E+A)dg7= z-nmO$dU_g&sCWpTOq7JP!|DnJ86{IJH@g0mLbywIq>l*Thgz$tR?urYALzeXU2VKwRdIE zeKXY%e1v5yzv>-kH?@F@J0c1>0GRb)JP+IOSvQ#WzR#r{QDt_kgT>`%Oo?zB|J3w= zX63J=`fixR*p*ltK3CA$vWI(@r{f$2k6`Ayv%a@hZGKSE(E-`PvErHP^+dOg;lswc zlm*UQibv*yP)x5^w}n+-rm6?ab?8>7B`JureNTxF(vprjQR-)oq}bkvMgcQD*H3`f z>*9IdtsOl94EM#C+0ID9W&p@}sj{UY}?4nAlgIuwSvZVLwnb7A_3VAXF->Lnke{o`4@=Ey&Sp(EI>X#=+ z*@{;1^%(K)6r;2&SK^;OSL_OeS~XK}&WJ04)`bIbxEC6>c}$RhW64$!6_ug}Xp zfc?c`Pc$01{lDEE@05g-ag%chk;SFqjPm zTbTmBo587`_}>T0zUPhiySMUj7}T78ysQJZS4MOn?teyqiD`$=0Nq((=P#N*WpJoRjm~=ITHV-p=(dx6M*A+;?x*{_YGu2&Qj<+tF6| zI|T~X*ZYiO&Am>u^(iF4=D?%PF@534@0p^+btV{$kFi+TKmq;X8yf@hiqRvjqI#DgQe zXuk1g_E@%?iJ4UyWg3-vuRknSMGCB&({TD9>-!e4RHK==z+W+;2K3 zb&F@`VX&Hx;v9u{mDq(4yZoMl)-D(Ue5Kx3iPBb;*HG|lq|968I**bKz@ac6iNpUivYzg#Qg{oV zLx$VK*E!ojW$0oul+7IP=io&vkJs<2`sZF)^rJcKD3+Hu$YJFT_5Gd_XoolXL^v+X zywb+yhWxN$O#3siwb(}JPDK*cX^lMr*wVlvbt$a6^nTBeq7Cgs<052PZL{K}29mD& zN2ph^Uo@l{j4vW_tV>e=eZF0L5>PA3XMqH!8uIHeh0r$#>sLsx!m2;tum4w{tzVpw zNW>^tv*j&iwkSZPKh<;1%HD4hgZOWcp)EGpeCXMD(j`*&_OsP|oR%Y^bF(>5{wS!0 zD=7+@kf2QLjjFhQg*2)FlSr9zmdNDn*@^?8ehbdc-b&OT=>Pt(SRg;}F0=~Z(eoH; zv}|DWIKwI8$31(j^e$3zm@dHu z|INNpklz$qQ>$vk+{GWY=R=7P@*0?XUVcm73SY`m(5ZD{ML|2+I{f$#TfzE$Z=OP4 zWg+NR63efoCJOGWx#MN}HorEY!u-;|db~th4vUSE1CsK=l1PiYP>>}%_VyJ?D6E=) z>Gi)R6~1mF;JT68Yk`fzC2kM(W4Oz*OzgpZv(V~pU8cXRMIm`?sxaP{<@6b^5_?7>Jf}NWGEEHX{iuYUpaY2^`H6W#E^%-fMs~3~{|`#U{zA3^fsLnp|2i8+Qu$FN>>e}LRKo(PvsORqGrLv% z7>iUXt8!(1z-jVF1%ke`?o8;L%52H||9F%QkMb3NM?C$<{SGy`SUpafePv3EE9bxuB@?lpFPU``-vk<6XH@?%6$^9Zsv z3@tpp28y#?;{1)svOsc`RLg$_FgMx;NhbzYGN`J&C16Y#okHzS)ko4!_q=uJS^o+Z zgl(&+<zSA13kW=|C);&+fHA@XV{j;}|RB|5y zL=WJP?F&=kGemvc9AHC_uyn?)AC3YiA8L*#4Kz(6|Ic(e2PznSP6z-}v5g_`8GsXE z`slo*+%T2QsuGIpkMRyhzNp9?fgpcZFXo0v@UZVK?0;KX+CGUS8?W;JOOWA884M@L z!C3Gay2`LEl1*=VWm@~BxAWq|>pO!5Lp$TChSY`3ac)c2y!6(c7G~&z*w%&clmF^7 zdhS-@tpN(~9g}d5!;mws$xy_D`*i=c>8)49aGd#hPQb>B%Fas3s6qHkyc<#~c@kYt zar)Pk%@1kC>t!P2Z*qDijn#`|6_ zBMwf;dDP^{7lHd!3|wXYrOv|UX1RHJ&Olh9IF0QdQNBR+TQ?Vz(G-q@4;^z`q4xL#a?mt*lt!uy4)h zg89?(gi&^>#?ft7IWsVG83#B+zgiHItHSUntpRD zgb5SCj?c|>=TP14OgA0q1=NXcIHG1`?DGxKGZ-8kX@VrO<9AH+Vm7s%R2Iy6 zyWQ6psf)k!kwL~i#NkAavS9;Q=qol9gXt~9GHj6%TaCmQ8>qjN;!@R3zj0=%n9M2N zVKOo{5$hY<*|YVp7P4ND-qoC0o;}n8qJo+`_cp0d)HMpe&KVGJP~wB#e6@wuz+TI2 zW%_nQwIS@>%dXilo-4re5V+nk4+wK&^WPu`Qluq{00cbOvN%N&o;dWJ<15EFAdyHzjIzZ zU{(HAKykIi#?7ayvvtj=k9IL8bFl`zUybU%x?HC^H8~ix9zvvaz09|^zJ#J{Cv|EJ zZnpHjTm5)8eBMJZkfC<9#>KZ?Dyi*La+O1WGgod)eC^3&$=OstQezxzkbZs(vId#b z*M?%)!MdkZP0~T^9^vI!MPt3eZCqqDg^cHXiPK+ENV>o&C%5;?I_*^rWuEkdya~svP;S~8jN{7#UzPuDHE*5 z036x34(!WA8PXpF^TsjFR$VG5@ubo{pc?zb)gL@;hFP0&BN5?2MmmT4i!SNqs~F6w z{F6A>{Ac;26FK!P)W%xnveLnes!W51@yhfq?DA`sk{#cg2JNfOeJ|L$Ur`e1)+|aFF+J z*$ZgT%Ni2`g6TnVM(kjw$zBww+}FAlP-Tja@H3`Ap=y(4NR>{RRBqh5@oK`SR`Z*D z2xXgN5x~{6uNpn2>`L0-_*N5p-2!&@H6ac?ukI$PyZBxLQfKq&)OpflUY63A2c#Dy zL)>`rw_c(}Zk}7>V;d;ghpul&EQ}?SZZrKzlr2oR=3Oa-cwwiB5y@8$)~)4JQ%Og# z5z)wW>^{TjkBadz|c{PLC&L%GnI*8F6K+n9Y?x=HoCH82Dhb)9tq- zittu}!qPm{{7)9pht`9j4$;JsJoGJ2e3Kw9kVGgzF{3k|&83)K`TWFn@at^EEdxS< z!rg<4E4?3>J98}0Rn7N4QMl4geX~_`t9e((o?~UB*vZi*(AEMg;5K~8JMQs6s8+_D z1#|jud_0z0M}jTeWBVZ4)`l0~d)8<-d|Wk)MLWiCqa6a?ezJ9ae-dM25n-xWQMp~j zEjR_~m_T>ShfAeE;zmsJvH2i+j?wo0uzULSkH0#TO(c`Is%~Q7wEM1!5L)wxOY@2c z>#``f53X*0`0xGS$YIs3wC~iatpX%wF95u2HtvzY9Q445jD0A7p~=PqN$ES2z@*RK zB&loUAWRY!-b3~uW~vYDaT8Z^++&*!HwzWDDjg(Qyl1nYN)dP28I~zE8ZOdQz#`(} zx9YL5gW=F#94>Bd;pWN54H~(Y#jdNCnB(^*Z+;Q)*(yc=kLjqFJ+FLcE{Zgyx1|Ng zPO?STOp-75%2CBu-%`${I2~CC{KPDwU&3G*?aC8s~FpoC5B# zpKRt3iRK7{+&pi7n`Cudo!i7DVrcnmuB6>g+tQ|XouT!@OZISq?eeAAbx4pAo>d{_dPWq#}%8hADufScac9~4KB-foT&a^9qF@)dg9&?C2X^e;PL zC|Q0edcy&9cOq89?Qs}pR-?IzZZ$|=+9mt-ffRO6i{txyv$B+`MNl&UWK{SJMM%1^2S(1G=El{P+L zC)s+f!K#eoDfD)sGj~R44~>xVd#7HCa#5v6O*kDuQ;Im5J>IYa-<%v31mUg18^+`9 zY8=d3pNL>m|Hg;nU$()Pln_bfH3(LRn=>CGxd2%=Eb1I~JvSy*YoGN!ze@cB{y?2=ql;xD#ze zO9x96z5A*VtAoVcQiP0`Ff{*r>n28$vA3CPYx9Sozhz^AUOyfd)!FV{9% z=Gi#&QkPIR;)#)8C~@lA`!T|J^YZpil?FRN>|}^ZYxcaty*ey4AFGN@GGz_{X`0ql z_b+b}nGTp04e#7Q_gZHJJv)QLu@zX++(Z{)z-Rb8DLG5q99dAecPU+0qGmI@J%m2g6$~2b)!FVC<5e8% z&9qf_H5R3T{1Z8OV0l-KwZ!_eAA#}B-+O+>s-OXY!ZQ?iL^m;MIg>D-y{R|E_>yU# z4OKE=J%7|0RYjPthfs&M2rsZu!12bcITNWlU>VT++)muBqPmibLpXO?|6Y}ba*$~; zYLfuvJV(+|9n~i*->JJuixofrgwb3tBL>~ISD73}(}>k7xHs77Cl$KnCNhcDi@f`X(aEe8S&BVRQ+io)u~lnsrv!1Wt|b( zh?YNSNXVbg?Al%P?mnGN?2#84Vx1pOTp_?Yloz?GW|#u)e5(~2jqr^zxij7UC{H+I zWvzO#FlerGGGTDF8ogFOnqyIwv6)O*=Zq@OA#()M>^e^?pI-hY?$mYn-5v4LH-Gsp zJ=-+msqZg)jr8N@{(kia^Y_NNGuJO2!={`v_)G1V-KoOAoO-nUyl8#h=7aplfmod) zsU^3yfIMf3rgikB-#qi7*!(P0g{Zi6c5PWwpvA07FLH+qfO&rwyC?&ePEF*VOC(KD zUOt^eV$j6pBt{l3IUeLgn-w&i*?O@=rO>z;re##rY+=MDGU54H`{iPen0GA2hSQoV z(FT{YDWy7#3xeF;)~+yAc#uf1Ov9X}39ciqHY&iOLG*lLQ=mCZQ5sdNC1UaiyoWa`?$V|^-K|%c z`2u#K%y4aW8=Lr5Y5IITNw((#&b7eUd*d5?aaEKUuPC9c+#Je{_uI@NXN*a52MBQ_ zFE`#@zmuY-L0igeN>dIC{ZgdhjLWx{<>|isf%PQ6#ljoMHzSl}hKFw?TvW-gUcO`3{5q*uYUnx` zk_o@GpePrA9KIW^AxjD9bE%&5FY5KCX@Vc4;j8|6>ZIL`iYPtSdM(&w1_4mDAo^W%}SzV?F^ zI-;+j@JB4k#AVjW~~;y%Aa3WpQ(@yTPG;(o5L#<~PKM6xH`-O(PJ(a{(34yd&**+vc+4D6ok zBQT998H4Dhq==-r_8IpVI9>msW0JSpCeWjszK*5JW1eP6rg*fX zTvunKq*8o^r`=J$vrCh&Br7CC2*6VCT(e4~paQb$DdWb9X( zn!w{bE&a|z->xy;C9WG9(q>Cm->-dtVsAS~m&JMqSbxfm8lwoJ2fcI8H$+6a#C1G; zrhNU^bLQ$=nJv+tPLbivEiUWz$P)CQdtvmIC^6>g`9;&$V~wKUsyPf49(xxH!ZT5K z$zcX4tqU-(E{nYs^BA)bA$hTez2}vi*9!$F1$(8Q47uz}nJ_muzfX2=xuEFoGW)8Q zh#t6q)PBhA;oNE~%WA`HjTs;BNgf|x<-pEN;3Vho?c&ZNgwU!)1qP816TY{j@7EsX zHW6zvS^SVDvh=o-_6CZIcgd(zcUupxiPXvhGg zG2;3n{FP3f(D}{p%PY!}W8Vb*h5V}b%)A>oZEVf~qZ+56tIBlKnA(vs2B`Xv3)#&F z%3;s#`QOPHCbQtZYu+J&r)^~W($)Q4DmLqi-mk33ByO(f%`ARyZ1r~FN#WE#A+Srr}}WRy?cD6D1^g;VqQr&?L_C3R$%gov*#J$hNaIv6?D@=_PWf#LLX z=oh+c&)mn^;;(XF%Xp=C$#Bwc@QD$tsj)g%5bPPngQl;ZqLl*?3 z>(IM|CN($~9z{fN=p{sHQlo?-C7>c;XhA74v{*tf(S%|MN&Y7RpYpBmtQAXc?mcbS z-`@M&n6Do`w1LyIyAxD-NogJw*Cx9ZBJRL>yp{}Wvd3;=r91lTQWuupW=YA+jP&gH z@vX3U7|Rt=Scxh$i_oVyEfX9=--}jyJ?7uOy?}f1;$&%AQ`p_aE7E7~CUt!|m!RUh z>YK6nHZLNW*Qh~LMURbSuf4d%WYM^au7ixJq^mdWz5M*To(&9ke0!XydgJ52)YR16 zmdnI5m?M1=OXDPWTKGyXI+sP}`tW9}r20=Pe$$|tqYUq`2arAGRtMsY^mE<(GN|)N z-j#NM5`omDd0F!2eSt~4oA|Fw@{dPok@g_lid>5@fvNdus0MAk6PD`oc82}_ENlW&e=5NGeezp9fXf;}chDUOhMUy=L7A-w0R zuN8~#D(cQ8m=}OH!#Qm`*kDdOy!iR6?G#aTEI7(J+T)8Q<@`fuJ)JpcUheqMOgh8b$)FAQgwcpahD67Ih zyyw%Cmf^<04i<*l?yKCXE|yD~d3_j(>Q+Xlk1iW1Wck&#peDC!(?7ypo}FkmAe}_6 ziD+3=Jwci&srs5RX`$=qKI{F%R4{yDgRFEGq1-4qczSH&ak7zNRQT1z!sMnJ&(b}= zmUxxIkKNzBDde3uvI+Cy-t%)DvXytP5z0T?XvZs5`r<1^yAy$7RJI4_u=M~}gEl!; zIZmZG-}n=+uXFTR`>EeVZTcT*7LLc$egGATGoGTL4SAfo9X3-$n*Qf!HsjQ4%COfR ziZ3~=VIgZpYKiJs+u1ZdaG9M~U066q4NHruoLAz|hg`Vu$(XOK@(z~hXcTzq^sH&b zie$>}ceg6MF^b_=J~OBMHJwIFbQ{`l#!vRT`m%_jo#6~Dcw)xfOUh|)pPA7GZfUu? zMtjb;?#7kpuBZ<$L{Sup}Y6gv`&)OG#*!;W; z8}V$dI9Ptyp&V-pt+Iqu-rT~Q9_ZHrHV5}Xyr*QnX~Y3o>K_fCW!NL$2JbX<@E?;f z`qvjHRXisiI4%;c9J&LD-{r>bj=xJ^((Lgx=Q`KWLYwzT@~70>=w%5N^IK(OT!_k~X=IK0htgM$un-mU!{)p> zzjD*CvQ_2Ll|!da<+TOa>yyunvtWkimBYOFaVY4k?aNb~RMD83X4S~0Y6qw0m1Tn} z?Z*e65pz~zU6i%DI4t7e4NWPz09nm7Fd|jewS7|&qu`xrrLXX`i6p;^+ zC^T{NrmC-9@R-i7*kpR$&(&`Mux_i|%I9~?kEaU$GE-M9d2=who#tNRCa{mxnsPLDR2hmB3f)J=S0rPk}S5-F;_ZHqe( zs+7rbV4WV{dVO^Js@(eg!@9a{T}EbBeeouwN1w-6qYd|~$<+OcEa3M=8$liXYr8EB zvJl?f{zPaRNJ3X3rZaUZ*>lr<_0sLWhqLJ)(DSfz{`IM(S752eRom z;WSf}>EkD`XU(?Q2sI%5J9{oXjPMjp#f(i;#x4ydcjag)ZrNsyzYNnuHuJU!cEh@H zQqMI&KX&j^X*Qv=KKYCppO7Kt5=bw1D1vuAmQD zes5N!nK2_JgwYDaB+CVnU|4^XQUvsROfPG-_lxyT$bi zzeEou?DefwhAmzO7IPqL75Bs}GQMK&bu(>jX6V2$18U-~iapvEc{>NncDbf6P2xaZ zrRIm@#!<#lH|B5-KkD78E#}5kA)454A<*!VFSjBkO)8y4C{zOyKc9(7O*_Yj+akn2 zz7A~*{l2PgigcC+J0b}jzu3au#>#BZ;4cZP0ZOe$=T z#O?3RrdKBO^mXJ&)~#&<>@{w|97w4fXtVZC0+M+r*$D4qq~g1E%s{(9)HAH?uhiMn z=iB<I-B6EHhOs^Xl`tOeUCwpoRdrWTr0Fzkyq*psBQWPyi*5fh?Dw0O8W3riCPaO#Y1u)hs=)uKG0#BY&p_>KgitJK$z?LWP zfL+mVZkQ|bb{<)+S|RS%s*F>6#mxM^>KpMn1EKo)37TG$Rng-rIyyXq?XDTs@^lJ` z*;b+ZGVXToe2j7dS*5d1hD6=4HDMtq!7}EwP%P!@Y`!j1Yj+x>=#VXOO_s!%eJKUg zJM&(+U>18>p3RrS1{?UVG8absi(IJGMk=_|Vi(>d;%GCGexbYqU;EyJ>eeZ-{o*fG zli%a{8G8-t%`?T6!HYUo<;NPBpPsO%JexCH40r`<%QMzRw|nyrW9YZHvqVxy`Ye-9 ztS=iSPj^SJ)<_!tDZE`wB7aMv4ExIaqp+#4`*JPH{ z>P8*Deq&YCvDl1+Yp2SR*!w4}pu^c8Zi%i3Acp#{guq}t%5O+XMeVoSBUMSCkuqWu zzr+O;U|Xqm$N(g>74D0$(t_IlvN~RFx%xmAZa|_7CAQ^CHv&>0S!? zKUjTA6EZf9PPDdXyoY~<)=n1mjaJ`;P3^P)U>P*l+iOt-j-svBUHzoT?g$c@=w<^| z4ZeP~w`mFE*ThxYD!nCjK(4er#XKk4EQ@|U{3W%OgX75nCW3S6ty3{)wA78ihf0iu9a(@V)lXL6A$d7l*c-lri|jGsiS z9jv6(+^88g@c7Hz2)q`~{u`>c(k}Rv53fBJbRfhX)koZfYlv9= zjvl`)$`CA0ZKedLHIV+!99;kgSq>aOI>tpyr(qs_rIfl~ELv09Jhme4a&N(WGX0F z#lAbnvU42*UsmGI_DUxrQT|4vwtk(BaE7r;o%7B0MOw%!1{O{yb}zeMj=|IUNmuYi!QioYmHXn@R;INr8}`{by_+Vtx>q_u?|E8cqb9p93IhV~k{NsuFzT}Xy^_QH%L|)Gaeop|&JWm70KlL|-0%4$TLR-~Auvu~BPRwC>w)dw z8~~!gU`t^Rz$C?~{-NtrUP*``IGYj zxA}p+C+0rOHaDV7hGUkqc(Ii&=Ss82#B9QqMtsk>$L>F>L;uWK@KGQ3Y1c!&-?ieN z7&@qYMEv=m9!=jPGqbWvYsT)-^rRIP70W9a0FbpF-coy+m8>v!>&cvbbb*y2kO%Ty*}sG{bzjXHHNtR52K zh50r`_s3@Fu@V8dXlP7WA#yR8W=^M?`jXOdiQYZtx=cfT^p60o&+mvRPB+C3;7XlK zyw-#RtsW4$EyBn*oPS#ta zlv%a@HQUUnR{{>U{KO`kk;XcL?X$}u^-Pq0?}FrU9U61A0XWcz>j3ZjtEcgmsPdp zlCfKXxI;HINUq2lKUWQ9k_gmznQSN+9n6sYlML+8oRvabhQ3|n_0w6b-@+ZO2AFfM zwJuI!H6Nb8w~NX1FRcODCL!vA@RD=PbnAE|*~d4rdnHy~=}df5$tAg|N@tTwW5@*& zK^v|BYDS3^bME$f7FguNwx9bu5Lj?j0Ghf_CXI!;k7cV8-6qn zgk{+{!>sw3%Q9n}cnwdMhbdW)vUa3FlGVMN5!^0KGYMvWVQMXFm9#_|dR9?2bS8nF z;a==}D?afV$yvT!_a&%1e!e<1YZGG%oAM4b_;iaJ+AKGqEhC=N0o;e^)3*-u1J!6`}@jxal2HH)n3USV`W_o2pGOA6Ys;o1sVzW zq(#;3$2-5p3V&vWe^^JV&H~oj#-X&N4j2E@k0c~+7)~krPvH@8TYcsRk|p$S{LTA; zQLfQ)sruHv){K`-cST3r-Yu(KM&S+E-#MuH+N81@WU~v{#*x|0hL_IcPs-#`{;(n} z#qX5LINEYy&@Tq(KO5K>F}mUyMNF(*jyzPYm1Piawz}(&E0gQq2C%=?ekz4}|J}Th zyZE}(RQ3Z~=Xd9FhcwK&Ec4Dr598oq$wszV-Qw+0=0tXeJHsJ7i%0-58f9B&7;I`` z-+Bc<4CfoXA%)8T@oRm$ojX~n%t!&DBn?J}DmTTEN8@43Dz3ciIA-H8 zgH26MH9>n@%8addlc7ER_&#TOy4iA>vzAn{{GX(DLr>hgAjo;8?XZAdiKZuyL{Mwx z#x$p2JE(#W2EJw6E_43tmcCkkM}~pt`3aNUOwGw2`w2bKHRc`h7ZZ0SI(7+}Rq#hn z;`(qyes7SBiUhDkrbs~J^^ApFpy?-ivTOc|n&-U;^z75qulkGeGw}!(*8|LA!R^}j z?%usShkir;@bRNOe~nA_t-Rpsil1YXf>{eK=4GT+!LNkPqH2R@Vf>;OFKm|$K6`4> zOPh`ODe*R;^RG+GQu1Q2Cwy5~CxSahGdG6zSJr&+W!@|kL6|?9Yn&UqMW<>IMD#0% zgFNZMX08ajKu?yc!&76 z!Uqffu+SBlY%o}4a-lv~C9G60;o%F%)m?|P%SBh+YV@Zt-T}_p;>reT-WY_(ps!Ws zb>4_Vx~2{=W{nt4Tvf0BO!21GRdF?+Zs3vZlUTP)1W%kXTVLGzM{RA+;`KuxcRKm| zy}u;5By2b|8yPUATSi*1gOs$|z=i-I`_BpfuFu{M~uoFMv=1Oc&{6Fg{ z-PVQc#3Z-~pm0m54=Tgb|A8mLwaR*h>|tmvw9f=T01+=tcCy>zFt70vREk-XCf&UQ z7s}%jqyO&X?`pVQ=&4VJLo9-TB@QjTxnqlH`fd#nUdiORS zBb{{jAVAR#vBDY0*<1cQ;SGjE{BVW}RS3ZtlMNsmcNajcKkuGe2t!t)GpNaMgR*s; z8rSyUmwOIcYKPWj_d#97RzmW{?f#$34=+}RW>CK(l}b16{-4Vgz&N+L!@h?+FaY!k zXch750qNVFz^Z14c5C&iIX4!~XlxVjO8|Y1bS8wToSZiPN~_|9x2m zK(Go9J+jELvW+D*+;vWvk1^$O5K>cSWJRhkk^WV!QFi(;PI96<6Ptl=`nV9|;MZ&n zu2h`)6DN5<;f5-|o>5^#sU7ns1F&=HTNftDeMnweG1Pyln$lU~`%qTq|19?Nc@(a| zaC9fetiWq2C(P8&Y7fZ`XG_SO_`7|j^KQ|O$d0>tfPV$$9BvgO9 z!UC%&PeMS^M@TL^dNx~_b1}M)-MUp+L}(2~ z45v)``_*&88??6wcQ$T@V+%Ycz|$p>f0D+Lh5ID(cX2UmN~9?jR%-J7YS`$&M|iG+ zYE~M3aXkhF)BbJaRv#q54Y<&V%XI-4;I!Km*pu`>&s04*TCjJ2ZN+tREoQAy$s2Y* zC;-xT_n?_G|Jq>XoU>zT`+La?n_XP$2|W;>=!ySQu#4!JZKMfH1ND+5NzR;QgMW#>|23tnbK& z_rECg5@QU;MIW64XrtiAy{=k9A%m+K1idx*04NYle*ZE7o(mw-VZRhQ9=RNmDpzGxf}!6_h$YO4UV-{kbo zIG={)4^op0%_GnItMzv4>WUox{{5fdH&v^FFd?&>ziLrBYw&W7?Cte!&(4qwY5cit z0dkR6U&H_0?oPgC&v$}_nA&ogB6TZ0K?MelOY_l}1~01AJu~4yK|?xLkruWN_E5AM zDR2g)KmC!5WcH~L&~WO}g66$KN{}oOphRoAT4V$N-yLXy6*e^p0z)icj0OI(Lox>o(Eu?xaG<8s_iW03mZ!W)FSR;3p95r zfb#lwDy1-AVD)i-MGUJMK)am z9_2Z0SwP1GU(ATpdai{b0zkt1yoqpIF^Q*J+T2?^2t?>`$_I>@rgP8AZllT-h{A`n zogf0FTe*3?a0(Vz@%cI2rSybUEmP3995f}wxwL`K(fgW6}Ja1G)sqrj;Q>3ZK zNCv5z8}?SOtQx!yPSV)Fpd}9o46N041`=iXKe}`Wa6F!sC-lVz)ku>}kriglNjSbL zi2N>j`wJ;k=2+O^p>zP6Ilwa-b*~A96)eu|^8Q4Yn{z=5r zGvz8MAA6$zN?9odJVNuI#Fhd)+Kq>*h(QA~U5h4hI;l~lHE7&XYW?ZQ+iZ|Zrqi!q z`)6d*Kb^X^XG&|`5=g@+lx!%y9o~4aZLjXLPeZ)@6BKE-MQSrhCtxEVnlcGt3pyaS zz5m}km^%Qi>67AASZw5OBr|&S_f7j4!N@^H)dp3P)X(Am1<0u+5R;5ucI*iTnWy;$ z+oNLiNu&EGd}XwnwsY2p2CMEfAT1$nlvM+f%zN+^f!zCk7tXfNurmfZc|xIcEJ6EkGFJuSih zT@@Em=$Nmp*js<9Zt#K66TsvxKzyMPrjQ0)YL-apZ7Hg5H|ZGX~GMsxGFs0~|C zBG?PElJAl-W4=$`?grBv7=cg9P>+zv(3&|^w8Qil!H_~CO@Xm7DBPMqPtN^ zr6(MeN$CdxATDeQ4c3_d&t?g~4>=|rzS$k>19)Knb;j^;M&P9u;W0!&E4d4IW$@W` zGQx6Lgtb1D5MRM9>XmQimJTww_++zM#Yrdiu?-@7R(6!simWNWPNpK2@aF5)SaA!2 zy{q4LIla5=`GL3Q}^g^nYz<&0@0cH$XU;0Kzp4wO);?MoTQ`I$o=Z zlvoxTV=&lIn3tTGtCTS+1QKwFa28Wd0xI(jxI_Jy_MAcW8@~bVp8~n6#vO8z_CBtP zRurt;pyGOMoS`Q07%ZGr<+|?5Ok02D7TKmJR(u~@Uo1mkAYNmjP3{vr1Qu3)z4ZFb zrzQm5%w}vSw83WwZ}2tcySC*ok8d1X@`=A_j*5ZQg72Gc7J1GrKK*S?C-E|!!N+?95(zJj z3`4swqO5dQ9FyHr4$d1q&td;_a9(JR!(hp3GFsBeGa2lDIKxzh0OYc;MgAe^s{xn8 zo(f{LmbSU z{T=RD3Y`h(n^gwsto(a|^W8?wCio<;eTghnN8kl*^edR-(2u`{luIfe)0g3tqDA_& zbLY!2D+o9P$4GfdNi!5(r4bzfwRXPTSlHf^37G6``d-%0?uZuj6{8dC{=L&MWzWvLQWK1zTu=rdJaEkrTt>r3AwGzu&`MEn zTKEb1ATINe3kZh`S{(K)Ad8wNEI{lC&|*nTY=ZpUR}k~nP8h~48l#*bpazYK&qf(T z1~M7ejz3GX1ozh03jl~k7!6rzZq$mik2p?>MPf^?lQHTeQm|CYOSqItH-wiFzfuq?g+zH6x#txocU%}ZdG-Md zvryE8N4OXvdY7G0ms(1uZ3WDGv#`ahwPV-a1?giU4;q6L<_Ro)M(IqZAZ9dfV1QsvbUDwg@}zW? zd>@YDN}^7Cvg*#zFm=KA(WxB*ymolLJ}`@5rO)Oy{^)v}InSk9HK!fZ5Bj@%Fh0`$ z+r*k<@b`#w?H8fL*MGFDfZW^tvHS$Geo8Y9~MgR_IaCwYH$%LHmRV(iBp>E#v9QJrJ@%Px>ka$Ns7Dj`ikKE z0c9<%pdf~FM0u85Lb6%G=n>L4xV*IZBezQ+gKg}hiWcb%l9xfh2UqkjbC|BppDYS7 zQiO$^_s=mLPURt&9hgQSL)1`QkXFCOUZsKT`S`<286|0+WF78~x`oQz>iQ;-CJT^} z-U5&}oz>piOKEEN31$u()gZII*(Rx$>76afW;L?0G~? zK3ZB2_3o*#z13(Xpl@R3!YiqxTF5MHHb#cAG8^jraW)dm z;r+M(X-qnjW5U`VtX9D}_y*D-C}R{Z6s`-Dq$N|LT$*?mx2p&J^H=_Yrq6xc0<$-= zLiB39Ev|x9$%i}YDI;rx5HNHuAvEHmLPR-EhifeDJucX+XRvtgYs=f|14iM73*5?f$HM4bu==+?Hf zK%oyR7?ZsgaIUI$#XyUJ`TXm}|G-}9`t(?dAu0kTb0pj$7F1 z>>SYqQT41@&R8V3btj)v8tUWJu=LKxU?k5@YgOUJqN7vu=Tx11S_jR0(3w`%aWIj) zD&mDCcy@Q(K}bPQ!W~_{W$u>HrVp1^WTZ4V1RPixMd%$^$m#EQd-L*S1S3b2NfyI) z+zxUzNdxd?p!q5Xpk6{gtFDHLXIH{k6ndy&RB(zjchv|@)>~pl0 zui!O)bTp_0PdxB&_w7no*6*Y?uiAN#u}+KC8|L2xDC$1JpM6AsbbfV3`un|IunA33 zpx{~$;kfmISR;;!kBE1?jJOS*2s?f&R=ykyKKhiE(CMM_*Q-9We(CP1E)mYI-PNSM z?UO%Z!n@KhF2TMwL^4X6wyEO1%GX1wj}7{Qi6@$HZbY|vQY zEod&y>`zId@@+lo?IMzxt=gdhsGO3LhttjMFvUH4>=VzeE_VMJv#K#W*3q#V=%hRv z*!ncaAOC{qan5csOG$tHdE_m^9iIRCj9|%T=jyh=PLRWlDvgeD4;h0~LhjF%ZW>C} zg*;!wfk&cDYK9uqKw(S+;=AkxScivAXsDT9$kp?WERUR3(G}ezqmc@Zg_mKyyyzc{ zT2yPs1xji7!UuIvmnfImu(zaOwNpE)Or?@;Xr2kgqve*8M0E>ydan~)9A2=X=-G7o z+WA#;nTYDMfE}fi|BhRp6)@QXJXe}+41L9v*+1oOI)X$^PhXe-)Lm{hd^KS{xXaEq zMRpIY%3MrTTcNMetk|mbSy@*d#o&=?jkrbOWkcVfc{ZXDP(jX+%<#^4;e(?uO*Sl- zIJ}_Zy*Ve@t@ZqBTB_WyuqvFTXm4yQ5Dm$#^AyKNA^~;vX8v{iZ9AuJM;>>Sl&BPJ zj$5A0Xums=GRd>S$M)jMr1~sBr@LnjeO2ZL&~(y;1w0tSvv<7qok~`Ju21pPte`%; zSp%u^>@hDGDS7r3RFW4JD#vG$~_d@|ZX|RSV6f<%JUQ5ec_*Sy z`A%~Z$d6j>shUpvh4h=IXOzsiPH3~M5N`}NhDXG%Xdq}J;g#W9D@{_yrDyJHKoMmGFc zoT}tha z^3b(x=|goBDe+ioilmuxdx!83spOn|_p;ao_bRb;}Gd zTozDuliv4lF-txUbI%>bA+Q6t!X0x(?^0rHhW>F9>o6D9dGT+Ox+@?l1BEm?wjY~W zcl{V8(Ol&ODcKT)btm3!M?N$GxvB4wJY|sX*yPk>0jt_QFrXUT@w&nN?Qmd!F{6g@ zn7TB1Az5}mtSa!B!NJGo25g*j41vM0Ts>h}suIe~Ut6ery)|0#WOhImE%_YE$- zb2&u^q%}TwfJ`wXkLZaq72Nu*kY9!y4c<^V&7k&KMybqab-()+mfZFavWCx00qRTV zvW^U;t)eYQZYQll$tksEM8}+N7H=Ax)L=~(x!>S&E6Tgq= z8Sn#h?30{{g!WAr(g3duo5jCCZFMRIQC-w6k>Pe0LRjj2T6G3EV4L(bl*R6r6bs#VzBwHa@(9VkpN<$ng1P7GWDr+!OT6yW%#ti z_t)R9nL4xPzKTjC<>cflSG5nhuW%oBObjywy0j`p7q^K)bmEKui?)iozKmIkpB&4= zzdN=v3f=qKu2J8Uh1X4k*L~^AV~s9pkZv~XBWO;6m@gvRjQ$1_52h@MQA!!XZ*d_` zUS_nOjomY9E&2vCDy602|2~*AwAV9NmRS!o46;T<=vO1U^|OawQ!^`NHskzwJT&^< z(iyV~t6Ad5-?bQb4Ln{~>`0N_ZxKN7B=;D&L~HY-zfYGn^_J}{G>4ac{AQZQ^-S~hU$ zpk82Ls02?wez3r|*6~||K>_)9H3XjFT662IQCT^O%6nGET+%-CBuJ`;xQ9L^w>=i|`*;j7IKL)$aYPLXZD8vW3O9 zvDX`(2RQgonVJcX{JzRlkp{VmJ!Z^^48p6msZT)2O;A7e>l;2*2hk!%u|%pwX8vdM z3tM^@O#gqR+D@QbaOvCD=&u&%s=Zdrt0GgKt__6DG+xc4kg<9?e92{dY|Pq|weK~) ztX9usvrekOBHF2s!jCLdYIjmk-!s8pxpAY0W>o6gAT^((81_-oIJ(s3^{hY?+vf74 zDx_47^COqok=&&7jhF;;E!`r=NaIT?TNFJ%mh#_Wl15zcv9E$Wi=I|i?z{)XS!*Gx zMStg7)!h`sB%h29wb!um{)rHn7@%or>_9|Gu#9u zsOl8XN%hOT=1ji`?~5%pG`FQQdHeAiJyBhaVMdL)&1#Rf>Fyqx>Y~1im%#sGUn-h- z*xa0@C#qfXdRDNRBdGDZ)`vUxo$&thBeHtj#!+#Srl!^$MbBlEUN;AXT-PYpvy071 ztnIK~(Ze{QW6$2Atc~9sW)99OACOk<1?hpa>HVM;msfi5{Ti14d z6uq=1sHMNj6BQ1PcdjSMe)28pkbvRdIV*+7ZEJi)FKtg!hVsK9Nn~U!oAw=9D4mf` z$Mo->gu(bOTH8E5r6UwcuEjCGwyBX7L2is5U%({I`2`>ONVp1G8 z=p&HAEHtON@f$rabY^c`B1s_aX8jtiGoaI)6M#gw&E|;BshH17Mlv4>d@=SH!sE~x zbA#3P%eG__YwPw1d#U41RD#F&>d{*>1DYeK_%h<>RQHR&z{)$~;Iy@yACH1eBpcJp zNRlw(1dF}};1DC<5GdSI$AaVKWBxo!jf5%I^B)8+iRriQcrDC}{uA)E%_Ny9=J4mF zGv81PcScIC_`7Y{Lq?Tt4jIw_j%6+&a#OJv_9$^yZ^en1obi8P3#!AM#>zk%a zPEqyE)bF1pD3iB7x6JedwSxl8AvA0crXYL#^U?OeTNE_4HbG?3(0Aa&En$g*0&oyB zTSNlJ<~Rt`KWy<~Juf(gR+C$22h5v(OhkthO*4sN7Lv1mmDU24-B)BExtzU#2?Xc%9IbLI;CI62?t+{vYzUox~KEMvo|pCXsa zMdmX0gQTW)rae+!)Tu$2LM{lrM9|{?0fsINR({EN7ob|^O8@T8-KHuvTbE&R=S>eA zXzXnlTe;9XMdlA*jT!2fJvS+PEd)I=J2eUI zkc+0Kqv%w#ER_f>W!rs$p|Y;8MSqZPZjJx62`2$^!M|*cTtP(C-xkKRU3~N<}SRKr%>0$j9BTmo#}5n{$~35{{1Pt26e)xwaLC) zT7&zfi#$8%!1B*&2I0{9?d0xOV!!9Wx( zlabDeeeRpQ&aEm{`z>qJe>^P@C!40Zw=H^y`p|}huC6K(9f`haUbt;lv8tXXWZ=w} z+Pd7h)IzY>PIGooT$?vv=`SYod$L%K3;Dl&odE@ce>{jEq<`JRn0TTS@XVIx%6BQC zJiW7>*hVim# z?Ax5^wuLlaR-kQ_UK}%$l`^RUgiqvBtbB#@UA10bS^ePZk`JH#jTo)Z{3>uWJn%Zq zuPcYj4!yfI_%)Mdb}@9ROS?Ki??8{F$Ubeiq`_x}g)+9;p(Zt>5%{vjoX`#l5nTBd zSyJrQNQ|Y9@XbQ7-jd77f)lNJ7jjbQ$ua==pilSj{#b!=djSH*Yx>&&KIG*pN#xf= zR^RV1I>WU1(|3`k2G+ma7ENz*nD8D&6Pb=gdv|M)y%%*W!d~q7!)tinF>}3DL*gp= z;VCVFw|n=j8b#4I8`BW@5+1)$kCcqT@o1$muhgTm(HC2`BJ~wFSVBwqj*jC+ZD!dL zDReBH1GiHn6(W0(Od}{0%HINu)9US&ebK!{;iSobe>cIey%|6P1(fmtpsvGJa7zSuv`vE2eGt`O>{Za;q z9+u7+=mcxpk)A(7PL}E>95^zl?7RY2HuZ zRxCA#dFKFVQ4KL?aHOwLO}BXo*sEPpfqcT-V%X5_n@A0X-Y6Xs!$?dR^SinrWK<)6 z4!rM+;2mc}0xO#hKpgUuh5(3I>#V5h9OB~~JMsOWB9Pv!E+0tb{oP~0i<_%$8H(VK zq6ZoT(mQyLYFh+UvZ9344qCvaqtGWaqtf2LLB_l0FGZ5|c@_dYID|o!r`gAjhs?gXUTBi}=u$2Z0etgI*SkYC#^lp;eO?qWoN8TkxP)Lz;)e!9Mh{#$<%Dqi4GHT~RKR@XSkyOsFe6xM97y+0 z0fI)|a?n_b5N-Ac$~7P&I{mes*ExZ8aZ8CE6B|0Qf4bgc#iRUvo-Jc-wQ&~p=FuU7 zVNuUHvtQNPO~rCkWig1s;!uEha-{SC7?*yCA3M90%`PRX0@1XMGa9wr5uv%O`>)Zc z)KlVyS6bE8y#FpV!KMR~XmP6UV!d+X#RE>!q%uHt)6LW{_CjPYzW*~S<~#LWBXf>66QgVwmB(-&s2&V_tS5^-=@Ol~clpqxVhlq4BY&p>g%QmG~rFcCoWi9%{7RklNkg;6=f*K+#bt>L`j;IiG;mQ}KxP58Th_0l7$R7jH{6N$TY1A-nOoS-{=e+@ z;nD9ho4tZ-j4S-2^k)k1ihUl;F1g;R0bP9P#~r ztb)V4d&t7nb&AjMC)`RT zG;F+{?20@7bGpDh?)h=jh5myZn+^aLwU79cnRHcr6T(=LGygkci`MHE!iP)SSG*#P5ab zXnnvb3Fi80cs>5v*SrOeL`n`i^7?OkH&r2b6fL_^?{=A?P#cEbzV*|=1$W^FUM`ie zn7vM#0ukmnd^n7GM<~K_QuA$Zj&&oQe_A1~y%O@tvBsjpu;)UWz1k!+o`p9aZxF2LbUgPIh+p|Urx88z+2LPr**%LQ3swcw zWBj4mkO9G^(tb|v=iBXIunwQKbY;|9tU(vxt%Gy6)}dV)wlqvZs>2h(ZshZjVamOn zKS^6R2&Z@b&5pu;-G$hOwp*>h19|QHQ2Q&hjQD;HcJ`+y-dz#7J zt+#e}`jQPUJ#Xg3UT~kxm2`Y_7Un->hTN`~c=asg`*Z7C|Fa7nUusIpWPrX|Jg1=v z{=pwXdHabyhFLZl^ttn^?TCy^PuFcR#h-6k11cCLTu)6p{U2`Nl7pmlKS0)({3va{UciyN5Z3*_p7snJ~e^oEA@ z3i=s#g~dV7DzF)+Y zQv5{qWbW~gG=JJL0&6Tj8LUmiiBrhh&BR$~=T9dS`p+g*y#&tc5z*0zGp~7(Spk?9 z5vR*w6XxF-A(xeVvyz8i3-iI_G{EVV8&m6jisf@!>X!e(Y+r5$wN*QtW)?2nSf`xW zZ`g4CH1rqEF&@sY+HmfS*5A`BxV86h{Xg^-ilmx60mwCQwK;U@{>MU8m20^ z|3}?>xHXkFVdGI2c@>3s*A*6NtAwI7rAo(j6(dbWK)Quql`16(>MANK8bG9@sDL!3 z8mfp2p#`bZRZ8fgCO{JM%>mSXf8X~H{Bm7hVoVO_JY}Al`@UyJmzs}``M&uuKi8+_ z`=!^ZKJQjJ6av33ZDB;4nhJ!p_gT0Scb!Pso?>%W9aB9J8fg+~AhThj2tT*e?>69W zZ&$z4$)r@%x7p6ux5|^%1-(q)ok302O<`8VK`^+G+dg3AZDO&`1w;WhzVWarqjDm? zXOYA18Vdof{QDVeMlt3i8j!U+P-fvYQp%%!c>CIPG`IYmj-!4xg+~+sGUBFn_V~sN zU9S6pZ2f6$)Q}UVU5C0)RQ;HWlS

    1`o*1j5uj@0jUlTTZW+89^27{CN|62MRBd<{ZXHPetYvW2_G|&DV#Pv6u9e-MY z^>|fQuhjforRLZxQ+9O%EtD|KlHPKXl*a8D1BD8-ZesgbBize+I1G z*CO32@V8AzRRPWf9*t<^0VKimiNE>)m0TAHtib_Ppb#96b40y+KYLLT5E=DCIc`7W z7=%yw^`v{G#NGOW43i3rRhdF|PG$bW25;(o|0Mv<@N$+cp$J~j$0#_=y*G%}e7*g0 z=xGEhdSR4wX8I4^t%!Hyt%o|{T=#4%I9GoWFQR1KUZZX5H%i@ys+lA5ivM|?l=(5- z8}B$?a9!}y)wt}le=bmcXgrs{va-H^xoVmbBfayaJ-yf00wE^V3qAZ-Fv#2j zfNt6H2F~56BmSA@mCT&V=SS3|_Wau1g2R94S|`3(m&hD>Q%%8ZPhV^kj7!3Q`&#nB z0?H34I&57hS#|T*=Thn(uSu-=X_MkNp9%H$jXPB2jrXREuF}$i$J;@hQIPB7oO%qq zlDuWYEvGV2-52KD<5RPSSGxHG&|A2UBZ6}?EY-BDPUkd}hgw_G);C8AasSUnx$*pW zzPCNy_%{mm|5yg!ThRXaOo71vJ&wqN4^?rfLbD>X66`;q`v?onJk>p`Rp5naT2sB;-Zhed0=*SsQ0^0KUXix&GH$wY{7oM0cl7V8R z-AB)ED1Fzz;+zJHrohPRxxa3qa`&IW8mtt*?XFMrmkQA3&ia`h2%j$CfRVCHwgm?< z;MV32L(qJO7km-1A@nBNm-2lVHE&!tb!`mQ`SiWw-9eLG@kp1`cI*$%8DE6t@X<^BVEp&h1DfNq5c3J{zy%KPo-g= z{mxFN25A`z7%3FJRkk5)KkgkuP!_bv3?}qMx<}b}Sc|V&>Gf*>xB&eVbk)j}?3efE zm_O`}G~xzLz4*~yuM>*Y%o9^v^Xs3}?AyWjIi7dvp?4uv&YJxEUYTE9?I5W^A}1aS zT7rWc90Fxh&hWh{!V~P!MF0Dd|1*12abGP`5?)9OoO-{wKW;Qab`Iw=*n-wEm znTUL5=NjfjDW;a|oXGo2jHP2g4c$1WN7{J!`CBAOWXgH$_s2y3P7#hB*zyJ?RW2qt zcF)-R(yz2b`$&3*_ENqIvj6_vTQ)4(l!NsWU2h()ierxPpHFtdGT%d+=|^uF)*f>(lB0Y>FGA8%PLg zj_?M&IY#3*)D7Y2?yyU|hI3O2>vB0~AJ{J^Yt;=G*zKExE0XOmh_PNMY&;F5Ixjot zXfi&tSwui!E6W$|Cg9#D#cF%F3Pf&d4!se{1f@y&MZ$R~w3K(YYuybgI0*YnYDnYW zg0|rt+>=FQw<;&Mi_Ch!rdzszz;y_1nl(NiR9+)mrg)vFyKs93%K801Ob~X8EF3BH zcqkFABc;C=d7Mxc#2LGh)qgzq^`_3iMMtsnkKgZ517U-LQO#(no^of;TAU$5ZWh@GoAWuv8-CX^Sf z9f-eD<;ElGdrGC-wFV%vl&zE({>O{<#GsecH@w4c8E}1+?4O{yRa->+t_9;i{mr(L zeWSW|skb46$OKB0R}0VK!>%$Mfxg;*elIHSl`Y{aXVAsS?fW*IJr(GJfZE~Ws_W;@ z4Yj{!CKY~O<124vxh8LKkYUy8ZkB4}Ys&A_94GlG;$tUM0)i}Q!#Uudyoh1!CK!aRkJ`x&V;f)q>l zNRY}W(avkZs*C8p8&;RR)}AKRY%29v>QF&7trn(h3j=`@0#&siCxu@T*{3UgI(De{ z*oq`N)^;O)nL?VG?{3Mwz1qgt8+>dhcEd^3Emb<-`&g)QfLGDwuWGVdHlSTDl|(Jz zxyvC`bAGpqF_Uf%-b2#*K3#Iij^1MvKdQ=q439s;D<9<=w z8Q{Teq7ZxoqW8xfHjxSa$Jzg&m7m{U+t1CowF_}8ee!aB>u1~G{&e6qCw)D0$vIk1 zgOy&!Y#8KZAhOF+YQPx?jt_+0hq__9)CkO~*#_D&g?M1QTiQZh^?ArDh5jbj%h$#S zeE~}6M9P=i?7Tl%)cigv53rgVqnpw4 zI<@#D%JPXK!B@VyRGakbd+28lmZSN>3+>z8PdMp0Fsy{@rQn(g&NN&+GG8?_ho8O# z3Y!z`#-hYjw=}~#r zRp3Wu0`6L0nXk6Mhf`Gp`zmd*+Li3au0Yys*zQT=KU5_|DSe2TBoL?@sPPV}N!;bh zSPPHr9e3gcEK_5la@bcORi^*I5D+?|Wby2kq>eXJjrEBY*UrT z5G{`}WL@DkXODxn@tC7&CwtKaG&4@%-;qZK*r$q^RnrzJCKNvMQO4rzt$_LQdAxkU zU0;OI-90lHXnCXhBZ8bw=`b_?<_pT+ z@JCAgC?EUhXa@hN;R%H|-))NUnoV)s$$G?G{?wLM5ns1OccK_e@QZ{L-FlamCp%CF z%vaSHax_=odJNxxh#0!a>iqndnLZ3<{vn!Mn0?DXmwgJR5%p^86eUgXyA}W+c)*xF zT(w|r|7nt5-p5E7S+1Wf2ojtbdNUGXrAP@%dQ77Wu_)C znJ0Krln664(MHo8eM8_O8^JW!Q0djz*k|;@nr74nQXHx>s6WEV7V4>2% zoqi~#XBn+F+~rl~+u;oAt_U*;Zdu~SXzPPefg^H3)=3H_RR}gC>AHXapPf6@0`G(K z;nF*LintV2?L8!7We?LBp77ttR(4n$Ri{g|36a(6Mm77GdvnXR5#dqWoiSwgB71y$ zQ&9oFV#$}*gUeJcf<)iRh6}6I~rd^g%a%`>O{O3%pT&Y#@Wa(`kU+ zxi=r}a?TXif4nV}`06}i6K7DeB=N^O5C^R|vaOWc3Dx6ePx!mn;o49OpPDS7ey(yw;)z!`%Za;Fdxs@VN(2tA~`5S=Vo%<9_9U7z$ zcw9O@vIv^*hr#Z#`qV3$pjmkOe2`aw7vP`fN`cR8jbDdI z7qlIE*@{p@*lsvCpkV(?=u<(Bm3g7XL8?Ooe{%aocJY`>*L=!g9@xX@PoF-u#V=6U zjYk6d9&6+X5D>xJ7TuV2rX#yTYmElv33^#fdfBy1%)J_(dw)5Nj7UR)#R z;wpRXcTnH3yr*~I-ObEW91sl{BCrYp$PPn8?m5A`c6tX-lRwCCRl5Asvht3x7sg7@ z@J;5OL>Ng#8|ow?827c>HZy>nAE6T!4=ppego4fXeX9-`ysa}3GmmG5ZxQu8wI9)p z2Yz{!DOm0Z=1%(5ZdBZPI$ChoXnEw&i|=NbbS#tNqPNW+>bgq+}ED3 zLy-G>ImF}16TXbUyw?d zqpp$WISL{rP-msF=gx^R28Gu$z#s8jUT?A~QDIEXAVSRv_LV%NY{;1)ks~ypTTIAy z2V_X(#;Q1Ye~b`Jl-CxF1*TFQyr$zx?4Ih3oTRQSt@yz^ReDYfl*MG}LQqSMbW&_$ zK>6x1Q^AT5NT}5I4Y-+b<)nmRI%A^UDpy?|sSdZ2%}nGY88GrYw#2JK#zDeGdbX-i zMfF>3eidI2q#JPi+c@9PiHC*pF=BZyn>BR3Y_XernNdx5T&lE9oM7EK4;q=+1OC2A zxXCJO+_6^4Iy1ANOwp9+@yBa$v3Q2u26XG+sNuS9^nwe&^q0qvYCsa%)G~Db+2JyI zrkg7=r2Cz~rpFP;A#356y+~Q9KqL(==dSp(WGj+^3?%;XX^vWKO9pxMOLLv2C7*a9 zkYFBV$VDSof86pLOGU-UnWPeL&%!+TZL*xmd%QH_Yqr)lp8?R8h*sr*?oi zve7p8AVTHdUzw#tr-Op0xmv2wawHnDs-2l$C4Eh56XQBcf#XcNzt9riV13w1{zL|-ZpNH7aXXRE^;Doq<~|ScBM?&Qj6NTQZMC|(zed_ zVS?hZA#?M-{^{6Q)g4yu8QbBHSsx=am9{TkmR{JdG33Lj^SMuMuT&FX^z)n2E`8n~ zH1&Lv_#uu{vYDgVVJg|4xVJovz%1N2<40U<4|D07Y>SY0&Jv4p;*UFmcjwX;44o5* z?$UqlGcj-CB5ye7Nx+MP+Q@R2t%mZwK<^L29`>ku5^f(>ZizeX4yDBB=Tpi1(<1~K zMoIX&PiDg$meVES3RgKORPv|3Uk$3zC5I>WS~nE z%h(~69uc@qG;8FrggT;oB6_W^I5&R;f!dyGK9BYWDtk0dAaCXZ=VFi7o2RDpp*dc# zUjk?D>+rV)XpDZ|Zh6T$+;J+8{g9Kbtqc{2mbZYQq2Tka-|_jQf{KiLx@#el)WdOz z?^8@(HcqxW@yoX)w_bCzQc^9IGlH_M)5pX!j(b}RI)*?aD}RjKiMg``4Q=M-maB5 z<;gYjt@Xb98T^VJySB|(GR=;CH9KiXf%O261zK%4mEgvBC?E4A?U;5Db&7LdI`d`T zSVw8W6|;z>^1Rtc8Y4IB$)3!+4E7@}{N)Sr-hY`Z*nfW7i1X}hh_jf{^4A+{FEt(! z)kG)XWv7oSo3?A6Hn%b%XrcRJ9&b$6pN}9upN{_BF3Bc`Be^t0vHT#W zO#PP>hK4q#+KKIv`4SY7lY{TkqLP7sLf*Nj{@h^=O%BuuqR80hI;bOKUFLSXq@?7U z<On`fqqPcpka zBd+K7iF}~N6JC2okaz@TtOzpf)f(YOxu%>F+6rd(+~iD z)K%CM^6AJt_9)G#(g$SIVgHj<8h;sSdLL1ya^gad-7>#Gj`^0>Cjk>TqMX`tkh>r` z(;&~0AQs7l9B_=ML7p+8$OFgtcf{*b?WdtkVbpGQ#tR%?P_oe5SG;PU_ z<0@!)KYOD-pS8kk;NZ}MU#MvFwv$dTKe)22Lgp-aRMOoI>WB%>MTd&+-r)bL`XM)KEFnY?sQBM6`_4`9vEKo-shF7oQsY%-JpP4gQ6&XP=i>hds7!lg0=* z2d=YarC!9Gl%kg16OOkX9(m2mqzt<{HSSMuOgLC>R&^2OC@kI9~kr>(3^ zPTF}B-wk&@I=hl7y{oNXK(WM7@hVZ(q2;|$A!WuOR_Qef=K!9G2D?OJAcQN_h|&WH z$TPYvfqR3G43(eRdpdMyB`#bG>~3D`B4?`p)6YCvYujjHetcD#>o`Dd`gkUM#r|? zCv&8@2}HNZH{%{60Rlg3OG8YxG4ar@UAs8TAs%yhZ)=7887_=j)u^%HPh6=-CjFi( z{I=)(T}QU=u(7`_G2vD84Lv45(TP8I803c-k0fqiSwqnQQh{{jku`mdWkW0buaKr^ck&U2Rb!3 z>3Tr-p@?2a=QZ(1D=RD3xQ>Iwv6u6L?J?H=H-xZFR1F!`lg_cj=AL=0xeRv4NLM+7 zCJhTmEw$0-YK}vle*rgFim zsDX=n;_-h%RYnts-aD@7p)=$+hCZ&jXdsKDxv%fxP%D}hzQAkbt*@aqk>VJ%h*@nj zBA@T~w;(Lm32%1Jk05N{7jR2{iFu}bieQ}p8h*M2QHzv1`|S@@+)Qd8Ps4*7{Ph-M zwEFk6gOJXep+_Z~MD!;gK5}zdL+7)0yl0`$BWuqO2_dz{b1(+VCH^1UJDLQ{`;s=z z%bvWm^w!DD8k@K<-X{rKU#~NjizWK`Q`209V?KFBj%J6m9XlG#$Q&gv##+<(+E#W* zX~vd32M2aVuL30D9`hMRx~+&!0u12Dopqa3u|OXCly8o#x-DGd7J0|1Ip}~59R$ko z6##`kFOU*PxT7nA;$3?&RuLu^iX@}P1**ZEr(p6X(q!wsO0((z>K4BZ~VqRk{Hi~ge#VJ}9Bj$AHm4V3E*0jPvm6M}W2UC5R(up$~x*EjYBmxWxuTojO80SQ}-eEL^OtAra0 z-ItT?p5^7uSd}t7OZVte>8S?ED=y(9hD%G;)*;;wml^lWcP%9R%{8AS!9UjXbprRA zDjcUi#^)TrFH&M8T`SC~?%8canzXdEPw#T40|@i?!4q^tp}6aJ7IKW{&TNQ6PX5F1 z#&JMWUUK=OBI~FE!~S!JOfwJY^U=~OK8@9wX}1sVs8RQq1gIo}!H5{oohJxJPDa|F z74X?~Qld2t7ndK=uTzTiYA;(J4`*k}=QHapd`S+JD{MsY)l3r{&U(lgj+_$X6IF$d}E+D31bPLh`OLs9O@U@wm-**E~A?Lkc7_%*yX$xdf<$5avkx?WB)ny9DMa;cG1R zltcK~Z z`*p@RmA$6z?SWs%@RX$Z+! z)srb<;n5*j(%W2j?C@aQ)vT11NKCZ1d)PH_u95>Kg%Tu1DvF&!L=@1-6D(>5s+WT6 zCXoyKTNr+X;tlChsN>lrPN{njF%^B+CgOv|hYn+kV(Zlu2?aGh(Uplqx6qX?BXKv7 ze9f-6!0#;-fpxs&a`0c#4!$X}z?t`nk_X0-je? zRGb?bGL{%xN~S*Ov<;D9Fz4C`Os!CMYrZ)(VUbbkG}LcJ$-rx!TquEZ)sW3lJpc8x zTIHh>5apdCdNe;c@6oi)S9Z;sx3{+y1bTwqCgMbz)r;A)b-f{rM~^ZxvkGnRADU_b z_&r59E73k|Z~1Ku&U6DtYPbq@V_MFtktC*++-@}VeREL=KAcu={n(y`)@b@#;-JWQ z)?HMhO1eCCfD2VOHOw5yn>>PXe5A^Q8dmbFdv^D;TjsS$dpvHz;vSz|uSAraHaP|43w7la0?;7eLnQY{Qb<_AFohwzA`~JjFUVAg6TcuC>o6 zm)L{ZemajV+{cFVI?qdvP*quS5n5NwQ~STwhZJf(-E4E5s*UA#EiCk~OUjnb)9k64 zlPL&?1Fv_Pk{M3pw+$If2!p2Fmwznq-Dli^iUOe&;pkaTLA39%yqphfXwJ zw#r8YA{@Vo5#K#1-@jTF8HRt}Kauy%NiGsPaz~$3&(!4^ z>%PjFZ~By_dG>>FFPsvxu_HUJS@9-wZK?EPHR)z=*bK{KSM?~o^vZ;6{7Qa9@!K!N z62x7c@GP(}dNUJ29O>uJo1GEnUd=vEcwUirAy{vVI84FIez9 z6YJ{g5`w4tK;YfCEeN8&TFAMNTjt{3hdqGmzEF=I*w+#)MiT$-QCeRD$4B;{G|3-H z2sGx>8Z^ex3>2PUA5rw`QK(>F&6#Fka`aoe?hjuPBVjR~^^@XV0?5L3TBs`Z8hJFa z%}$R<|5Y;W>C?|o#0{-n?)mwU8Y4!QIQ$!`0|vU&JE2X9e$yWh>pfY<@pGHARqeli z@cxY9A4wU+CsLBHDCI`rLxmg2|zTY!Af9pH6`yk!ry3az8qv`?U8saya-9Y z38R*q9tc=A?T{I^;~4!VPJOFCAnqPX8V;vh!=5gV^;9Z#e0*friM@&53yC`(sI0ydHOwGQA7<(INWZRUA( zmJ@}p$a(AY&daklXTVCCS~2UI+OJR6d~{G=hjMiJq$3i*u9OHmF8Zmuf5Ng^qE=+qnP>E~j+KYkYZ@gQI6zs7W(S*O`(-FlTGn+_?IKd1 zmv|Q10lkrhilxIg&~Ty4F7u|OK$Lwe+Ufl_8I;f1?J%lrdUjD$ako;wQ*M8k16wS9 zQfvP65s$bXQRGy5pY2J;O3(lX@_V43!f?UT>H1x5(23zrl8{ERgyGVg84K8b5IKD7 z=yT3zu1-7U5B66|1^kY(%rPchj2{z?e)i<=bsd)TCP3-?Fj&GJ?=Yzg6tZ?nym4eg z(vUf(!#EE^*g?p8V1M>uu(pwcIy=B}fCJ;Ip}7xbV?pFYQpI#jgRl!eoP{@H&XzR# zbas6yHS8D&o-b4(Z#j{hQ>4N!qjX$bITp`K-|iCXZRI}pZnz5_$evQod;8^vr53%s z*iJrOwxVFzV)XbCev7BQzoMKI?IbL+j#E1tR3ZHbRCQ>mkACg1QQyhKKX1K9dUJRY`E)U!aZIdM0c5=yuoLo z2|GO_(}P*@w};k49;pZowznSym1(E4A;hupYW)hycu}oiZtxim;5d*xrDKZ+b2XE5 zvuE#_k%i~Izs3jsZq>$#dK?Dj^>iQFdJuly*vY!w7QpbP8n7mzHc#g7;rVu&HsB=6 z`+doWPn*(5W5Jut$j){-lMMVqX+v&S)(M;4@?@ImA$)1WmJ`U)i^H#yI2RE_2oG#Eq?!cDHkS3` zQ*!BET-w^6YR)iiTK)|L2ZV`Q7#fV6zJg}HF=jxCBrv;|AEka0NHe}a6be#SKW54o z1=7+YbubY5aV~O($+e7h>AKilnfn^ZPE_699<(qTD@;?*GPoVu^hHn*TbV*52YVVq zBk9Z$*2HQhUumyakg5tm%*u+Y;<*Y=OJ!cv zIgwd==qCp720Y8m zwQg8K^J&ufz86H~2Cj9#UFLFVTvYXJwNCN%WK=t-Exzj8HXbhX+Q46DXsLy3vwF0H z8FajbwVZ-ui8~ct>ENPP#MX$EWu{aB_*DR$1Z2s0VdUfk)+@J-G$2*Mn=J~4*E%pvNe2W~h1|g2Y`-tC-gObsY#Q zMLJUsq8QY5 z0WstHnM67U4up0au~T?Ryh_w)N^%|I5)ULW z!;wX1;oY^X1+XEc6Y;mD%TVsXx*v!21?wWCo(i^EZ6#sADYda!_Plq>V?arU26<}$ z0gW;CHY6BJghT<%w=c*TF(~XWdwdcvA|X}85xrsNP9CrZGoQG+s9^&QIb6b#P=X-; zOK>P4*^u{Ly*x!sjnjPY5ANdf*d{TGI+rhhq)zMuV@dq!0v*pu4Z{wd5NftTqC&Zt#Rx< zn1*RXZ^UZ;UU3>ap*_HHjMS@j_C|9Q4IGG+2TdV4lIP^#SR0#uf%y~2 zpYUlb``ZrQlYyO%!@2nU>x50Ri!FFj@}?ea<_EeBM2y6x0oSbL|eSxhRD`!>Z>Z`PfUWPod1D71@uNE%@|OEt{Fy8f%AyQMO#wNfX(v{ z7C9APqO7r1`;Iau@Bx`ny+>9yX(KtL@5Y+pu#Qu|Obbt|?~m<*(QM9^DeUd^Zc+|# zK)nCz*IxV!H4(u&#n!Aa(dg8r!Bh7jQJV+xSkqApfR(sNMvbR>KnmOn*J--M;n; z&C5h$d)O5VA9gy`poub2N$+~3d+g9t#LEz5jMv$bsnaW76^v?|ZcR7v;2L%n>zu#L zSCRtQj6)hWqIQveMVw2>r|5&lx%*%}9^2XB?Nk8yG9&+?WPi4aIFjSPti4g838gN* zR$u!$Z3@khRMRGTU~Kn$385ZmgYU>OVwLjB)}nn6c|zyXs!(u$Vb^(TwRfv2h0@>S zc^r-yA1r(KglCj6O!-I-p-tV=CZp#5i7iwmx*IliIe?AnuInJ^~f3z#K2-4Vzmi;_?1} zk&+qhfON8^ypK4dq{jE zyACXw-P~?fFl6yW+7jS}{82*vqah1Hj|vZ!?vNf3A68UoE2bIyJe4WPzt~i+UXu{) zhe;~zRu>#f_G%0~SSZwSHXs#wvgJ#YJ%Qi82G7^|7&`zutN<7=;*ok)ZW1VHekDVk z+-8C8+mR1$?{n}{i5HKY3eZ%2ZBJh5sQO`C;1NB8R6hfmRKp=a%>X{n8|YIZsEXic%c z@o(g>0)E7j{QKoA2*Cco-$0G30B-(2?=*X?9X9`ZFQo^-xPSc{tW)v%pY1Bv{wLJ4 z`d{5M*52y7xmGLxUtcWQ@&E4|YLVELo*Ip@ie+*%>to4<;uS9B* zp!fS}t05pur2^LKuYxaQ@bgo{EY`l^9pcM>87xVkzw|& z7z7&C^=l5>f1k5ZITzTn0!HMT>M#1XSM4Tp!4hh z>&y4^sZLKXwNkwYcTxDJ)=OV{bg3JaAR?1Gj^v0`-TZo5mP zd)21yShYeIX^_mWe^!0%#9aH?cdKX_!|{H9Kzv(6T$g<%(m-f&&I(~LAti17?@%plNfo`2I6WYQ8LA#Ye(8r3#H82IiEYU7(0i?yPAxEjP!J= z^ZQYC=?WwZyCt7Ww4Owu8gvGDS@-K&)0EJr4?nhIVhad&5)}2O%?m2OG#~Zu-c|ep zY&fLK>Bdea*f&ayhojZrykDQa(PuxWd@N*UI$q6jK=e5P`w|R@(nuLG0|X$(WnqQX zr8^OJ#*K+Se3r8jr;fh=`P~eIcy)2TX*EP5>Xv7B>eRzu0dv@8ZdD2bTq$rXWK5pX zbqS^4DKVop7kh1}5|06VYozHMa~F8|r=63F;gJX@9R;JC_;xeq*zaTQPPB~mVSRuQ zQ|qt9+M{VA5A~*5ZX2r(*fEgTHe-Ym?N2`JFT^B$huYQEeoo4^fZheh|8s2BuRbRT zoqVP$M!Nhwd~KEKnxFfzd-8&(Z|ixF+`ZU%+F_9s)C4V9lcc4S?1 zjY#@n+sfz3?WfCnY7_ZSC!kG(KuRDS9!pgFEH#ppO&MDG5y{TEp`(-lt{O ztKv8Rb3y0q#-4%;r^yoBt)J145yHREtK82Cf)EC9rSjO-TD0Ou(s8KV#~&x zKfJfRCX)GjgS;EPu#u^BPUIlkvc)wLyMcYXC?fIreyslB1sfHkIbXu<;o4v3 z)3q_jBrVF0;|J077&)G`p|vse0~iTj4Px3S9Bhq`41Qx?53`RQ4i`?@n#xHo? z4qdl@8^W!$s4|p#@iO0uDgJ#GhZvpUJR-mH91jA(uD?P9t09@ryDh02@$`RKb?_M) zdTyfCo*vJYBi-6iW~7AYeLvE5!!mPo$rvv7q1?&^cd%%OCjW8Q3|Y%a*tt8}{@la< zXpF6t&H8Cqvj6A)d7}^Y!FUIJtUj$Ci}#ARftsuT+(wQ5QxRuR-CI6}G1|YLe}F1E z@bgRQ8tf3ioXW|pr>xu@<|0C+nylM>-@nqt$4)&9a3lnLXBXstS_a_}pf?(G?{}v; z!%T5g7Nk850lP-Dtwzp$Xe<7)d-~q~-wB!zfcUJBO3IOtnSLt)BE2IcRym)9%k9T{ zcMlia*S-snJ|uujY_`DM5k8CyA&|bKMf^@bcDlbRc05hZmHZV6EF)P^D)jE5`C_O% z;s+cB@RW2*U&657=AsfHI4Bxb4i-}1FUUK9qz;Tedl{L~ zX24EID~s2yTNl-zr=7naX-seUYp|zu_ki=fNB+d&8pz;AC4PpKFPRnwRCWJ8I-XBU zdN+jzcAFCtET{kLF=L>v!oGzLRz9U8NAeS1>ZP@5kbL%qwwdd4!ETHM%i znV@O8L6rE4*=cY6Z)nq#{iM!%;itk`HlUzEUb-%eQ1zvTxe_-S&^DHl#jLc$(1CeQ zv%%@#lqowa(7LJlwhUqD!QS#XwBC2hxbH6TE=?|(Xzmz|zXeUvUAet`)-D&?g4D~E zV~DOrZ$b32c$i3`#Z2k^Z{rhD8o(6SU@$AY#%vOX+P_a^dqWkOTbG?5=N_k)k89Mo{Q<9SPF*v>wrHUS%1a?lfROL)R1z z&ReD$6F4JflI(Az-6Sj|p+9)%ifUjL)Wwx~)KycY2dTAN~760L@TawO&NTS?Un5k<}4 zvK{7W=GhPCYyIk>9b>T@Qity8{X%=~^BjQnsfP$*%St7yGl z|MCQyJ^%f`W25Nn;YcAd`weSwfHxf`Gc@r1C&<*RTErXXUE*?Z$)*#s+OJKh>U*E& zT7N=t(%sJPCv7?!q(~65Dp?P$8l>UcQ6B}9u?^W4!n>aBaD3rFrIlXL{9nZr&>=(qyeK)5g2Y)!Qs8AZspAdX!;l7bV{>E56uK8C0*WKfTsfY*ef*kT> z^$J0-j$-IFpZn2}&KMR@sg z90}&N(pHR8WSt2)k_&v>creWYS0v98Kbt zc^ATl!PJgm_||=YsjcfX;46(NL68W`yQWrsV8s*nYS7jrZk8^XTW6P3F@wk3&Phv; ze73V|?Qk{>0@2Pq72o@?h8<{pOo#C|VE#Ha!3gW>mR)@LCNiqOd)q;36=~D^wxY(s};FvKR)Q;YNQoH_eOd`T$xlugsL8K zm*3~aI{^?1BQ+f+l#Ebc*`K;U0D(XXOyy~65NH)_r>irc$-Hiub2xD{V6mZ6)O~^F zMntr%JZiJoR2r{LEXMe>ROxu0(V(s{5Ma(Dj^W^R|1;!D8M=4I+9`!lum~vO`*{PO z9?e>x>*nmTg@%iPU%c@91MW8HTsa=^1Z^o;0<7LhHp3@aKFug@=JM)lTBdi;Vhp8E z)z)K{1xXuq*8^6?dHa`RWI*+yHr_Dc2+AYR&b!ThcLi7>+CmKfFzvw=eR6}i)7|5M zR>nJN%~QGZ*&S?ojcHc+r0TcrX@;$y5I+0e$?YUfa?*-I+LKnshM1Hp4MEuqWB9E- z*9)(AcgG2pvi%X%hC8T-8hBjbw@-cL?CJQ#Z$81F#A7_>?|vd{b&UqkqJa$ZnD3Pj z9_p`jWWJ&IV5cb^)?OFCZ`y{)GH9j_FZCygPUdT=*Hp6;BB&vbw%HZAUZ&N5yo=Lj zc+IoDSq@H62DE){}XeUOvOEJyEBgbgC_=Is{t)P=8o0aF1W+Qj46*o=ystd63cMG>iXV`>>|K(N=<;CR_y*`ReZ?boyi9Q6o39t`JfK_M{kr z`H$u%!rocM0sPROYg{WisI!06E^vBwd0IuMsrl%m(c0SPvG(?kkt8ejgL&gaXju0$ z0STLVp`ay^*^mmoH%byn$p*Dl`9o@|ELxej-o{bT4JSS_8hv%YrrE?DF)B;>K);8Z zCJB|)zu;U%SbjdMAR-@m0%ULbELGdUJ)-4oPYJAoHo_gK+F=ipwPugo;>Wu9bTYLd zNOVZtQ4tT!gV=|lO5?JuOZ7nP9-c{= z$S$F)O0xH|%O)NjgH{5T@(6C4IkLmz%Il})pj&VP#kwLCrZHHt50StvoVUeI-_~5L zWyQ|ShGhrY>IJW6;D@8C{Sn%dn0kP>`%=C~9)PX|5*JM}>P-;u&(e25!fGlCp%b}0E6-PLoB$s+0d`#;eJoF9)+%>23&w+s4`HM3wE7JNuT=$-?Jr>c^X!nK?cbf8^3$ZisE1 zhFi|0C{u==l4}wErH|qtMIQ(h6Qi%3hct=RN=s0dj!%rsw4VMAIfhrTiwS4WnDMoN z;OkOYi08niWi{ezi((JfGkC18*e;BzvtdIT^ta(T0M}}MEn+k`kKP&C8wrl7bd>V1 zsD@NC+X?pYw|LRUSql5fQJ~5T8s?-aZwH$^^5`?=#f5u>n=QE_)a8MX@Q;u2d<2+O z7HC*G7kO(cfQ8kqc?^bkO$;rhlXHp%UoaI8EFQI{u%=0B_w-jPGgz~8o3P1|n8`qe`p2ZbRY+7!- z9TvTB1I$B3g{`dwAxH79J%b$Oo@8dVdSVJUMSzw;glUE_5~`p2Df8e|vNS z6M4;&y*wg+PP| z?BsIB{pmbSHrJ}eKjQzn6>OgMbeCjzNnv45$JNwqzs~ZBmnj!M+)H&WbnVNZp7s02 z=V6-F^YSeH7yCNftISnhR;=SI0y*+Q=R^W|cBo{Ug6sbj8S-E#$kVwO9F_T~=;-!t zQ5{-*FFQh7|MA8GN%ul3yM#V9z~s5TQ5W&nj6DSqse5kmBfoZ&N zB8y$Rd`Ci2Gad~byKiB)YHGMJdhEAtlZS7Iitb(j za+dK1t9bF_U8);*f!zU0-^?XG8}Hc7ksH5DcXsV}-K&~R(zS}D8a>DEHG0k&`i@E0 z$u-N&el_RHiQY6`9ZuFHWH#v#Em@CSOkKdzO&YChXAwzWWcdBDVF;2sF`Q>u0>e~S!R91Ck7&&(p)ZgL3? zJm|PkYwbTWt2P@dtmrWJY=1eHy+m<;UG2#!&QYNVB@`C=@nNoM6{3A~g8Q2f{+!R( zkO~m3e0*Luip-17OyAam0Ew>GA~dVTp3c`835mcxq{!I7cT>TOuXIokhG2>jd0F8K zs5VdP?mlNGaaS<%V5;7WygY@$8eF8;F&?s{Xjx>j?W*|}?N%M|l{4}xOea*-m_zgV z^%Z)2QGYBM9sN*{5HcgTyj1CBp21#C8O(3(58D;BE#2$74*QVT_7IheHFxV4?%Xl> zLq`SHfN^}$R7(yvOa@X;*7N~+y%8H_Q&LoLae!DVshC7ERTfos8Ht<<^S^Xcjb5-0 zDRQ}po|wDh$TPhe<>TBi`jE)Dsh`2|2a7@mG_*=<0l$=fEJPd2Yg z9+!AMI59G(uO#MAfs>FxP?yj-@wRM*X<|Aq==s`)XRI$b<&4s?NJ*pGubP+*5 z;TyySIVziU_P zo%5p1HYYBT^`HS7FAZB3 zdj(3ztA%tLLd&Ka`=FyoKW%hwOu4jXz&>V0aTMqbL6XPg8^$_UR9QxcQY_11d5vNF z3tc`vJ-R6)bVY#{e=3mnDH!TbYdFyxOHDPVev?W>R%Da9fASeKGn}2|wjm0usq zl)P`@lt_IY2p+$8y#wV;hSsGC)3L>{DFxi5D(Ca3QE(*qPzw1eZDRh4y6cpwZoav# zFN|HN#gbeITFJ$504{D>Y^ zvd*mTY6wZErNppj?}a1zN=x$*t&}e|&Ly!X@AGkh+H@x~=hQic-SGi-_;Ca6pXu?86hN^Y@^jjn>DUd&NG^0vMbryJ4c^{4Co8ZYR}Mc(I@O@M5w$58S6 z;xS}9e?3ysKoMoDdR5Xctb!t-kf&C=hn-~Yw@Ol5c<-aX?6S6WP`asWWy+nm-4RJ) zJ%JI>k|MoF%iE6}m||i2r4R6AewXl&6&Ujr zi`WC62KT!z)`!eAO|%E;^!a8o#}cHuk8`#an|4~u~{KXknZR8v_OHXO%MMp1c3M;ZEz2Cz_+DjmlfkRk|3ccg=W z^b#PbucD%$p?55RNRtwf8Z3a35~NC3X;PyE2q7f-_YGy{{l5RZYh}$Wyt%pe+;jHX z<=M|eUm0c_XHz^J3+DT$T5lM9{9PwO^^myGC)u}QAx1Vt(7T`T8I(75omtRMzTYFS z2rPMRg0_xZ}d;AK4*jcA=`&#%4;M^9uIY9^Ip1RFQW zp+O<+=uqO(kgE{`E>n=0IMNvi9&C8BS2NS8vqEPRDfD*hlhfgXfo%bN^IeSrHlK@) z0=q3*#rvj<{CZ2x)6>0=vavt1!>GO7dM4SftQ-1`VQDe5aLQ9RJr`e>pAn$$8@ceBv1(R-27#%1+| zf$S0{euow`EE9vwWlew9jFJgxdxvaLRg7ir&cK|!>X2niFPvGKlewl$`kw^HkNX)y z?PX@ca7{YRD>6p?KXM0T4?A3>`^U(4HIsM;w&^R&l>*!@S3^I!E(Sc;1b@z)lTV%I{w(>($$DH6iXY8XfMgaBblJRYH3zydrP6b?&vHBHig1p)xpo7vF>Q?5i@n8oi?k8Ny82C_i4XXH_(ZJCjLGk6$**RO zm46e_d&azxvi;oFXf4ymSl|cE@0@&lJLrNYKMFrWWCzGQh?Kd56?2*PGxfeZU%7a_ z#4T>Ff2cm(F`Hmxn{bbsh!hT31=7mTp>+&O#$^fW2#LUmky&zm;# zsk*c!E-gquuM8@w0p6*as# zD0ZMm*dnj2Sqhs)3+T?YD<_)$ckD^#ro3KVm7mkU0P*Dix$tH?*A`y=mF4++&V*7| z-h+QYNQE4~k=?raaf% zpm~BBfq#MoNBXwFuPk%8CmAwD6nqddOeefWke)Pu!VWZ)Cg9XOcws$kQ z&uwmQz&GYU6!O)0KDb!E69;k!^xQEnJFtzo`op9%>S^#S-@ z{r)7r^4TXffMCsSbLo8HqkEh-d9}E45Uk0)`HszH4)ymZ$+t|gH=DIZwx%cWe}6wv zKH=`r*=xPFz;sPbO}80-{8Y8lKP=zXZH6n}Exu~**S+fByc?TNbc%8}9X%i$_C4)B z=tRUvo=;McA74;D8ae1?NU&;XvGg2^q1nzXC`tz(y_^qJ?ct_&fPu3bbWWx5%LdxI zL5kFQVQ$X2=kqu*ah$m+o5V(i2a0$T?Ox;u zxEy2apzP72Hy?8LK3t2^kXIHz6l8JM-J4`^QBlIj!R27oq(_0%p)s#>_n7Wnnm_Id zu8t6)aOl2P+D$*w)Ml=WQBk8O(I32P;JkZT%Y7VrAxK9K3!Qn6fvxZ0w+XM+7_ z3mHY8G@qh(ZH;8Am7;ZsZq3TbP3Hwk?5sL@O&na)5IDKx)0)l|UHSN@v&Vc{LFRP0 z+#rsKY9eZ>aRAPV4_>F?lJ_h!eUPc(Ts^C%(4=I-wpNy|a)kW|gpS2Uo{?WyK65FX z?QtvHT-2$H&20aRo4mM?7V_P#<#=F06?@U8GtjlSwDE*^vQe7HrsuDtNl~6{*VSZ$ z-p3L0Cwyi*Cu&-@ik?3m99YV(p1{7NfM|0Vz<;rJk8klN-+8D_QX;?S$jkX*C#*w zdAxC+0{CF}1!OC_T+CwQ9Ih{Nw|JyRvKhWoN;BUqJah|ki@%VI$Mh7N%{2PtjxcTW z!1xBo5Z-RZJwhBk;Yvzum0UW`zUeugPlk&*At5gKliW)r?4V{bWxh4XxmXr=|0-^m zld>rB_hJ4w2ppiHlXq-TfED|otoK+Sn^imi={qmP0G_ek5leyB^2-5<88q%Azv!p3 zwB$WmbT0Vps*w#9k7E5MYGt}54H+wt=mV>#i9Nt=wG!cg^3$TCL$iap{Z@#UOI6UQ6US*AZ@|Zpf zE2mk3eTH5sE(ooLQ|(jaGt><(#UClWRuXw;Wi8LYSd%@!DPjU=1I~qDYma%QY)*V~ z;ceKMwVtZ}cw!>->H1If@P~~Oi?4Ra6fZ6(kzG{B47)A;ol^rpFPbrut`5j@3HqJc zwx=1u9L$WMQ)7~Wpf|X%f`MXg1;L})l+@dB5%IXZ;?Ep&V^A&bucVAMKk2Bu3 z+oheC`2$m@iooO^4DP}TCS&%9k1)%ubK;m45=H(I$_rnSoWeqp2#SDZ&vbis6*7=Y zUwsG!7kb1g;d7OXLIAhPyfQ55cP=g5O^dNbW$!wl>2?lZyrV>gDD0JZuK?y95cicK z-NfAPFqDE@kwM%^I}ARi{nX(M5naxra4A@7 z{t+u~-|7B8C~-$}=c59Lilx*P2KTogIsBpnOuj|ijt;jEz})wvHkD6(q|vNf5Zg6s zN_9wzJ!&+OSN(b{LGJP7wDHNE+|tyiB8u<37n4`$A;{x7$K|K}upyFi$Qm&wtOZ*u z?3aWf`UDrmja|4ph%5TMtsQP6lcQ%*k%1&bsJn$6Q$Z$19I|^Y&|iqZr(D4Cs6xfw z*>Dn)%_NQzSYoL$-RUs3jYpdyI4BN`WM?ki4Gr}Dc*l%)=hc`-&smb1En%UYbJe9OAB<)9yeh?>V2%_sV~`(r{8KS zv3i%rF|L$rixx9_?XuvP1}%O`M?Uw3k4fwizu)-ZA2zU~A5N)|zytYR%kDJ3e0lf%V25_qyHm!KLcNtHWH?{gW--h#P=JW+s}EZ=MEg#`Cf^$ z{jRrNzF(*PvKklJi=&9B6Y6q}$H3{}DZ%6c@De_3Y6$qG>(y2|@Y6(TV5B!Baz0)N zrS~~yD<4m43ThoqNeI|Ib6Qky)t6gX71@gJ-Rck~9v~qbW+y^!YUk(_jU6E`62%p* z3>cTEBaN3ay39UTBp(ErB*(3wN$4(F?SXNVT!VT!9_M6H_Iqp3U9{iT(sFJt5HC&) z-g(a8!X*SG9J+Op)mJduWV5IXNxlb6UCVu>@@}>GMImL7)j>7a(zBVgTg#&Kbs@X- z*PQf`R-QS&62Ec;xij#7TTdb5Au8kf>EXQk%u)vU(geoTCCT0#{>UrXxMRK|#%W^7Fjb|!l##bdB`SO{N zG}{5QKsLtHa1BzTdGiP-KZks?c4c-sT(2>THe~FAV>XvHUvEe=eRB#WcOWk++3GCO z1V6Ecr$UKtQ1GX3QiCi>|M%`*hgf9wx6z9F47*l2SndlZ*w&c^ZpP0`uf2+cJJ;B4 zQK+4Wd2LK+m`;IxpPzxuL9YVrQSeYC0GOM2w*{k{n_-eLvb2U|3dJMI3eM4rIcP+P@A~Y|uCHDBCZUEgqvtIua35g6i$8&L6`=Zy zv62W#(Ei(v4i@%=gBagBN=M&wy~2Q+#DMqTQZrez^5vUh&VsUJ$+eb>xj~86kk>x} zbnX7tq>(rRuuOZJPCViKkmfPY=8pV-$J2e1X0}9|sX?LoMp6nj$`jW%v_dPV0+ZO)EaX0U^24G*8f>o$Dr@R zc(-^!szHPO2I&*>ABi6iM|fl>Hmt2KaM>%oo3M1^KfRiX1-CM+M0gs)G{Gyf=c zpyYHkw2QnXtG^^Dt=)5T#J_$!QR-aVlUS=Ew2k(v5*~`5XJd|`TIZ*uZHLVQDdOcD z#^%DtyhovQv;*+Pli$+fZOzsM|1_W4Y-rJ-5@T=TbIr8fFXI_&*ku$y!jijow0e7= z^VAYz4o6*F6KX=qX>H6M$kiYJleC*KKZ}`LCkWAeYWuIN-xiG$G}kWJ?~`_J^=&l& zOJ&26UstcKCU$TrYRCFJaV*)GTqw=qGA(?t3j%JnU!Qx!|Hw z^@h{8{%cf!C>=t~k(DXj_n}4D zdXzSFTCDPFZ-t!bzkee8yr&7?C`vHd)*t^7AfSAl1`1T-jkzbBtb^R1(d_emY)Rvb z=Nm!zDg6Crxlm52v8Ls3mOPZr_@}^+JP%nKt>mo-Z%wqj_!p#&RSS=a%Lk{3JH=k!2~k@t~~#{VrK2dwR3;lSR1X+s+XD$lrP^<@0{Gs zHBbH<#5o^ZhnOwvub+xY4RDTD+u-Hbl}a;rh8!T-EWdbm2lMdW_RN^$d)H1qy&=^k zhk?NLTmiF`3?8VI%`&sgZTB;pH50paCKf5tZ>5;P zO(7~rnrT*#2iN~OxBMmf3zFI=EaHlXL?G#O5*n0NPYbQz&^>B>*6$fWRP|=a!+8}G z#!#pQX1k5^-u?4XI|N%bOsre8x>yi9k0ROM#<{tTmaX(-8`fEF8mC$?6@XAN%pj4mJ7q2IxW+Ipa^`C8D2E%h<`$BS|7v>bi5rc)jfy z&f3+ClC$r)GvDjZfNF4QeMmq+PO?XxrK$a`7=Y}rKMxGP{xiEMK`U>Nj2S|AD}H8S z(LIH?m*p|S?zN1Th#36JVE|iqX|>6Fg(TAB66gW_u|TROJ1P4I=OWZdr}oTD5M8zZ zJ}%N-F&3F+iANF|8$EHYm%uBzS7M8|Ivp0z#cY51wpc~9C*$_A>`s4j#noinGISr> z6setykwS)Q)X%j^lXf0E#n~Wg*{?RXjv}uWDn7`9TYara-2OkWH8ULn zCZH4O%vTQh@F)q(Yq3i5qJUCoEzC?Y(bnShFYa=L^YED9YPjN4qDoThYDOWGTx5p- zbwPj+d7jYv7m(jU7ER6a^i#9$l|qVjyUkNcQ0rTL+|W#zy#jI;0}U*bqDs4(@%R_Hw*(2(VF4QqPK zrI5+`V}5yms12UlLT;FHR*sWmw^b1zb1UQc-d~qp-a=iskFbT;A1{ zmSX$m_T4te>W9y;Ld=Y)pi66BRCMjF;9X>a&1rcABH&mu$F0JUCZ5%Ux*4W?#*dD& zf*v1(#G&ugt)}xT(dg9}M%1G(W_%nduVJ|X0o~YpLn(x=e)SmR1@FaCqMrOjgMdB+ ze~UkWu--#r8v(pT$CVvc-X*u~K-f+a{HccR|5}&Z4nBM1e~A}CDiy;ud@&w2XFw1h zGtpY;h2WVW%aaTN%x^*kiO4#qjHg~&eT}_#e$VX6MI7Eh9t=r>cwc&H_`$4HLYd=~ zK(=dJNbe3!n~!$;m={DbU~A+8C^amD8sU|IkH?DU=Z@Hq&Q3M83q$c&si6A%JWT{C zDPFCdQm68}=EE`;12N`53aXdR0}-(XeXgBH1`_j7z*z~=$?0+}LR8O?M3NhqP+W|$ zdF8|0rnFKPrr~_@(fn_}mw&Ej(R;@F;0GFJs&ya%*hLee_?;g@BDisRGXO>Gue|!Q zUzH+Txv0GIPSE>Jk7%U`HSXR$CuEyD4X}A60RC4RyJ;ANzJl zCY`O8pls)v!jVoXP-h&p4qm*_HTZoTJg%*K>LZ)SMVMvZe%F76WE|twUB$m)r3Pv7v8y`|=|V~w-n=)Y{wDgpCrnMLSxF zy~8QpTnO?f-=Ggl-~3noeS1r?14de=yxNCaKD>Nw-BIBN^?p9M@L)jjWw(m?TyIOe zg=wEpcj}RUA}%Dwt2r^HPh(kIzV^IB8045D(f<;kN=zU_FkgkxiQoID!@rO}7gGwT7+Kf`o zB2tcSkLXq78SrpjwhA;ys$HAWoc#~N=d4`V+#cFqN9S~Z#2t|3LKyfGAB0g}DF6t@ z>Q7n?Kp~3Q1zpFEb1z&)^8Xd#Fn*h#pGACNdER6LJa(tZvQfk*pLS&~hf0ZxQ^poP z50GqPtW`)|i9`WisRGHKs3}?`s&i2c+OD&>8G@vi*j4|O>8q7hoE)rCjIc_j%1AeJ(Pq+McXdL>gTCGahl`gXbZ4p12D}4=iImv# zit%Y@C{!X9nw>>7kSd|JOl=mhb$5JGe_uEO0Zp+3M(JCL-T(El@$7KZAg`hppgd~Z ztsxkrQ#zY)i`TqJ%N@*Sz|<&i6s&Vg=-F8$?HR-3)>DfP5f^-DC{*yu(?8G$5}n0kWQFELsQ86T z7M|}dG5^EnOyqkcs~?vdEC;o}3p0s--z2{Ofpw1}4$-dcGk5OUN?uc%dys(4<(o|V zkGOPXLkOk6L8`SC`9;fu){0lZ^On;x8((z#seFIsZRP(_Y0y2RvnzFmfGq1Qk*cIJ z>wrHa2mG|v0ZOM-GgS2gmO+5HaP-;Ps+#(cu!s~+Np#qH_Mux2?HoWxA(_#Eaw zGylRKD;4kp5#$V=rXfPMp$#S z11;GQ0j7!ze=4qj-Q(&v03`~)GkKd|LRDq%9kXoA-9gx7hSB={vGwSEo5c^-?pS4* zNjvdEOM`gK8MM=q`>IZ6tsr%eBkEqM89s0F8}89a0w;SowpoDb$+$Y-I5WOf0Y9Ey z|D|Up1g9Bm?Gdwl$GGk;*J2YG`e=`#`yZg3ITg%S@@X7pItwOC9y!toyJ;Gd+TNlf zDc2YbkkbS3lpp`|>*J3CiuT@a451LKpu=28?B*M}tyXUvf`X(aOT#jB|b;uzF>7%Z2{UwG33FV^rWRcYk` zFph3BM6{0!j?AU@#*U8m*vC~D!>*puEmGRpzz(j|Vn4V}9(z=oPxdAD5eL0C8v(JU z3`SQMw3|Lu#I3rm86y{pQNPXfqvb_RBSEpUKAhamM*njRLP_WQXm!YCU2z(rF?3qgGjU8o8AX}YBJS}ed-7pvIsaE*S%y1y{ict%_Cdm|-h3W3~VC(CiF3k4H}ANMT;T03rctDakN zCbV!%E1OUXknxCEqTT{*T3ArRCMG2zC#Y5;MqG)3bJoz2`9oGO-STC}b!HH|Cr0ZgW1)!<<8 z6BCXF2i~;%U46dMnIIZV|7bz!&Tiaq>in~Q3MCkv6~@cJ zYVoFg0MT{Q32M+JV5WCI)dU3SK0uAsD6i)2EEiHf@FI*$hcNprf??-F%(jjRp!ev~cYg%bj084WoihUZGT;Cn{3{1thBkc`Ax{x4FOfrl&{~u#0pa{& zHcrtRHd&`n*YOB^nm*_CqEm6uxncSxoX)fw}_ z7d`~Dx{hpW$vBT1^}A)j_tG4fnS#n6(q0|eyxo1w%ephTX{R3cr*`KV9@fh6id)oP zfsw%i9>Is8tZ9_P_HNG`4lr|a0%n=Aum}Eid!-` zN_VAM@Ra3ZOQeZqaphDHkK!CShl2{NdB0nmypYOvDR%X35e{2? zQCPN-1nHLzaY}VwUPkQdVV7JLJ%$@t<($q;ouotnkaw%ja9{Ka!izdj3?#kdU8U)e z+l{;|!qX^0<#2hR)UEvT6s7-AKFV84`DfHaRbNVTr*o29u@}HCtu*=5j|D8hR+(FL zkv7goUK2yuN9)Ahbh?>aom;1K!3y;*0*);2b^r8G8lgmWUVyiB)P&LbEZ444u&vTM zFa_&l#{3-J2lhTXq+9(V{P&_e?M9~k{GGp{V}^G+8s=kjdkq2&0LXwr9t*lzTiROd)Nz`Sh`__&bvPPwV;R&ji=Gb%gTkOiM1te$tWngmwQU za7SoMOho#$6eY~)K*GS5(x&M*!PeatAH7nQ$dNp@j}oXWn=ZS_1+@KFmA%B=vY=Di zll`+(=okXVky0zZhFOfO6nUu5O*?X8e|%+LMN9n_f>V1<^AE1scnDjX7puZ%Up-DQ z?U>84e;lHbZBkPKXxc#~hBZ%y3(e|~d*|VXG%w4jel9b-hfU4F=RS!JgJ%+|-|uE} zJMUD==0AAN6W>CZm%_{$|GHKfk_FC=&?`L>Bp-}fr$=)RCM3x=@WSp*`iGz5uO>b_ ziQi*TeM;pp=>f)9@9PpD>fjBN)ZpCD9p%0=Dxl{bV)f*drk6)wC+|oU&uy~)RI5|! zbYN}mZqXa%eO)T-klXF%L|RuPdGvFN!Uu5*PtvGq3@qTO+l}0lDirLgn=)N?^v*8Q ztunQkVOEF^s9WyS@fC4Al&L4Z@{8?1sWdr_&x+bXpIy*W zy|f9%KQJY&Zlpg&Y~yztDs10D0GY#Bpjtotb|_F37@wL!>fO-TIChtia)x%9Fhb)$ z7d2{3GH5JFERqQ$oz$i+jNC0Bt2(h|A%&)-IuO`oedCm7+AYA5-i#pG;Zz={D^5Rn zOrIG$VjIU~Nvq6weLAmKP&IbrH62T6`BKLeiPDQGQGIz0x-=XKGskhE}1v;}MnkO*o(pOeVC@$~21lwJ9Ug~6B zR>0(|v0=1;IG<@Wl!c#A2ABrbAQ8pZSB8*zUTyAaq5-*bu?BC zRI}nRR_8pgKw)gjR~psPewI>gs6W+J>?cK^ItJ*z5NLD1UR-rN360#oHu<0DfDlF6tSkEoWtn_5{YiZ}x)R|#ZSem8W_~7?*flWhMmxw$5AOWNp z(DEd%S;z0wi!OPf*O55Pj>TX6a!dmoq= zo>_Perk_ul^Qm@-6sCJb^f)jqzQ-M~ztp-ZkqA$p|CxrPY~dx9R?eC~IaM18MJl_3 zx4Iwd$~2-x{FW$7r$%4^$?JaQ^klXV<0@IbBLG#5Q312IN#|r@& zh~st_v4EpK(k&4PDfr{ln4dMh6px6vcD>6kLFw}h*9SdKbbn z(wXehtcJ|<1S^%9KKD5i<88BZLN_XP><0|yn0!g-1wDdmFUr~~E z&(Q*Qi@c6R8ZoOaLTkZbW)>54;CEDrZNG_iM-K&NX9%I;gwoV9m(0k5M>&0h$7>=* zdL(yBs(#I%(=^C({DZVKXdhzaPVA3o}7&e(Ur0 zO_~FlzEok@FWV$AdWTNG9E)~7c(Mh5KgoAfcj!tJpd*q;BJ=Xbi zZYsuiY1Rm2Gteh%u+@0mz|G^EHN)lYK8)~B1@oHAR0>_YsL;n!bQ-A8Ns$GlP|=9Y z5j&Ed@dt&<>8JxCm8aF|m;GP+j3;|LcJ*H47B~4zc5zNN66&?vVTj4>omv4o#-itb z?y#LUdFnM?Lqwd^V<&?fH(^1YfE^2$R0YQCa?0Y=TrX9x!~aPTK8Q6DrbLZrdNpXU zAKA22$uMKBYJUH5UBuM(E~^KI#%rM*cj#O7vH67QqAvzLp0%l_?$nv0Ys8GU4D(14 z;Y)@_rU@4gXna88SCcf{{>WYB@=wo%T%4*__DwA#g$NxDOOhrP66Q0rme(-@e8r#? zWYZ&0+KZW7_FV|ewz|V_40gQa;sL{8JRQc%=~+TvR4#46MISGXSH+LCp#7dLU-U-B zyPOBJ%Rd#yqW9+(z8))9E1*2l9$7I@eIL@7mqJz#!QCDlha6oPrQ%Q$b53#L!*;p6 z2}pT9G346U5oa3Eyy88ar}glc=Oo@VTp~zD9Zjp!7`Dz6_MhhKnV^L+zf+(|O0N{0 z+57zT3$ryp?)3+}wIifnrq51E+YQZhefa2Lm9Vp{|1pNT`PSmf@ZA7Po(Xkiv)^y? zH3`b1Wmdr^xBF;j}%~5kja{!O~yL7g_+JUmw;Z}J^EqcIZf_a3*y>8|^P6lLe zMjbtST!Pe@jrCX@KuxCzxje!Cq*;8y z^uh(3>S5KCDYatrNV?ZjdbsoS0FJS+kjgEW2fovv?mL1r(`$xm4GoRQBI{cPgTN|9 z^kVyN)b$MTDBItz>k&yJlHbq=MD*V4=vAe?2FWjGtXY2jRHiOn83;4IglncU&yaU^ z8~uQ_BE4aT7_?fy8Zy}VV4K&|6By;LHWg_S_J5vnGRG1> z6}9rWShw0k+hO$6B-LM0UQez_wzA@(lRJKx;M!eNzZ_j4F7LmnoOIRlxZm8f`}`9D zTCM${{CjIlqvz=8D4qFhR`kJNzZ1dw99LW!cHgqV+?tv=XI#u`4L8m+cc>hij%%C^ zJQmKh?YY6~C=ee9%}8f`<8&5hLt=kdQTq0Z*tv8xF>&4^-QBl`!uD+5>~7mCT4q<6 zCXp05h|T(3aXQW-vvBxLvfC{*L1>$rRA)GW<5_BQw^npOMD{2U%AI;pf*y9@~QQoA5*r<^RoMqy@dwlFb0xaMThW9r* zLn2wWphmpXy)+1tu8JoqKNxQ0cxMx zN2f@85aIR`%BMpqmEJm$bYQC5o|9#gcFW$M4XfO2IBlF!P;#a)WZTiKB^PJhf0*fL z>%GTTkzK7Q*p1^Yq3{}GTbN*>c${<$lc^X0a?@KgEYg{UR@v$?zF}w}RBXZVI$7UK z!=g(5Gk}%Uw}Ar6ZE12#cb>z8h5F;2`yBt}HTq0}q;%^Z?LEId{|JozhWh5CSppf* z>NF^em1j?gYBq@!`^qLv>#l{=q5?0_!=zvEeGrjP5%fjh>))lXdyP>KBnw)6*x;V1ADy*q+tVu;W2^P3h%?Dh4{CvIr+Cs2Bc48_o>NEhs_U$p#=h9{?=rD zm!U#KU-sLN;Fx#V&b|AAwCm_oAR^mJwt5x2r5{?d<@^=&gOKrnCTo(bNt>feJ0q(>xFXY+>)@`unWW!eS)_auOxD`prCM7;rz@^(VMzqiko;?(#549TS$(J+i=qQgaSyKCWYowH9t3Mx}r2 zy5wGbqZcC3#_wfTPObflVe01kQ=JZfY6rBQPsV-tlAZfJ{&5#9t?3f--^dVVp3Dkx zR<&Df=NWSOKJ8&c%q<**DF?6hw;D0+6YE%jZdj0`oKV4?-M86r@P*N~-6z858_?Vk zy8zY4ehz9K2nP@~5a)KaPLZD}GEq}*xE)UpMn=YC&u;oPcSni0=%*E6$xz3x z5!KovsoQ-qO~O3t1-jw4brWz0R*-(ua8#~hlnV=QtBF6PBf^CmJ9q$ZfuBr!dL(Q4 zlo{&ai>|yr+i+`UX*%n>rD7*zzUS<0jndPzAr|`9?!~TC@;r{J?OA%{(^-yIU2+sn3khl=f zec6GhKGf9jFT5LJK3{8L^M5$G-q3x|eZWmE{0X`i)qMo^~E$_Zj>Y` z8XYOdH#gvN$!Qp+NtmH6oph_2>qnd=5og%)l$L44CJh$VqQZOXSYvU0h`ci5N1h0t z*lXNqCct`fVeY2|TC0%a$b-k^-#TdO(<3Foq3|;>XcWFCmyvyVQ;qeBj^7`dE@TOG z`rlh=3OYL7yrX>L!;NLITn`mod%MKN^ljTSgOiBD1osETI1>vmCbV;^*YRwTY`=n8 z%*jv`{b#$e11<975xPZRu3Bi|gsMSaK_lENQ>-UYVOB-Om@#W~)eqqsmVA2$%@ahc z5bxwkL5139&~Aj=GKPfX1z11I_$JeWS3-8NXZG=VlUygtHHQ*f=$;+#cl5g?-KT%0 z-WUwotfynz)09g7SuO)fEoDFzM<3bE5z;L10ppFBCT0gT2K;kW7e1%Rc4)BY-y+{$ zS$I*|UasA3nyLuK(W_&yFZ0Qj-W>}NFxiq%>RrA6UULt276>SQOq?Ab=(axm%?B*D z?r}y%beXf!4cpfJDT&Vj!b=pVzq+%ETMRt|N&)G|W3`Jg2b#^6E4y>!`_Iw-t5g?* z5tjD(CH+LNc#j&Xsm%W#r4JoBO5`q{lLC7Jx*>NN{=r zhisvsIg&am(c1O^{-UcsqUd8K3;CNZ1gu-Ra)CPgR363DGa<&a_82bDFTby#{3x`o zRi)QZYF|5b_BQ<7+Ark2GDQ6v#WR+aZD{|Th{Okk(HBZ%O~BBaI7Rkuk&WB|q_`|~ z>mZiX33uZ4tW0dd7Jl%!rnU;PD!r$V>nRM{XU$tXJt%P-u)ockpJ=BJ_7#lX5*L2| z)Ncr(;H{`vqBf~mx4a5`FQK-w^&CF;k!_e+ptYD%_4=raeKtRas_h?HhC~VfGi^M! zy=qlOt6FGjYGH2Byr88EdmH#CLJI#XQ!XfH=V6cxm<0JM5QONKe~VrDJ8Xe_pH~Ac z2nS)Trj%fit+5ruVPe4VV+o}dX*qk3SWy>gRnwR6sntFTJ<43dmTWr>$GbI5duJ>E zuh)A*5XpPnk+TP!XH1NYI#t@i9b4W2O{H9XvmYXbTc9s7k zJGY`!OKoyG&GUyOv@rLPyP68E?|*oBHor;IBqa_pYOF21EvnQO1Zl&kG1horgld;{F`p z2Whi@J8$k>o*d9ztz@5O-Q~|efD8(xfZ|63lH7^r5x)m{d@v_CH^pnJSzuY8?=zjf zPXrSWaFM$Xb!s~06_dJ@#@tQpzW<6H>vPZCH*X!d{H1Ds{%x^*F%$+WnP0xGu)Z7e z9}#QS1TvaA04+CnVY^m($guhyk+ItU8Ffyy96$@>8`bfya&%EEETl9l^(7EscA5P7f96Lfa$1w4lB; zGNaupR;F((Cu%SPps&rf@+VC%0;yDGyr|Nu36fp?pG^k>7h9Z6`kg%XnY|ng=4~#- z5tVV(b8g|qN3mw2d>7BM-=lp*Xshtnl3zHDWr@YW)2?i}FSOjaOqe=8jZ=$;MtfP4 zhLD^y*m2yRtpD~D&t~@7v(&jE8{JW^9o3)H7&PGZ?sL7y zvllho$M)2R#N3QvV^0ixl_;?YmnuIm#iGfUvrDHuse8w5KP5?%yBJvMSLb{`Q6F9< zPzNVIWqa+(_&HH4ARxflY{~&5eoE07(79u;os8t*O$7jugiZ^H^VJiy$Z?y+F)u`myxC;d6# z-4r!TF@77hD!%fAb;K4v(aKxpDmF)|9RR_guR92t%0H^u_j1N>Hw?MVm+v&SaBa_Y z4LSDNk6sr#G&*Bq{T|XOk3ct0hC*bV5sMIr0+CmH$nmvjd&POr49X&@-&kwclw8Pl z1K;>U+Y3S@ms4u~?=o^mMnt)ow%ojFbMb)tBK*cez{4i@UBAbR#+fU<9SRa1 zuHjF)3klU1MKTZsYiG4kGm-u7HP{82Bl(Z^c3WtG&)_=Wf0Q>t+y}=BxWvCmKg@Bh zTkkJ<3&ywKm-GoWJI|W!#0N14xKUb zPbiIVz11caz7(TqEQG4+5Vx5`V>=t#j^xH>m|T+Fytr(W{Z#Yj!fd7E$60ww(0~jj z$VV-b;BO2&Jo2y^5u3ci-$qI3Yf~04vQv(6?&xS3hgV%rQHQ|c2Y^3@mKzqJaW9Zo zxA=8G@g5Qqpjwlg;y`gwp8xNz4sc}3RY(ufZ~6aT?LCkrV=&6yZIx(J()yhHjiX+Y zUj7X~x#w?zqV*p@gW1+)jqhfM-mkq)U@3?Cc`*oU@)wm0@u&o$qF_2sQ+@PyB zGZaa8!IQ(+a(M@LBYd&IbvVoET1C#fY@8csn`9RFG-_pI*V)fu;*T}}1a!u1ooQAh zCtrWG@&mBCpJjjYKYjrDCaS3r+)5yxG3fp}jm@@-6~d1^LR<4nBR+kJ1)u|<(^f6j zN3pN8;{vormg>y4n+3XymOokF-S!_r!V=Ww{0>o4HJ$Qxx&zIFhWbANt&LVX*eTv@ zhBQ%zn(9M^zCq;ZA7?4lMhoxB+KZssrMw#z-DU~Wfie}h2OnV$-xFBHcpXI2wJ6QP zVB+zo8i}K2I%4Vs2 z%P?g6kqwDC8nGi02Desg756w=Li$%5#d_2*#ETjW>`e3?ZJ=y{t>INt!Ey02Yp*Xm z2#CYXb(N@l=E2JIQ`x9=)8CV9FTaR$EYR^h1)eMCsN=|X94yVkS3&d&e>$3lkW_dM z9t!LHB(MmKee{PzzbXBSlG7Fu>yadRW$aqL2RSw5(U7C{uVA^aDaqG9M?jqOyb$cc z_{u~y_r2sbL^w*T5t(+#QKE^wh(}nr6sTo%ev+1!CT||*O8o5bWEc^6# zdU{g4(m@3C|vIyl&n2_V34#8w%ZT)?jeY5pBALCl3qcR@I)Gc zIlpVgnV#^!nzD*OQYHwc1H`#}z?=j4^|jfB3CQJ~UYFoOHAikdSpDH6hdoy|ZAR({ z&edbJHZAY<6bE1Yb0hQ(sfy-LrsBfMFr8j@vG%Ddv6`< zk4l8B!Rpsqn}Yt&Ns#Q@gOh+NMR&ITiSYKBDBhI zoE^A+sQr_oC;J;_h$q#Bf4Jp!3;H+lA$wK$#*LWm+qjYQ$;|PSbKos^^$uMLQrbgzhOM?ruck)9WeIjPcR5e z3+~136rLj+lRVyQW3a@$$9Kk!mgY#qV68Y$jof(+{_A=xLQ~Ji%iR+&+S4#sW&?2F zp-RdVdZTC=xM{xs7$Yx*^>@|!^O+F2{SDK!93+GOfEkgZJYLes0wPT8-gN~t)W0r$ zAPJP`BY?#pi3Kp}G>riN8YW4>RXcjE^#L`u>z@m|LRvzJ z`JqyVTtyYdD0?T0XIU+#fqRy-(UW(%r5j0z!!fqIF+(OP>uUYiJAPJVCcCCa?r!KA z+7AY0UkAMN%%Sn4VTp*@T;O5_2Lq#_O=LM)7?}J8SRVEYy@6Tx{b>ux$KdRfP3nx1 zn>TtPC-Q`WMHmiWa{1so0eozVH|*>pjJ&OPKKYz`B8}r`Gb^( zuQIM!RkNv0&P4K9a5RaYd1jQ_JkJ*nE@zxPus(1Gc7(}3^jz{~>y?nSw}O-5WS7A- zQyXTp1o@5NB*gQFo-bH>V>G7z-Zl5xlKo=h*vLKyfo{kzu|E>s@gt+?Zc!x}l0(KX zs~d8Y>1w=({2(}>_37vtR+e!pwDRE&hO7#*T-M!C*+Ye1xuiylAk5dC_Y7PI4SD?| zg@pR;Z8qkE^F&IrZP5SUKg$vFqOM-lrZE2rIFE)wv6J)b@JbDxV{ESpF%Luq89rO} zKWZ&F4)E#;I!*;^(N*)hr`xn;eYJyEb5U7TsW5_7i*66!v-)`P=Id4t@RQksskYaF z^Fnv-+Q!YTX=WhTm%C+!VO`WNkRg5CxccdTUHvy!vh5&z{oI`W#@BycU*Yie(hU5x zk+!?R3tkt_!aybdcYQ~KW!UG0>FsD!IY1iUxVYWFE*{^dTcjgd{Sm`5UQ4>yTC7p; zBlq@T;y&7rFdv~UQ@HN@mg`S(&@Zy?_FNGRJygz=%?H}sC-kDOA$t;SSU)BF2g8Bnu>~al@dDA2`wlyGU^B# zq*tZaD4|FR(Xn7Cq4yG%5;{UiLI_FzeFUBR|NmLbwOk8G&Uw#U_I~!Wp9fmXOji7G zSUJqc`Y$U5#@eq6wUVT@4j}yDEfD^iB0zYD^Y+H;Kv=r_xHMTQ^(OBLidp<5@)S-e z?Q>&biX2%M_*kIOF4XUM#tQegF$`D%$4)1HXxC> zbKe%YaXbm;T89q9tirv>Fr0Qz+FXw9l^R(T*eD&1)5*%k{zToHimp0FGBcNrm)>2% zPHpZg=YNL%F}2{Q_{t-Je=Y&PD@-wMf_y0}Wa}?feS~B+a}&pEP_YVIg(m@+9Bmy^ zxOo_lwp0Dm!7^4AJqDXk7^Rhg%XL&B3gLErMT(*-6(O66>^MPoh@W?u{e^Mq(ZpNn zb{UKk`Mq>JX)f?wmqPFTXUAl$lu*M~$q?C-aHZ_gEyt2Z>I-D1A>Rycl14*wFaNqjkSN%il)f>2k?Dk6&Y&o7StOXdDdjxefnQuSBH`sF91SR_#sw zyuR)_t=X9Hd%~yut9@{BX={={#oOX0CbY_DsBfT|G)nUgatf~XtlZg`q1Pu8lJrqo2roUlbUv3w(lRRi-mj!|^r|m< zmfCOsm|(6m5rbU@~8k~I`as{My5gGju068P~2aHnZ zfwW%ZWruJkd6zyx8zL5@dIUmY8O~R%RgRTDx4&W&950KReuH3RE$w=VAF0ml3GQ`7 z*%--dq@nlSYYK`6tJB15iD2?9U%z5)h3@tOFlSUuS7>7ZPWwr^x!&QxzaXhp1RjWY ze!nSD=%5vljA-_XGT(Ll1wBUyQY-sF3c-qx0E-%djUkA1MnJW}g#KnRanH=Rkrkft z6O#JOl7{t>aSZFh6AX)yw9@%!uySN;5-|L2^Ubp|bJt0`0d`7(R2$N5r7UEOjTIb* z7Z0iyF^f0^;vw9ny+<}D`l;_=uW2>0P@+UGQHwa+nUbfQVa-gjiK#@%l+R1f5p4S@BhUvNsJC}g`8wnhrOo0O8e9+4agOPFixlr7HkSf@y;kNN2 zTo-er$T9cEQ048R0sI--kdRrMu7(352;SqdSm{F|N7UG*alGr*)4Xax&!MXpSv-d0 zlpbw7abSWKl?wEr17SW@)Q2CxbmB(CY><-Fs$Ia{d0vcT1)Eu)*KoOHC;GNk zz)jp~gn&QM_;nLL43JRvNqh5^m!7sH@8YaJ9S!zP*$8SQ1j#$1==5Y+BW$y^`*{1b;h-_mOs~W;ZR9ZRMa+v z8(1Jw7j`DjbAYfzA4D{5Pp-Wm37b>XWG-2v$gHs8#G!%UB3K!4-I5mKO$Tvzixo?f#;JCfQY!Nu!}*zv{7GI$vMA(uRCf_ zVFM&HQ$I%IJhjB}7xL~}U9^brVYK0u?tST{Jp!#f;}6tJzEJbWU+mKIjN2LUF>-x% z<_kG+Qd3UD^$4x)N&D0xl}iu4asjfx6Q8)>u3yI5mE2wBHtd~fmL&l-Zm>?0Wq%@= zr%E@$B=KL>BbCxCb(7N~PR^I@RHE<(ko_BE=q&Jpu9r;G5|c6`Ul{1;U_ECa2xS9sp~qU$FX6g$@mR;9N>9 zJ%IA&-{UJYg0JZxKi9Z(Z*Y;4n&N2a#D||K#r?WIji1stICb|u<^yL(WJ)#yUa#8U ze6$J$ep&PMhY0!6MoB+Om>O39VclFmT&Zc1Rg#XSk0VS@;>s!0P^C&&IPSpF34z&6 zQjdGzv7YPm>MCjfmC@V@To9|qAn0%)7wd!GBfil)(f)eXYBI@OD`+-7Hx%QwW`mz# zH!Zg8=WiH2Fs5Z;*RS(Jdm51pb~d3(7HLN^3?5Bxq3Db~)mA-K(pT0U+$qytWrPoy z89LNmQVd=PNus=|V=0i+KUhMxHi@eK>e>&9atO2|u4WFDDJQ5Qp&J)<5n3@~GX)5f zJW^jTTdHNu(vc6F_kF+oAa#dz1z-mS?SFH-$}E=xpyvXi6*fw!DIXe(RDcQZ9^Q_; z;E(lu9g&fBry)2^3Ndvo>tBc>w$gTW3`9QkA^_GodfdaXQJ3@yUPHE~*in{c?WfG7 zxxj;pt+(HTm$R{t`;YpYG8<7YuK=QId)uWlqi_2dM1fA-XLUcQIoG~poxYwt87KfQI0!tj1{L6+ty3tIo}!DCZv=&Cly(6;>O--ASHP=FwDNx(ngB) z%NTVaxad-QxsL)-K}H5k_aH6H@2WS6`SkW20*vSYrKOZXP;k+1ITTDy{{i|n|LsU> zhF<5Dk6}LjwHw>t_P}eJufu+9&$3!Z>i^teD)4y#1VXwjkW+)b`kI9Ui=R$?51+OB zmF{+|rt2{J$$1-eW?XsZH533R{;D5=GR+< zL~#>#N(b7gUD-P4?;D_odb_lbk&V7)s^^bE zbfGFjD$mhSC;#;Jd)Oi>J;i+p76?TF%KK@CS!KSMpn`}!p!MB8kI^UiyaJ;Q3Pc^Yfz}#@{0f$=Sv} z?L)x1p|HxU7iHN^*vuBGot_T?I@2^<0z-zjzWNP4yLwh?nNG*W1ipS4Yrm{>1b6ou z!Fb8^XKnZMug28gd8;zV98KoMa_;UfeeUSuv1*pLgW3Mp<#a z)MJ!A^M5N7>PJ|C3#a`kDpZ=`r)P(>(V$a5c!NeHEIlg7=jhOT=bn2FSGE68;E=gb z!Df;&$G_MCtxO(hw-9C)$O~9zg*A-DMPGD<{b7&9%_(_ZW*Yv^zFqB#Jsfn3R$w!K zH?+q>n2-^hQ8)2d2|r;`H>}OC&%v|8w3^?xL}(ro2Qbg?PX86KOoK?FKPTVF54PoLIkLQ_#PTJh6-RV#4m~fg@-JRU>X!UEYUOaYa3a;d$Rv8TP~cOZXik zh(JW5Y4Dn9#!l=ou!WIFifmlIQhVbX9{~H>9sN2w(^DHCf2VuwUyT`jW{tDEx7uj> z&DmO@wc{`B-@;%(aSE4#?jZegH{mesV1$k$|9*+^5zX3}&R2xhsr5{{(qp<$=;4g| zAf;&{b7Y(y^yafx7Gv-sYo+IP^!Kyc8%$x9{pnnTq(%C~nvl2rK!@7(k%5uG?#V#P zHq*g_#_}0+i(xWGS(wX2K{R$g+mUh(9zdax^qCs-{hhl}GZFOO4yZKk*uemrx+2Gi zc;?kJFFX0Fk)yQ}OgZJxv-M!&M@pahFmLWvH5_?b@OP>DrP$Dn-en`aRP`u5TWdEQ z;D6s&N)h7mZVpv1o$m-^KIf=JjwFX>2%26weOi4qvVCM@pq|ZLruA_Q{UB+|8gD0^ zI9660Y2dT*;sj>#x!`P|JqQ)}e~40{vzo@p6b`S*Ufe%E^%gfeR=2*de-TKVEkgW= zLVKFQ{#_;)Jp{RJ+rWkINsjpmS zU6nbh656Vbjg0slbvqQw@0r+*S6W&A)P?@Np0DTh+QSEFpX28eK&|!)8MaM_5S~|m z@0^5d@jlytyYijE>_NQ(NZ;6#L191l$o(a*J*sY+-61E{Xi=%*HPjO-oaX(aSFv_> zQKaH;u{p|>@(d>1ampd&`R#Q=+-TP9?5tKsCnzS5FehRN-1Y0XzU&tp&$IPFg0NxZ z5?8(7&?0aI(@%pJY0}OXNu5-&uJlaNPY;PKBcgf!4jJu5o}CA4bk(H8BzpA0Wg}x! zXYbyw(_DU%aW)rY&XQUUAi zlZ5eUI|E}bK9SDQpq@y|@CCZfRo$^)_*r2-N`+nx3yW^lCl*AyCviA(N16*sY~Afn z1Dzz_xa!By6P~)#Qd;R!#&|>xPZ*0>@0}~9N@2a<{dKf)W3HDb33dmXM0@nFj+eRd z!qIC6P?7U{*BhLN#_yO5wD%GpL!WL*EUQ?=SGRasn(Mo21g!>(a!225d8Gg)+Vh!? zxaV_=vUZM=o?3SM$P;50MrPRj3-%pis%qf?`4ds+L%!HTADlG z-&d5X?p3$0;jr85A^iaAevfB{g3Bo!>Z`Klc{!wWH>nqA``D@MAa_<83vOXW+aPgN zm7yy&Tt&G5pnh&*DaB?a1%__Wq=*i4*$eM%7PO2p>+*z)`?yxr@Re7?-Mv|18{fSq zoENqWTP>~9gWG55dBEIBxelj`&uoOOstnv3IJ1-Tm%cAaP%~P}Vw6?!7Bn2x20qx@ zDXbG3iwX-54}@y3%;C?aZcmMdQQW($y^m29VhD21mxrpovX;m5`SM-N1?@x`;kGV4 zRN|4Yumj}%GF$C{=j9S6_W+2WX9qfHBN-FypQX|>5}o+cNskYUz=jgvQ*QV%?PGyi zhIK(xBkxoEj;d;CTP>Qjgqd@!tSZuAVX$d2YmyFKxxO1OtmigIRjPjy$n+NbT@ZWs&J)6(SR3si8Ko@345QH3>jyNof}yv@|k z%jTnY;LH`c>0{>ng6u0+Rwx%EW4^7_9Zoh)h+(;Jmp#34$4Mne0Wn&>TGuCqvmRHMQP&aZ|LhiaWrD~Hx?|WZv zUo`U%t-|8s=I*!=i}MbCg9+WBtgkG6`yK58kP4v+>rkoR9xmkcK`puqf=zHDcn;d$dLY7_QYI~jsMf(6=pHH1}hnVR7cSczk zR^(NU<$6@@kPwPu=I8ZA4Ya4_P_*}vLWtXs7%SGVm`G`R z&Gzi#2Anm37CuQrLJ@2Y?qyi!g^!6g*&T2~9CnCYMj1pzD+C=i6mt!4+}IeGz`op5 zRGfOng9LY}IX+w8Md-gRV|HaE3H;V->@n5Zjj&}W9xz?NO937F(cAUbF(xK?SSNJJ ztEjwOu`p?+RyTYatvU11&c9oxTbNw!-K{R?5Nb1JckLt2`H2-rR!!;-$HFl_{UVSC zzg!Gt!cSJ(tXdO#Bv9Odzm_=1u+3Ere@ZXqd5~+df}W02>P~zvAbqSM!|ah z(Se@Jy_IfkC@t^n31eCxhmiS|L_O`r^BnplO^O!%3QsGFS)w4v7YI9;2HPQF#_F*} z`Qa$NwywLV@(o^p1g>(eG141%ee(Ow!}z>N9}?;$R@s{iY>FS19~@_Jj{ljh%AJf{t7-PT{Q3 zE2y@|-H#c4r6l~i3 zs`=VEi5~}-$KO$ywH>w({sXFa`=3SRn<#GRq~x^MX(4g2;Zau|$+f242nNx-KWD65 zleN~c(u)0lcFwEX@Cx_sJDIi>o(Wmo0$BK+=ByO&X%Ctc=oO|~tzpexIE+feo zb`T+~)CLv6qnP|o>VsC;+>*R?r%d}Lbz5+^YP*u)T>WyL7uh^w$6KIuR;xw!M(sPd z!jXRM@;Ujmh04`QyQcze?F8t;SJpytKz*S0I9U!gcGm9-Za1!#_dmh{sz1T1%;bgn zB>cN-*Hg)$uG5U67aG1d7SgVH42#(~l(~Z-mhZ0%uj`K2i0gZstS=ES-w{^W7GVH^09U;S;sRGHi=u?SI58rwB**Bn1P3f_C7qTUu(EJku&J{VW>! z*#ZgWJ4vGlmv~E)x5sAZym8TSx&^z6vX|G8wL8MA@^SWVwGUtUnBI#e-Cn9fw!tDG zt0|7sj#wo=&mqB|!@Ac+5 zLqvu{wn9<*==)t#Oe?)m?9EsHVUT;Uhn>;j1nNyeC5@#*A;=?ka`WVm%6|#sqLa)( z+-?iPt(&z6`{&aq?n%cb9Q|29hVJPumCb!6Y~zL_ozgK=PYsEC?C>usr> z^X|ibRV&uw6LAF_d1L5mkNzip>pevlvk`sfU;$a1-B%s4z>2Qzh0WdnZv*W~hDfIT zG{eU2L3-$0{jR5Zq(=0j8l+IGRP-DYMbzf>w0N}ZK5}FYS6};3^YrOKqYTXDM4P|` zoU9f%}+aITDF;vR?+yHHMUl3Pxe8S+WOLCXP#k!qW}C@ z{Q}mha|{mXHaiWw%z9qX+W_ohxY}wrF#hl>NyAd+SFDX)MEi*dz!31dM4XH~aPzaw|vu>8ql2Ql(k z*`r(id(MGM-du!tTF`<=nR%L4)fk$4$xD3O?)Ja=8qo5NoY9!YWx?-5jaTjTXtr4F zQ1JAnJ5C)Z0p*_Tc^#Q?U}*zCt)@R$bK~DX^|m1^7Fkt5j}}?oqs5%}tRAYa}A7H{~bi6vR7c|eM)L}Hs4rqYW=<$^e4}csL`ma=l9u%la+IepTGZPJlUb| zkZioP=2OR<*0l2(8R*pHz1)xJr7C~*v0MRjpi_>^wm5BchlAQ%jqYt7tGa1UgdVRb zrl7uO9`W0{XT(>!e+U;i?}wnU&pAFxmYHmG1AM#kvB?H;sr1S3>Vr<-u@b*Q_w+*l zJRBh8pH}SF?KdRFYE_9Fv+1x2S(fqVQF$2@yZWR9qNbEC!sI0c2`zeDUzYp*LcOwGY^ae(;zJ{(+Qz9e12oNg9!P{X8 zHkG7_iet1Fbf3f5pQdm=EcDZxM%9}knBTX`)R`EVXLB6SCBl?JX?l|u+($i$h*sh4 zG%4`t96gsPm|B4y4Y2|{wm)x&B5CJTRWKUrkVg%RKOrr&rR(<}2+a!fa(uZdNGt|d z9vD4Dy_*80;USRS+Erwaasf+YDCh{gOTe1NnU zH|o#<{WF*SI>DF}6li2xwwn%`CZ#_TGSiXn?d|RE9S)v;OyGz5T(S3vR+dS74uS-= z+02=T!F0CKQqqCV7c1~M3lW=)$H)KN*s{*IDZOMMaJXb}^ps7SlusU4y&9Tr&pucW z`fU%@F}`87=g{W*74pGU8tlAa19*hJ5KFPJUwy+uiuz!!u5TTnA59zDuNLYz)}C!# zr!nXNg6{(-FOO*3kd_>R?*9s#jv{gPIFqUeOQN`n3d;Yx8rI8^BkD)FV~aCJi{u}| zyi;LcPb;^-aN!XGBrr8UJ%+7~-Das7khB{qeC=I@?gFCiM7wBVJWMIup!Ey2v+3iI zb!rDMWYT%e^H+H6JI?1c{O>DNd6qGh^w`hdpf+D{w(oId`CiOO{ch++UDDBi2{^Mn z#Uf$p?pNks84`}SU5zMXNW72|=pjFA*K58tT$TWESa~*!{-C<`ZH-4R z(wo_VYaQ(_bFKJ0k=7m&Pas$5tL?ZHu}qF(b7SWwKvY#}ntLPO%a5{~RRBSb^Vyvb zngFO*xt3K%U-tMX_v=;iGORD?`$SV#3j$hnAsuoy!eQPEN#LtxE)zE9cjV0{_r2v&!PZ; zfBBA6V1HRtLscJ1Tr)?iesdH~(ZRDZ>RmpQ@uS*MlKc*k&Q6zre)hNV5~-a)nOB>B|I=87*?Cs6)AVlW`JK=YMF{YWD~co;ZE)~K9Wi$ z)HsA45cI5fDH|TE9`YikN50K~ti}sj*B2lzwb(P9)3+q0Kfw7MPw4EcPdwiH*C^Oy zX^#I%bs6d@>h84xT|x`RdR?3OhG25VE)1(pqT#iYdj$8{3^QzM^_V!1v0c>&nE9rB zs#l89Qe#zi&Ge7Pv=!|v%2Q)`yE{${6>w&>M!Y=aeSh41Vpjv?(1V({r{&K6HHu&0+!+LDJ>lfm zZl<~i!7NOMWM@uBM;7fY5OB3Ur+bRy2uu68k!}d>f##?FG$aV_?uD6HL48#4<@~#M z@1CaLQg8oo)cpoI5wWVTc50W6f;oTUw z4Vc4r<#BYJ&#HUuBr(Iw7?N~~!zby@ciwUGKaixHu)@f4MZGIb2Lt(M3HzdU zS^%!((XM?0EwMao0@R5*dl0zv`};Ju#fNuuM566Dpc@nD2+PBTd|KwP%S;0@s~vW8 zE3+Gi>e5=fFdaRYOw$sD%r^`b_1JMc#M6g?A$7}=ny{a#m1{DS?TevLqWzdr-24CR z@6{d-e_yH+KM{VF_pD_dGfR#BKJ>m4(YE}>+~Dd=%?(t=B^cv6A+s-`I0T9LbKKAC z*IC=+6j2b<+DEQ;N>p-(M446}l2T1iBsHWCbt% zN4%lHXCfr|&L19y(LNezh^*EHWXWyEHy&##s|!L^l-7Qn!a&r~-3xXyiSuC-MKe8l zHbhDtKbEww2LaZvTrCUW{MI`El?#xzmTe2V;A!!^XEvFb)v??5?e;=brE`lYh%Jx8 zVF=L7r+A5aY7jzVDdQrwyAOa6(>8<>PFg)V0NTl$sRW=oJ`5-i9!VO_1T^xobjvOW zeL!iTz+;K3q5f(S1Q`D0h~pml|NM#v>0=0o9_j9x)o)UP9rXYt8y?Tvs`(Mq4x$_G zAEyRkhO0u&&Fx{>)~;v)jzb_Q8HgKo@oU2x|M0uZLaH=LKKNhRR_;koqe~=36J=@O z?=7O*Sa|YVsqbHoIQ7&V@|%wwo&sR(=(GYD+h}suITe6HJeF_A2d$a%f@WUAYvnt5 ztp*?RAKf80`7B4XrC>VOz$V=u}=&a`WQ{T;MTOvL8o$ujq7tgO&Xr%3i(Sq54z)Ox?&OQOhKGZ@&sLZYFl>eo)Pb|a9$^82P2_> z=$8UJ44PO&q?Chd$Wafz-<%F($)LNJj~UOiaw}sX9jtAue<8y%E^#gK` zd&2g2Wn-S42!*}CeSi8wO_$gVwofhPQQ!L3&St<9d9*#rgaiHGCuEl|?CQXvmtMFH@@elF_} zveTr8viHvn)OwItPFVzzi(+UX;wcXbM}x=E_9}%F(HuCB+Nx+7$@SiKIyMV+KGg%x zORLs}!9+?3?AHG4AH$qs0tkg7wXVp<&O~r8-JEr)l3*Y4GvPAM5GRo~F{v4jk3^Ye zlGSSDQjW*?3%pG4&?GadSQ)Z-k?7NiU&!64{KrQ`1e}kr#tRF%XVe9>oYSZN5=;%h z96jc-0K|tSJ+4dWs6kVD0!=FHTHVKfB&&eb(z!i4jtsWP3E;gUqEik4vbnC#VG$m? zBV4!iGvNU9WFg5bt+jV2X+4}dS?P|OT1>+?-#6Dwhmi5M2U2=`ZC2-6jg{IuEFL3>R&p##9aZ6rON*CC zn&{TNnPrb!H12ZV*>7U(Hzx5yL*Vi26)JXr2A`C`Tte{@azBs83aEwwT#^RI3CLk& zz+pV6s#A~Tl2N?v{$w{J6H9!mx`M{WWaUUG1A{zgSG_qY06^Uwl6Z;|X-#^mart5+ zZ{@yq`#j9!!SN5@?Ox#sxQrrsK2lt_kAvPjTkwmH6}9(&zf1$uv!WPK>OP_2;2YG* zgRb)Qaite0pvnZZ8jCPBh*=gY-L)Ppt05=t+2J2*r$+8bsV|NeK*&FJ6j|_d`7Pob zBW*$JUKufH?0E>xlCmOImGrr;xYUp9?0rDTsb`r02&Mui4B_-i5jOPJ0j_v?H666# z(nC6_gx{!>=sDKr=n0r+Kr-QyuS^C$^5cne>3&&^Drz~{rDs$OXT|sxSuloqe4AZ&YH&TSA}NN{w{8(^NFUp}<8&3LIe$SThO}&{?m|&73Do`3WDJJ-i+oFRu9@N8a}Q?GT==+&A|d z;SD2xELBW|4uAv%P`bbL$w^?c7ckojU^=w*c`RjFJ1ys}Bxz^9M^Ld>lui6ND!+Bg zDyr-1A@V`Si^ww``>vR^?Hi~|PMvUIyzsGOnE5rc9I|BCK41v7p+s&1ksMJzx61CK z$}g1{aanSMC&B!03~i0m#r@@)JOIFh{-~nI*?m!GN&qGz>CV3?t@^mH_EYP381{@2 zgg`ZKr-}P)RY4H)S9R)4@NVdD*nOQ5sE*?7$;dAWgp%7Uio+^80x8Ce&o`vF4c0B% zWYmmB@JpZb@M1cKO^SBn8z!k=4<_`4hC}ZVzOe9p6ajDg!Qd@}bU1f#`;^ZhbcxBZ~=9mjtBqSNA*3xAMIPd&2o{f1QE(r}nyn zCBuH&;44rV2LF0P((n__!=wJoKsxmyk-Zyug9!^ ztf#-bZ$23>OeF^&YNQNwQuDkxd%igA*n5%@LIgA&IXF*d`MA0!p7HoYt*`BS(2H)O zI3UcFCIc>QfK6~5_Y#}M=VV829X=Vt)X1D^H42CIG0vFWeo7bkMM ziUZSN-#!FLx;dN}6(hwSXm)SpBZ$>8d-&d)i{{Hac$uzR5>4pFZ5$yx?@r!mYob{ImC;{8uIY*EjA|!v5#{XnSn4x1hx3#lr%sC%~4% zD07{a{gex6geEc>t@KF!zY@FQoF;6nrOXWFpb^lmiGq)V9R?ZY$=L5?It!@x{8u;L z=}C;08#a|zQVt}`0+-`6 z#2!zOOuKRJ#7S*sa!!$GB2h`N6~5~x>w81i0Q_J8eLOumogZ3n{HToD1)-|tB$ zIa78~h7`X(E8IdyD;(C)SQg(b-7n3y+n%AJOeV$aJe+va^cRwB5Ac_9j&L_65Nk|8}_pdLkfj zxS-BEeSgZtM-a{Xzkck3)C&a8D<+`I%@(2wy(oKB+q3!Ys7!O^vVhKSp8~zu#V~sX z1SZcvn&^@a;}@#K(4ZtyehxUL=7<0FxKXl5a4m4&9UjBj?;7qEl7YOO{|O?&6Tt5H zcC{f^NT3#>j#{zB#pA*+j{%wN+oh@jXaE>vhZVw9|L1aTL`v;jS5&B#47pC z@7=so@2G=KIjSrI$3u-7S6m}+nN_I%`rp4}2#&>FVaLcKUyYJGLjLPUHtJ+V&*xeu zOcZVz4-2?LII&r)fp;C*BsXK9%c_x9N;fOSswAZ~=MY9#uR}O`0=s))+hTj`MZ=K8X!V$h&3umJMQQZ3Tj*yJBPfJTD zWytTp-P@1B_Zx6aGi?($3r*U7kXd+J{`&egUN4?rukow z7MEEhnpxIXDc$t=>%hhT<9nRFeDVm2c97^1-*EZsz?sJX*T7vTOLO+ln4b0f>hCL{ zYV}{A9&-z2y>})98ZN($OvOJV^O%~7sy@~wo;k7c?Z;jJ{o`6tDOrUk)PQfd?)LS= zQ}5zqA~GTGY8W{o5VbyhfIM_MbV;_hddt-s9MlrO7I9zBr>Xk>ieRh_-1YkaEn51m zxh3UaF6o<$-67Cw+ag^+$=3hno3poo>pst|CE)t0xTHkob0Lw=oKuoTEfN{264i5e z5F(~B$R*5vcqtume>Kxox$xWf?)dudOh*Et{uVbDF&9w9C$0wU83`&2Umde?KDR@l z$DlyEsXZI(gqz*66Blq*|N7{v*Wr&myw_UXs+f@1O4IgZZ{CG9!|2c_ho24&md50N z`?ha}!KOW7K8-l2A<6ajRw?Boj7H6mf2W-Tg_FXZ9k`9>XMN7$#=lJ=tFKe2`!uk;j5@XQB03ykd&$0?mq^v#`8u6vNK?niNUdqw={9G|M}ZD2*lDfU*pv% z$;5PetY-xVCfZ@j5R2H^Cq6jp&od8DerLYDJ?(FA?;+%4yL8-_pchN%G=30BpHA@$ zk#>Jy5;&!sk(TTHXzZo5L&Db?N%%UUv;SSYcsqV&dbDQW0+3av23dbvAikG{1q|q& z%w?U%-Ty`=!ayYXWj%EKrW486_j~>Jt)OEVYbHtG!O!@pP37V1po=Ma^dcd!I(a<) zFQp5csd^yCE)?=Y{L#tn$t-VNu>+ zO~3!^Zx3leJ!IEFaGFW_dCtK)u#%$zbEb70=%zwma7wol;`&|dMsg`vzF73Y_qACg zJWaTgjY|{V24@Q12HRs#1drWBX|4$Pzl>Sp;j@{L&W2mVEHOe5KZ4|t!?bTxio^@%C$3QCVqakhRFX3PGGW2c{g4!gV9ID zS%+RmT`^x-@l4-zF?$(zDN!5wHRL*_5^U=(m2Qe7HGS9`%jmCf1JrwHt7d*@AC0|{ zmV2zYslW4b<~o>>yW_@GB7CjY%~w8oN`!^t)K75uff6&>hbIpuzArZj^bv(Z#`ItdT_UvzPuh6ex84N}4K}X{hwccs zKq1&N;AS;!Iiev9I|L4JVN1R&of)YzGAIL5Yy>{WB^Rh{;NdauBh7Z%7iW8dTz)!~ zDy!+SZwqa^w)5MW9VHeoYxe#G$14qXLEwD7Hm~o2kyhPL%UugoF*8-J__{$%iG5vj zVz*$;rDIn0Fd%jhoGD0I2$SWUL~xQmF0O7~;rnQ;2{a|POx~kv5fUMCMV%af&=I6|Ovpx7r#eHaLw7|iv zZX)qgwJYMm`qFa^gKIn;sw7ie_U$gUzTRasLhNjFi&;v5yS3)n)wRbH%IoF!YXu$w zyWwl3RW;D7hqS#ew=6*((LvGw7)^Yo|v629xs$m>G9gOj&sny%cJ zh6Pa8x^+@degE~w&y@nz1}#Z6N078mk0AZe)1I}UFAF+Qtp>d)Z^huvw)&{r(_2#= zCc77?XFS$Xo=$wqRqLn93ra+s`S(_E1VN3|x6huwE67hF*@yUbMnc-=*CkVvTXFjS zHz#fZSG})i$K&_F;ZN=6t)>C~+&{Dg86u^Dxfn3rllM)^L?Bi8>ww7||GG{6Ghlmz zT|i;(@Hcm7P@LM@5noEE11UnHo*yI%fFKM`~Fj7aY3YZ)SAO2f3VDg zO$lj%M6=*$=m+T%~&8C^Ce=3&p#fcv;0Ay z-Y;aX`2S9-&2JZIOZz%$H9vfrN7!{lqS}2S7?NJJeORzo!0biXfB(N<->JSbr=)U? zis&4@u;wV(R5uq{Zb08_-EVilrFE)U1qhmxO9IU*LTe3M@BDzW&xoes<0oiUJ$&7m zC7Yx7WsWc@FO_f&c7K1__d1{ge6{!Dv?&~Ztiee7H^ z$~*?kar26*HAZIF`5p-8kH-W+R&h_5f<(!u;;Y|uwLrrSQ|c9h_U-;y!ggrHz# zgCQK~IH~Z+=?}k{-3T`oLam_{XQ%vygt5sblR^KuDd0x7zZoU7rGA zhO$df4GIS(pvM8LYoK#OE<6y z5x4`XY}X!=MZwHc{#5crlrj1zG)SJf+;-8zNcWOVRJFd1zap@UO^?rgW+d&N3;mgt6Mul2* zDoc=bW$`~&E_rGMO8zkAbE;3HSSn2t`wRHehUkTG7)W12ih7`X=UhEdYSzmt&!`XF zDDZst)(kqHO%0pMlVE$&@M&1<38+Hww=*_N*7?7wqGRS?c)yDiw^;m-ChLx1#k+M< zaTN<#98>zNkwoMR4E6UbzxIFk;EV6{WQ&p>`55R4NT;A1cT^zsx_)llSpW}Rj?swF z+U`Noy8C3r;)3_A zS%s%BvU{O?sC6;t1aJXH0=Y7Iv5%w&J)4MK(5`CD zftieGUV+tQc6!?dv8aXaU3(Sg^hoGy?DJ7x5HCtTru(e()2`Cye?K-^vi%n;Nhg2~M zJ&E&bh_QF!BlC$`sP%(Q>j@u{`YcJfwh#rgi7>HJ;xt*M-Yh%3lnK4XtwD_rTfvuBmF+hPz8P(DKtmUUkUV zH(N6vKfE|Q7`AAO0qMu^>q08dE5V}SW_%a`Tq&=<&BHb`VhOZ2=KDP0RMr)xXSKV8 zj#auPV7PhMDMk`6MH^oa?akHRu_qTQcIuX~>E>r>Ao|yKh&7su`l+eC$3r$k<$#h7 zHzeBmsdFfO603HP#l%lJ6uz4roB=wg=8cd=61Pr=&oWYG*ZZJDr*iL((?{ZkX|>Q> z0ezzHmx2dWI1K%;>cop#`XCpVq@d> z)Hq7AyotlzSU#YFejzUx)k~{$A|WYTV2GE)^>H%oWIq7yNpX+o`FZb#HaOLXEX{*ZFg|L%@M_7U=vD+pq_{R<-tRGreJp0SleSKtm>FiJo`p zD;MD8$2nxJRb~FKCb9S^TB6Y=bTw54VHP~<-o{wYzMqu}=H-f_Ay@NFc#8EBH*JZn z;hbI({}q^l<1A`<5~kzF9#$BK9;g5QhkDP4Lf)arq5td*aVsl#TH(LZ_0$GFPY7(1^GV2z=6VgvTf?{P3fA z(rUYy0|%i$C4EsdUb#aolrqdK5jDQdjN~XU`s;(sl;r%Jwc$koMN49e&{g@(D2cX@32Tq>1O( zYeZI$9V?h>7-zL~#PBoj-BTwdu&@N5XOmL1I&!Gc))SV*)?4|7(6nN8qc(vsaFK+n zk@U|E!;e8DP;p>+auxMPQTy( z7@XJGm;1>}!6Paq<@IjRkh4taC(+l9kzZfw^2Y+dj+13R`B9&LMBIxoERW6*g^e9( zl|=Ujjh|m%->#HW)^8WaivlMSN&nUqM@nOz-i^Ii;pD6sm5gzDu)AjC?H~P+k~@

    K9XXlIS@ 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

    B)hETQ} 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%0Daa9M==$8IVVepx#lOykvGV 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%0D) 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Ξ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

    sK)W`}Or5X1#G35ReWDw)vW9LU@jT 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

    q^<(Vr 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

    jFbNibogL~V9@b7rVCtrTobf3M|75>x>P|v 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 literal 0 HcmV?d00001 diff --git a/media/images/tensor-op-permuted-smem-layout-TN.png b/media/images/tensor-op-permuted-smem-layout-TN.png new file mode 100644 index 0000000000000000000000000000000000000000..5bb4fe47b3f9650589cde833769cc86c13ef901c GIT binary patch literal 265401 zcmYIw2UwHK^K}xMpwviHnizsK5s{9dNDEbZFM^2lCJ=hKq7Xok(4;Gb-lf+>4WOW) zbg2;pl$M}0Y588f_xJyN@PY7zeP_;|nVmg58}wZREk=e53?LAQ5uvSa3<8}+0YBEC zp#^?puxX+Ne4`FfLztcc{)L~p9|ydq_tmxv0D*4Coc;%oRnlobUO%T=nsH&Dm7G00Ies5bC#0k-6)$!L7VzZTnk3q1tMUGNwPf z=;L0V5!J45Im=;Mc%DXs2D^75R5JR!+It0@>RdqN z3Jkk`(?fsy@GvBQCk7+)dvHBq_hVJaL`Sax0s||yxoFwqI3I$S;dVA^GKb{Tub=az z_B`VWs!|?>gGQd7Y+k+-r9%G^%m?A)a^ItBfykX}QW8bmV_-X}KMBV=tY@PKemyDV zxJbAD;xi@GF{s26D?3U1!nTfNhwtKcPJscB`Sn!x%k?3M3p;)+>R)RLHSUvRFo$PP15Yzo6BlH3yZjOl-R0sU114 zfj-hKGarZW*BAC47oGgkBt9U1s9@6mpPPuE|2?i%KRPu!Z1VnV+l@Y^vbq)Yapx|q>qd-|g@ zmgSqbV2IUwi_tex$EYrpU7XHbAQzqI_0e7aoq1QPOkg-pP!ug+g`zwHW7olPIz0{_o>J}c!nm; zw0U(R$O-bb3!g=Zc|EpvP6q>%=~X9Q4x}@x|A0SSV^aI;@D3eR8JKqLNi(C-v(bLQ zqT*?meOcd&WCh2^q3_B+A{|wU9e6vu2>wKV_X@%o7p7FFIeXjm$6d#b_Q$7GgCUOJ zWL^Wl8B?;)rYO~<8Ef0 zR3fkbb;kWZ1aK2Gic6wyu2wpOz*u{-`Q7Yd-6c8mdI5zyB3C`jFLR-<3ffv@D+C9dbsb8OYhZiT-zfu)uk&Lu}XK2i^O2Ir%^**YZ#y<6)(%I+&NCBO%uwLdlhbK{bq z`v|>;f90FRZ3_IIRbxv1zjis8L+tZfpW#4~bbR{ES{Q6^4&*3id(GA0Eb1$shlp_G zsQdMql5<9nrUVRiM;l;ZKYxx>%~6NrHg8=&ydq_F_g@T+;iyyNj+dI$1#OHn!IEIU zA!rf|@l2L#pRrDt@vxh@6=fN?$Uz)`6{M5`nnR~Y%b>>4*h+oPCSKIfkUJSLgmp2&|79{rId)fOgBQT-!!qL#^ zH|Kix9To1jyK&6Y#(*nc7l1laIGh}A$Fwhxmo@F)l7PIk+%A494}5kNLj zX37P37L5!lJc)NL2UZqIg|fEiTe-A zWM1e&K1PB8aM_KKn2c{1@;tmmyynQckga(4txA6o4Vl&PCQ$SQqgulXpmZ!&l| z%|RYy=7j<{EiJfIhp;3wDwfUU%L>Y7yf71$7yBoB=p7U2rVq~9Fq+D zA)o4jJhqyvVG5C4xaHWFSfA$Q;8+Sdj%2pY_@6y1|7QPGR#A0!NiOHc=V1WS!DL?;TCb(y;=5PvG*L`tc@f6RrcL==Jb+1Z`W8O*neGd2s zV3Dsh0Bwp-?lIzNxt%|FL5X8D2X?eamrgxCbq@8PZ!dB`PXH^Tv1EvJU08{i9fap8 z;#1y>vz`3%pjO;6kn)Wq4cRIS&r3xwus2td@5Sr$9SP0}1Nj~xCg#6Lk4ATHu-1V6IOalQrO;gTqnDTAhunQdp?51hOE z*C32$V(n?>Rjgx65vco6*35d1@rB|xMHmc4SNJD`4M7dj9jF|wCJ)rK*t70qbIABb z_mOBbttR%^lfl+kI6Cr`%jsTxmqqDRl`CdxJ`&>JDm>^uiW8+^%1{6+Zt_ z5F^Yl+?}lH&>|^ZBUUlkONf}rAOyOYIJ#)o2#>@Ktr}_8{FVb-KrC1azCKRZn(dN_ z-atvjEzbOta+p(2@JkYk)QlxbkOVgGJz(oQ2%hq*vL5X~A5NK4;olI3p0o!`)~RkC zJ3%6(^_G4P&0cKyu}8V@#Ma}va2Tbs#Tz2&H{0#@V`vR!Q^ANMeG=HjH4D^yE2{M{ zc{-)OVCBoP#XYB`Ol7Yd{(wS27w9%z@Jo_&{34a|?T|JuSVD|#$e@Vi;L3^bq!%xN)CMr+!s^up7u_$-HanL*q$t4glxC!byOk`wJ2_Gf7Pi!BE>3-w zs+*?s>5DjQr#ZDfI6OAIVBQ5E#UdGz>FeseC=3Rlc>Y_Z2new(SbiB5$c;Bt_+ zZ3z5v@poLZ)lF|%Cu?`wg_J!Lsu&R$fIBH`!(wK1q@jc30;2QX`K`ef{i%eNN05}X zkzMw)K`;y^0h!xKJ?aV}Q8T^TC+P{-2#U@h{}U=&y`c&7=hbWLqc<|!L@osQ6{kK3 zWlpIpSY;|4t|`ZxqvL;+6++UK-xn*h}MU|p#i_La3%7jjkplH7wS)266!-f?W zw7AB)jxCP4FLdtK zpCRxb8}w~bNtDHfi&~w(kvF%PuJQ zYSP;(V>sNB+2#=sfUo;@`a&L&wTSxes6Y>7n~ zvO-lxc@{rdES=!voh?+3t-;}pg%~GjJ{>2-l?CzH%Pf$F>_-^d6ha?LOl^XginBeC z+~zR&OhiVR?_A7QsrS@Pb&X$zsUbOd2I8m84v0JfyHdz*!;hUJ;EJA4DtkikIJ4ugGn$D7rbag&ic4{S`-dUf z=TTVhi~UBYuXIxal^_aY=J)9F&1<)2BsXnVSu-V%$`)+xsXeEnexvLT75C81bRN38&?3MJyoonEupV`kr-Hb-B9zIYL z*Y(J}A75`X1dk-Go&2#h&e1a6w!<|RNgAfp6Y0Pdok@q9UDpMbx^wT)^U@c6b04ci zZs(AM!#)js_}z9=vx-kQ!wI2k^*ev$=^xLdb=_B3pc&I871ZQ!1kxIGFSF9_%=(v~ z2zOL6bZ<}t?kL-oN7pH^f~bh2Cw{WfgvhJQOczcc`}Qu1Rs4u}7j@M+=QtnK4e_P^ z1Amb5Ws^VN&la&FkSPkq7o0s3x);?pC3N1w$SLG06j$qp_hVvPyin9P7xv{55$Cq~ zz4L6`Sp4*rrPcr;6iKb>dFFLfTc$-$7F)dt&?L-Z?XtZ`Hi$zbXU;nx-%HSvy`Tv{mx z4i_Yw7qTI;R!Uc?$xYD?F7aLKyVUgyJu$|E>IxOwp!s}lj*7$I+_QW_711l#pK1@b zHi7$^kzw&={@8=#r0t;q)SR_M8UKzhWFJYqjOSUU@U3I>3_9TcW+|XZf%;I**@90C zUYDd0Z9frycO8}nMW;dEVVDnN60%^w$A_UmfYAqY+fd%T;=}h(tbQh zOvnYf(`6c z?0hf*?>1IYSp*#e1itJmwG%}OoPNMMCfm2HD)coy3)IbBFK9Je(D!Sqz$$3i6}s&Y z*%$D$JETo{IPwUNl5?=4Cq9?e{8OXXXF-S_i1V=85F7aFtqMo^&>p26;N%h-!NeQ_ zmQo@j4Gw3MdK2jl?ESn|h2S?!CQ-=V%0tVHiAY2j)X9J9pJjHDAJ|VcDmn*4wr0jj zP1=zCc)V~N`}vA}<%|qax6syc#_NqecKMSMT{~9)($&))J!X`o2lC1H!*hz*ZxxGd zJaSC`xKbhxIHYoBhH5?aXRgc}F*n1dgxpWm-Lm zM|H(vM{1DDVC}!ex(@DiGl%o_uJOJ2FjjN9;`|Le91O+GM$bfgA28)E{S^7Nz&h_` z_5WZJWy1$kUDcU1)DcqxhuaWKvXiP4gDx07DJl0CMj29d=hS^_w{Agy=@`!E98PE% zdK6OCf4OPuivYQ_zsQ_BR0bT*;LElX)wkr{@?||{e1@Jljadn+NDAWrl*cn7Nlye) z-*n}#+-Bn!pt*1tIO@)f7W?eUMQI*~mVC2o87Jz--V7M9``| zX~+>^YVG^FT_3aem#|r@8upcF;IZwgXz5W zChcc8Zt~{V`r%U=aqSyoO7iAQ4cs9rEsraiY>R*NP?H(s4j;GUru|zKZtS@P)Bw-w zFY~H6=xUsQ28T!Q0elch`M5VH?s`=fiqENCrzUg4JSi6{9KM!oFZ?pW!+AYB_}TC+ zujJ35KXai6~_gbDj4TLpKDRHxRb!mSd@1Z?+0249Cu2lku^Ij1 z^%NvKuXCi9zK8#l-!IWd$WPtj9ku`A0*u1R`ZzzZpx`wd-a+fILOF0`QxJ122W|n` z4|9t$-VQGuo*VW&b5soWTYkt4S-ZMunLa_MP5HU{B_CthS7d%bpIFIFi* z%`_1B`g%W*W*NvigpC{JvrJWa{>HkWeNJhk=D<6K$?Q9gC?zlt@oh|msnxg0v+?=| zCmONSq#bJV3aFusa#;6KmJWHZ2AUxNSn-CS!xmUDktU0OooYVuGI+CNnT<3zW}p-oLz4&;Y*y#V1Gu<-uvZ&?E_WJFKe6 zJx)snom_Bo?AUY`>zFn8EgD@4M;Ts<5E+6uW#Joza!aY=2m|el17D4CYol$_2uf$S zRmiBQt|U+tFwdwR&%3&`Jh?&QmXrY>otf%#?;D;{jYACTe@O`y?OzclW$)D5x?j%;Fa z(w^2GF_xFAKa7KF3Qq#ef;?6k#6|iVvDD--6cpN$(;y)UR&M&WBS6ktS}*$9n<8s< zM8BYXs)iU#=z(e{N^TUXxtnd!6Y&6rYfpiJRn&Q=L^9~gq-Y;i9NNkhXMyYib{S>@ z_*mVLR1gjZqRB04>4*1}ULod@2^NM@h1h0)#+7eK7Yz<^6E(@=5^UIJ4kSmlu&k$ZwTX60u!%}8da~Mid zbd#g1T#*l&}QvX~oi6Z!3$-om9kH`X1+R` z>gfmE80&1sn9hWuYK?~WEX{&0RkY|`@#B|{j$)lyzZgx2Mk^+>(t}1&>2cKQ`q2{T z56BVSc-K1%_AbE-Q)3S*K}zGi>hvn-!ejTtBehM-NM;VSC%0g-6+BAN${K8I!9HJV zwiAuu8@Ca*y)Aj8Pa*qlhgTP@!ue9vrH^L1E^K}55~+hO=@WRhI#JzJ`yPnHvf&r) zR9C*_phlirp-Z=i`uklTR$UFYW#Q-Af3I=44Tw_qtAt zw4c45M!e>UPAyq=?#7jV>Z0X<}Q}(Nw zHqm0}Oo|-aWA{DK9vhX%08qTH=17f>^Se*8KHhZE=a{6~7ua$tcVj9#db2VemwDNO zwO~SD{q>Tw`r8xO!b%W>QJ44rkVM@4H;Gv5JTp&hyB<}yRzrne#yv*j#P_J%N}ya_ zQ=($5Hi$HCxuCcuD2RTzX8VTm>r-vTeL1~2s~NSz_^%rT>JF{glW7LRP`|r6+c9mL zoPyJZEzASyg_W1$0dWj5%xry%9zSrk>U!}nZo|%ryV3u&Z5G_rkFs7+Ij~FWpLHGX zj$ztqUPL1X+h+B``H!Qu>qM_BxX^BOMqHEnCbKfU4UL0U+Qr2@l5oGYwH|qKYi3VA zB~AHgy@fUf)WEkS{4y$5do-%<`?0CZbFQ;(?mvdU`K27j74$3#**~Ki7aTlRBt(oJ zs0$7!rL{C3fYpZw=!Lu-L>E@@QLH$s+0f0qN~(ZLU|wiRGl63fW7@7{L{WrDlW(7> z3$4s!f+VsOMh%4EES_fo$tClX47^K@oGc{!{(rpyDuQ2I=NZ}d1f|jSF;?n+8Q;QE z(&Jp$89%6U$apG~t6xQ^lwu=po$qOTYU$_9aharT4%@VvfF}jgE(s0RXuyz><=73* z9hZeY!Io)saEvPpR4xAeiB)RchNBb4cF?c7o*?6Gv7l1FQ3Bn2?se5^J9wcjXeGvr z$3O{+m!q=>4)^)-Jy}kGD9nBhI4@5dD2;QW3*d%{#`0)P4PDW1rGIp=GV~iwF(jcXfJpU50?!= zlEmDmEr9UAU80@NbWuq;U#INBDmk$Wx97_=Lpby>LP+amQg`YCRen@y`_c@l?4hde zYazc+AM$)>ZY)Np#&I^aeH7}R@79O$6>|x|!|e<@vpQP7ZVdKnjva|?5A z?|$FjJqR+(ABM`bb2DD;WhHzs%N>M?X69=h5Xw5x>e0|R^@(@U%q$<(BwHtwg~p-?$O!n z&87def9_}V?g4b@3GQ+)wB}XA2TUs3b+`*0*#xHo`ykf#0 zYhnDi_uEkn$7Igq+vaw_#K(JknRPL~SbUd>rEz`2(${8uq-G18z5U0dqmYn|3kzA*?qaNq+zLtG*5jRHuk@z=4*lZR zf#DjkygcGpb>}>|Kcpb1NCMV7>!8*hzceHmY3|?qXG*WWcq&mlbTH7?0(@x3vL~v} zzC!~5??>Y&X*i2hb!m}SRAx3o#j@?~R5R_3oi{=6b!#N=dH37w7yZ^A)g|YA#gHsSE&G5@8>`_t)mZ` ze;O`1wu#Nolqz~grGn^oZp}u1bvPA+IN2)G(?V)Hq<_-4C`^eH#nLRQABvOj{SxXd zHN8AMtS=nl^er%5tNL{lu(jjy{bszd+AJXe4_vNloJ6m%im@-rKP@c_UN7mVCWD=5 z5*}X(mH}2Q_4wTS0u!gsJWD`f!Nt)Z4Pg(Y$_zSRY;S$~7Ib#UV3!VxpMKd7Xd;Hf z>!dWup-uifhTdPRki*q$`!3F!bo6NTuTOuxS=Z<(BC|WF)$; zfxCWH)2y$tQI=Cazg13jAm_txX*ul`be+qEJElJd{gi>@-xSH8-6kEZLzK42q}3Or z*R5x9TDtDP01Pi;k({E9n` zI5&Erx;3v6E!;CAwK*hkA>aFnN4+}9^hgj!Inajx<4<=rAX}&N``}gxkFnpn?rWt# z7{aQ~q-8cYJ_;0k_vi)i_rL^=HLbQ6#!xYEqXv~Qqa zosALC{ZkJP#!j$NvchJ3P5tBJ)Z{(M%QfCpMQJ&$4a$|EDELsltwF?)x*1SkgO8Z& z0yX+>tVevWradWif9F70pa%Np6I2)~iet^6sR0)VGO$_D zkY?~=SyYxC$_-EYAl(kFO-vp^t_1KEj-Not}s4QhEwAt3_P|$sOBqLkgh0!j|xop z3WFNQKD4Om342{4M^uCvDNT7GYOmka-Wl6Id_#wz*s2%-8#kMaQ2YcP-`cfamnNk+ zY(u*~BodKNqO?b94FGafy!MfO?dzhD_O9r!-xcz4W)}|xuL_vM|C}>2YkX!dFoZ?( zoAK-c%9T%d1r&b?uFpBUV#u%=fUq~e_O#{vj01pwf##HyvYK9~Pc~$}n24mzXo4m91VNax^f9%++?aEwpOc@FE@Qr2?lnOSwr8`k;%t3XwHQ z6{jpaI_93e3hz}M2+#N$vl-=JVxic6LyO3cWOD2K^ZQ@b4J!of{1tJRB5o0{3cjiq zfm5xdMA`yj@!HYEZTWidtabEu|GFVq%z}6SN*m^I6Z`eU5wHa-peOzTc51a~Gv+m*}p2eO|b1L2kLN} z@OuZ=*zPpB5XRiXcqW@x@tOC|rJTtLwf$XAnsxn(Q%c}p87eCUX_PVv9?R#1Z(Ilx zbn9yk+qrbw+cb;;82BttyEX{uJOV^Ur8?0NQQ4^0ReacJGgk6;#H}TxSoS!=#%Mut z?E8*RFK&PpDp36IrY8iH`$&|e*5S3EeGwul+9NkQF!sg%sMeNpYe1D$Ejd|=ij7G4 z70K+%x>8FIoii6a?pP`8FWQX2!H-uwHvq-%>r@8l}|%6_*^Ao1ppKiK3qW9f0sa8%1}06P{jzVoxBE&4-V^G4(4L+I|; zWooh?_F0zX%WkPD?_9)|GtbL*onaRkijvVd|1($R_Q~Q!@82lH;Y0|Xf;n?n!>_V; z*;wIKxt*|kf@I<0sBwSW%J?g5!LE1Ibyv|)i(C9DVAFLb|}bU(kBDmym~V3u}RcAHo< z7Hj)n6RUrn60YI54CIJ2$U7Q-!R|s%3&AzcJl+(nmDnPv6TQ7S)%vUKTUiV;cDhsy zpr^-kl|khKGvnnl;EJz5B*P2so#bjbnpa1!bBe*s(!1aSCtihalr z&eL9vcL@G-e;k*L_DUELx&lhI2hXiokuM!Pi>8$-m^uZ31z?Dp+!#dlsY-hU&HOy_ zDAtTGaL-t{l=1FyKdg-nZ%A!kF28G#r`bLK?kgd%9*t-lLDUW(cAlcPm%1A=V;b?k z;#LkDUJh3M&x8P(F8fcO0+2FsD&aK?F9Kjdm*={L-;73;TK>vZi#acnc`Cheh?qGR zdqe>=+VH?rWgAmRs)eryUyOg|6D4}D;PV_cnI3Cqc=Orvd}`t@O+5cvo@s-z86c@j zyKVMs^`)$E(V5Ew?9kapJDSJ2LQ?B zg$$yWY3DfJ*+3suaOXF)VoooAzDF#M-8y?+d^l-~yn1KT%0xQ~ahM4NC;L^VaDZC!86ocYQY!i(;l->@McMdp!5+CNGtyy zIYg)$Y)LKib572SFI;$DSWQp#SrzQVnCYtSiW_@hn2S>< z^Oqzv+q-|WS%*)iQG~{infyCb3S2L;t!osI-$aww$_u_p6EF49$znxeP$Jp2JozL!YntDi=8kCExke{n$TdZye z-HG2pP!y^T!mbI8_e?uP>sK=3ZVbVW!#jb<%_Moo^ADxs+s9(XPv!Oj;Q4LFbcLIR zy!6UN#o`)@XO6H3&%=ggu@OwuW?XCb=z1mysrK3&&%a11`A`x3ac1Ti@d0LSB~CNk zEghLB+Xc~b=3G8HkbPeE-Yj<@3nFYbdG}x&@=*o~wI% zO_0MZt$fjOFFlYU`j2R~-Mvt&prU=h0*l+>BJ@Nmc0%R=4fc4@(>UV&6XnN^i=D6E zS_bPU2J&s_${(}2^&L&bFY2QMTW`{br|m|@N`6w+R+4lz<^OfvOW&Hc!Qt=uOn>!+ z_aqFl6c*q_A+b;?d;NMwIH@f>MI(%Ae zRI^^PG)Vmg*`z^M?I+7@^!G*PaxXDStU92Nr(fId7vtZ?oUAP|s9V7qN3BH6LV@x5 zp<=;JAHERI{wUm~8~<=VA%8O#8zss2;_`EqU^^#@XrBhwJD1VcvW`@N|7Le`+`>6I zl#B{HyS+xEF*s2-^ttB#;+Ly1bNm&j;Bfxuy0}E)8J(&#)~4x;^gcT4QP+*GROlyN z+L#^X!*gUgmA|#atKcmjl7jb#d2%Kx8u(rX$cOK~j(TboXMY-?H+$6?=*=y^Sjjr} zG~W7_si0R54xA~xU7#bKN#l_t96il;P@5+9oN4!WJi&`cHQr`@6&nZ9u93@^~=nSno!;}4)a=oI~KoWt`ar_H{Bz3RQ zwkmI{u!*>tZZ*8!A>+you~$Ax>Msq}4Lf;6R>8y-KusIXBY~uW4(Fm#kDPB51 z=&+>1UdZ8tc#V4xoG7wgb$MBzgJlGbZvFH(1w{$Ilf??=-_aAix~e=}Nj=fCviU&Q zjxSu=afc^*yZ$!uOU%h%w{tc1XhoeQh}FDDUBD#>22TpCP|-&dB(qHc? zv@HWxPR;@tcKsF4aB|=$p4;MmN$A5i$i7yIWyQGUkf;OQX01{j+b7|!yI*a}9=z@O z)tS;rpKngdfR$^VHj=Jtu7Wgj#3GL*-KfS7Q<~3ZzFnk`Fu`1D-x?;I%)g7dj0nNn zw$LGJe_56~2=Dp~=w>yyUaqHHuqrIm?5|IHLuj?F0@cW_t*mU$r|gP1%DJWbHF>&% zlZCeVsg#vW#E(6L)aEOCHL!xT+Lf=5Su<3#e(66_ZF}^*arL`bu;ZIZD!idTt#N7s z^kDP3MEuDzQf;L|empYLT!9lQ|BAAS@6U2F$|gb1LJw*Uq($5LQ$FwACK66t$FZTO zUB0WDIx-(iQPTc2#*f1gm3r5xCgH$?*FVH`o0+y>Fx=w2{I2RmLL~N6^fR^t2X)h7 z?@DRyjtA=r&=&vDYxPk{?t^9sD@~57k68)q_^}7&2zJ~jHjSIhpeUUmI6*j9=1)Z7 z+i(Wef=BxNoGHe+x3;L?Ge*maFH({(V+b9AioRyA;zI9y@f%EdNYZ&(G<$n%#R{mE zeU)DYnDKb1s#Yq~966{_w(u&azD#Q$ieHlWqZr$T2wOR#5)T(Z7!Pqd05>?Wz7@uOi`60-80p&XBpSs&JNSPS=+sm@^bs_ zKgSca%``P1IgFyhuGB~6*iV-5tzpHDuJjFkG~sSGN>2t?j`6Dhg9G6JMm)7lZM^?V z4B?>I?Tw?c$9#@*Sa8)@lBYxZsZlokX$sXUxBxfBLETK@MUE8U8iUIRvzrcJPiw~< z2XQW4$w{us3di}809xaQwK%DHZ}vYSBO?m=pW8lI6Kzw0-E)6wiw~unqt^XN$R8_cA&Mt0@$fxum&5LNlGn1tcgG9W0RqK zk{79})L@3S*DI$fI6HY$gAb-9sQB$ zEE82;k5q~GbLUPs7&T^_m$&c7e*xC4o30ol{!cE(Wl>LJrgnT_n1rZ+?ABf`Gr-=EB*IjmNLeH{G6rK_5) zG#X#y^rd8_eRM14wQ!nGW^3~A=r?-xqdl(abABAYH~mO=M_KXHzhXwxx$y(g0}5^H z&C{m5a`0)le4uFHhqv}z;OgU4jO*E9~|v zXwJ$C=&7Gnc||fI_nb^4gNieb|KI!(hNl#7TUY50Kl8fi`c0lRew*a{r zkh0!Z#jZVWAduZ{V*6P%{r9Z05!w;-R&rCw!Tx(PjyXA@%F-m!c;q9vn=!n^kzxqJ zIeme>TY*BuJI02_aF^gE?DZ`B7K69k&2NBt7L+Kxwm^o8y^;@_1H3M&y|UcEFaw+s z&x~-?OGy3nL5P`^SwB{1UoV0-`<)>hRX7|U@DilWjQYMa0Cy{79{-)VEHK&(_A6B0f)G3@%77(a6FsY&a{T}ZhM?&K%AnBme^yiqt;bfNuY zg3J->pW|5Ji}RThg3o};IITth&B>m<|B4rH){i(>FVW>-z;+A@^#H#=h4Fk9#tPWs**`0HF=qZ-lB_mJzf}fC$~=( zSd8&M;v7O$KLAv;+04T ze~-ai7X+5RI&F9wZMWE8G5(A$NfyQ`SDs@*mjZ(m1L=>0Uq%4_x^wtK$b-P46H|EV zYHzZ`?al=8)#)|}aOm{u8>kpo4jn;+y<9IA<&=Z%`rH8;ksO5!tp`u=(o*0O=#bv} z{C2@v#74cB6U83E_qf%YQy=7z{$euq^-P22$66&+ys}j=2=dDmqKnMF#&2?TK1&eW!>{j7qnoZ{M75Zi78m|hO6aa4s>&O>LKUDKw(h!tE!rN zW`4Ca24Z#d_OBIs#0pi^wpPgSY-1CLXF$T{HtxMhf(-?PLcb%;|F|UGO6&2%3ZZJho@HHeSDp%#s|15psphQfC@F-!F^{v`H{;99r-x*9e}uiio0_T< z;HUg5as*|@c5qmA{jF>IgEojfKhpcHY|_hYYVroEi|v5IeB7W`1VcphoZdeXHm;Ob zXq9%F6*v0c!0pRLhU*;|q$~QmLRzu5o!-emn%07HWd3M8FgX6@)c(`I^Ru-iP`-F$ z?E^X^lgS5mHPdW|wOK;(;myKqdh@8%C~V1}>tqf`&*<($h-%^C-pdv+?n)ib-uWLV zzM6`x*hTuC-&QV!PXyR2!3p@oK6m-!Wy@ipg-0#%Qo5b`_qdquvuO7f09ZQqE~#|b zPUh&Fys+2mU(S{H4X3@yTcKJ3t_K$2zms^39TIH|gcuMyxN+nx-IEHCqlGDmX| zp5Ewjx7PRieLi#0P?19~G@qJwjmb$Q+?-pAA9>{!&YAI3fT){l(PDJ){dgCkwGCdy zv7>O=HnIcUkSR;rJ6KHY>e6P1%)k|>K^=jQoS1N@YHMnu(smQ%uT_aNCGw4|0ZTK>Y2FF`4&~O zA@PReM7DEEW4J?wufradYL#!4KCpq~gRU{X)Y={h*cJGchgxXpFEmc-b4_2i0)dyXiFcZiN~kAF4c1zgGl zJAJ){=)VM5nXugLDJru2Vgtx09zPR>`X1=t~{YyoBl)UFy$TWuWbnEJKy+$CF1n3czd!`Kqf?JkW)XfRS2%YdZDS0R_5X&C#vG-%a>*yspP&u&UKfpad69 z$J`KK68dLiU1Kc$B}~L_m2G5E+vc0bYR1rPf{sEy!qTrnFF?DJpdbS5)-F(Wo^3rh zS-B9Q+g}tfN^C$mi%lBZU=ss$R&T0QiuZ5z&IQQTtKE%HgKfBksMNWrQG7;bJ_rGQ zS5&7rzVcq=PU0p+OFtrhv{-YRsmx5u>-g+3W>}XV*%Pw^-fzt6jKzr zQjEDP(96QxdADSAKNt#UY=_#>9Ewic5}69EEmn<3To4f=ztl6Xz(jyDzUzTxKj(Gh zu-UYG7nNKlpN@(Yba1AJGRpZ?+j^COy1~9Gbx|6JVk4eJSt47g&)bsG^6QnTA*!US zeurM)8|tuM!p*HrSGV@7hV`PrH99lB-xMI+E)hf_`r{~dWnCZ`_<%OoY*_iRG2LaJ z8LLqS{32j`{7$rVbhXZm7VvQcvC*+lrxqwj#Ih*I8mFF=NRZDIQGlHAluo;2k zTj0GKp@TT9$9uiIP zf9+0E^e$uH(IlpR52HIWh+lcc_}qRB_$+~@)2n(|1MJ`?spLACc_G6Uf@(s8qpoId#u2zXv)G-5slAPWtZ0-TwcOcIW0$ ze;i=dzN4qN?l9ga&otSE^{W53l_}qwV;y}sSMde3*aVx)_&FND+Oku(|!aU4-M!} z3st`E`7b(Kz$z~Xa)oa?0LI6B&;MfZoj4 zt6oE1;W-uk4cC0+6}nMEP1h1>`rV7EcE77$9n|=x{p@FlrvlpVw^&`x4-ZzqQj=6T ze9>P+Ymxpt6}ftBaFfwh>lta~tq&^ae_YyNc-HgMr;mvzU?;lm5r&-W>XS|*SB2n!o!5xju9k-htR+VP zE9Vi2sCCuv2BC6CyiRhB&*@yy4~x+KIjHw^B>J_P%7Mk)Kt6Go<%6TQ%-u(gVzz}P z>bXW^GzT|z(gEDCTWARIl5Q949gx}YR>8kPU=79g{?0WTc9sByjoQ;dO2u&R0tmp} zVBkx)33@97tVY6ok@JPAqE1SVfe${EGrGz%-SE6nyzfDKuq^O?JA^Q7TF7p_udK^C zvx&4X=b-$>I?%;0{cv6X9?gJf026_NpPoL#CsHh7o* z0f47k6G9(Au_7Rx&k5}~Ti#UwFnx;4?=Is5&u63ry7{B>*n39kEI0PW&PT}H-D-ab z##6G9?MdpFMZi2lsCA0jMGeSWNYLQ4WUQZ(dEt{CZp=4*K!t(5kv)?xpp+ZUA8ezh z5S8#)&Mz{9(sT7jH(eSOIQbv@U84fp@m(i>a1MwZIpREk`3)BrbDAQ>mhcIOwhi<3 zyy?^FuS=-a%j@#12M!c7&|z3g-DDzfBo$;ur~3LII5l0+)?MqO{vxe6)n7mVU``CM zT8EAnHomZ{y>NI3dB-k#{I@MKgX2Iw0pt==4nFq&9x%VF)m^DX>;*op!kZQ-vqm+N_u1RUknZJ~T(YV}IDnx} zc>Q5xqIxw>J@Z0kS(jVnf!eu19}bI1-D=K2Gw=SX^A?)AO;NH28Sz$9(3U9xvz8ZB znVTCq9U|uR;%$DSyR8K(e~=GhTFT#TdDa#2j1+QUR~*pWwDRZcKEheid4$ZvUoxrJ z3`?+WQ;^XpdHa)571-XmYe>l8n&ge!tfpo8KGKvlb9AgZ48uQ{UQKMXt?tvHJTS-70 zAB=mLuNpt>YPNl~>wa$0^%|`^@Nx9Aw*bA1R$oI~peoCz20HcR-c?0inHPWC%u^=| zZIx+UBRrkp9O{4eUHs$OsMswaZ_Anoo5x)TIz61nkNz4wAOQsWM(n_S2sE~`D*(>B zbVJyCa^rz*Hhp15S0HV};|~*oyl0`Uz#0w^9z%5Zi_dd!MOxVoy$3cCP;{k}hi>SQ zOjZ1qg!7T5c_5?dlO5<`APn$@H5MLOX?>8=c45a>WHALu>DMICXokSeFsJs{n7q#i zt}3GY;by*)J>P!xaZPsQotaq`ie81fi5Pia==S|0V1vsP+7qFRJ8@Py{BM1lsaDQe&Rf{8SEI^?K$&b}Jy^v;|&k+j#4q_IX#tJ%J!J zn)GBB1Ld5EOl_}nu3Ki=nyPZv$Rb>?6%})G@EcVUbJ93XGP_aV@^v)}sxwJ#P!BkK z&#-mGmh3)RMP8nNe#vi5Hd)-=rk8B!fCG!$H+G!tz3`Zn8a&7wCDyqzkQK6vyon~? z>Ei*#>}L(6zjT{Dec(!?9Djdxx{#BPdOfKvhyUj7)vHrl#i`~_sCQ*MR_Dw1`(E$1 zZ2g!iId^lg1ctyJ86-r^@^R8tPwhaXdb@hsp=(*0!gq-kU{vn=opdOVF+8edrNdLo zyTqh%+9PrEY8D$~Ztg5HGTs47cgZI)(SEAc@5_dmrod73cEzVPakPBJ-uU+QB$Mow zQnFxq&Zo6bjJ!*3ev1|*6ymItqbec^`z{O^n>ryk7A7V?rr5_kL4vr*>mrQq+K3A3G=E>vWB6CJMaIDWI-J+$XGxQ@%r&dJrv)B z?OW7-X)?H01m@K3+Z_Va@*qb^8=C54o*7<^vyqD#sjN@DXS=|qx_eRpmVdp^+(eg~ z(LEf@(1lHda)NyV>Lq7Iz()Ds*LHj{xxI<;_6Hc?9fSkX$}X9{^FG>*D>*xpbWk4M zds}1JFr(Uum0oOQdlI3 zzeAW=8E%%Q>{rIrz}>bop(CcM$6pI3MB5iOIiq)xyG!Wc!OAiH3pf2su&$Q*qO#8g{Rb{XGxq2%_e0F;wStKjBS536K;CR97W zPesYpTS*dMeZdiT4sW+75~g}?Te5N^IXbH~Unh%GK`}!jT9k}nC$89CF4lu(*|M$W zTT6z-tI)N)zAyT7hpxfa@7I%(Bdi8>w~W?(&`SEvbRf;&j?~iK)lbeX+c}%LcB|A5 zj;^Y);3TLc92gCHbOC)^1N057m!UGOkhV_uI%^|y_txZUrsCWUOo`U&+f~fmp?xbw z+32duNlB%o2_K14{OG1}J&E^~RkG}(E7PHDrAp#>-0Y!GCi9UK5Vn%!=!uIG)&`iZ zbD)-WK)#-%6R^7#rJ#_!+2Y0#Nbkj+RNx;n+W400aoLfb-vd&^p-5j4?L4xAg{0&W32P zBt=ZzV;lVTFxyWNTM$0i6^#~p2Wg5MVyC#Z)r1S%ptR%; zJcBX{hUNBsv32-*)kP-r`&ygY6pEgv&hg+F=nRyWaF_m@-0b-fSuj38!fK|30|Fqt zEslrTe=R6!y5LOvW~g&z&Ih{YBKLW}aoogqu#>#lj>M7mk(vB`w@-m>1nLX`{)4bkbpL=McM2QS`q7FKuV;O%e-5RQ$+4qG{=Sa5S@FwKI z8NF>eor-G({RQwVzTZ7s+yGnB_oV@y^X_cZK$hb4kW@Fp2yVl_VbN%7W7A|HFv}@Xw1k7y zAFp;ikI%+zi{Y7sZRu1>&UI%vj9jpuXfOrdIe+NU?JyMH6>(si7pJ!Ryqr%)fVf@E zE8F(1QZaIt*;6UWYW#G8N2d{H-twZC@4LnkXa`dC`XBR^WBop0wC2zN)ARsp=p;Ps%kcELLfPG0r$slF!D z*xAPhiRjtF^WXfUQjMQWI=P`?#fudnWo9^tNm;N}1EEqc=>=WAT~jgh8Y~KETT7-Q zW8eL(uuBU3-2^iho>voXP$n0-ud%`y-T8UOJUnY5{*-Zax(E2(cb*witJW6( z207SCND~sAW;!Rhp^nzNP_nEfVa1`(7pr`64G_zi@5bJH&Bk~yVZXq7dgMVm6N zS>rxIQ=>$K8A`eLpGKHuwNb>R@U%1!rkR_Sf<7+wl2JY14pz^NXL{c$4_ZeIaQbk8 zrf&n5V!BJt;r_TaG)eEeoM)weBdeF5i#&I-Rluq=Uxh%oYNf9oTG-)h2cx@=ZyW7A zUSTk_BND~Gq0LC*O6=fx6Rio|nBSJDj%Ga7{|IYvAWK#T?<`RSFU=72(PAWZxjECX zB+Kcn@s)bKA^8bzXf>8&{9HZ04`=QwZ^T0QdROBrGvupG^DX3fVF=`^bk4nMa7KDF z*PVJ%bb^6G>$_bnBFU(p6YZ#bJ<7T70^SZ<6D77!T6u6JX`5w5c%!&5!i2+ok&j;kK}$O*b1^c)8A znDvGR-1-pu2FtS>p2L$NX_Q)(-*TbEU84eZHbA?cWSd5HKB)<%41w9xLq2zBrzmOO z;7-B8pp-N)bJm+&+4=a1Xh?E=WpToRyHdQ+)$d5|tP0CYUT*=N=G~rG- z{YqvNhAYzQCi_5AQUSA~6n@v_elnhf#-5wW3WFik0A^Wxp~)G|7j*02f*bV0>rST& zY&fbn#AJ=!zRqcB5H-=uHdv;LrglZ7Y0qVN43wS0cN(_td!Nn;Cn&lvgKaZtHb`UQ z2vjjyO!-TSQR_aZaslFosh$hWrKM3!!P+(1kmR}UQJx?9@q5>$F^sBy?c}E4UW~nE@!#n%;?00o(Kgd_c=obD;7;hW*cau7&&r&U-BzNfPv~13DDG{XI|4zwgMYQ z*YiCsuIJN(K;J5|F~{`p^7Q#n)U565Zu#UJE~p`_>iT<&{LrYdh-?f|$}Sz#{S4}y zdzKsw&UZRPzP}KyQ(Jnjo6vN($tceEx`TAtwUOdzeyHgy8`YZxh&5|CzeG)VWYluJ z?{)eGhna0}55!R)IZrKFRI=#(vo4tQ^blpE1_DVBy5=akn<&p`9oH{A(&We4T9eKm z8tG6)G!vf4{od@cYZ~ry)+J*yePGHBH_2BRRgvfN#V{(B^%0@;4OO?)1YIRVJZsCX z6mH4cyqj}GCc8EDc0Fgq*J6<-3Ru)ZdMnOL4VfJOQm2~bZiZx%`Iq)6z|-_@JZ4q> zJpd}At$>Rkgv*|gy7v;>>aQm*s@1PlL=41gPk3%`Hy9=nx;PD+4$MWkk%)}K6WlkJ zJ2%Mp=T1`A3b#@R2urywsx>dG;k4>c8gN-3>f20c61wAq-COe17UM(~f>6#W&gu z)8w)%m$gnm0|Es;d=08H5JwwFZHidXMDZ$&lf3GX8pB)gUAYd&t3w&~jS2}98jzbB zT0Z9J{EV%qgzPBEBej@`1kbP1k;GspUEn855!pm!*QBx`xe3F zs96Y_Lz^RX#oBJ|V{Ur8x`QZN4cJByzachrSSxUYdB*sajd*7m76B;|WNFN`H z670lO2@*|JOp^0^B{rEF-w{2nl^`v{nA7T%MeK>Cxsm)Zphw#)M{486IRN|%^2uKU zX15>*CacXWu^hKVVYcLyLDoQ+<89Cg@_HtfPCS8x$z z=3NLUh)=dhl}fBR1NT$=Dg%gQ>!>80!V+I5?!=HMK4g}@pz=aGUwBu(cBEqCKX{rx z!BsZJ_Lev_o_F>n;`oVU0|_F;M2wEmUE8HkH=;|9)Kbl!hp?DLWo(mpVm5cRz0@f^ zSc|XeC@BEpHz5CQ>*D~@o2sQdZgCv-Ye7(v%*#{?INb3J_3rOTYj>un_MclE125~e zl9`}0R)gt`@YZ`~7|LR``t80OdmLYW-PIf9AWa-;I5D$3uP2x8v7NgtzPu!2%L6kx zFzO(}p4!}8Yd!Rm&x=wkFaD2 z*NkB;=4qPLwu`0E*u?BsWS@RTg3r0E34PE=Y=bCi?l(Vm>UihoYjq(nn=;ALonD=7)V0(ih_tQV^I@%@?J zx*t4E1}=bLS;MJ3E*pMm=8O=X%kA;Xa~VTeqzW3AI&ynk&VV&g>N?%}dedvxK$i&0 zrNUO+I1#E1EzoZ<$N>8o&n9c#lg87!5{g-l)CvM}l)(r``=4JW`w0{XX;PN4OmZ+S z@1xn0+LUi#QEf^)*5N%rBhCz9Id!v(woG$x^fVhja7Qj9B;A-QG0NMyFwYJ3K2qCj z+zLZzHXeHC=@r7OUf|NWI=*W173qNX>y7a?+4gbKNc z`=HfQB+>B}l+b=2;K(n1anms}uUrF&qzrn!?$(`#Zs?avER=C${| z!UPh?mlE_*Myq!BO+H5Z3*w6*>}9rAo>xCr3<%>>FkG<&> ze_*nvN$Cbl@yke9cTvsKS+D10`=t%BJg`AO?_zUh1XyG!+tdSFyIWqxPjsOTVV6r@ z>ewJE#fZKxLf0X^$#SXNVfrL^$*lIov5bULla92t26vA}5QFDJ_7qsgo`}XG7n0G& zF=7{pRXH`2rb$5b?WO+kdlZCv!%G`-iNbX-Cd65j5`$fS=I1dZAqk_HU5rkHP&s$s zBg!ukjd$X(?qeS`HDqAr`i;mrzqDp6FB%wlFOuuvH(J_ITef>(Xd+w|ln^nY0j-G_ zQ~UggX<$InTA;QLBQLbt_N3?x(U4dYH<+fBkWA^9H?MM;uT`!1CIGq=RJL?T8L&`8 z(i=!L$==y78+!sZ5+Qbaq#VM`MoXGVh8$o%T3B)1$4lLHm-&~ah?9MMmFuT5{kaf6C#2G_C{Nt04i0*Ap z{(B)niBWp9=5m=x%|T_{hAp}wz1dW}v?;$hpb@!S%;3$TEhEsX0ojj35~I8;e&ZO63Htd$QOwJPsOk%TRbBiK+UDEQBPAl#(D(W-QC$)m8>85T9nv z6&2UqduQzOnB|S9COZ+TR+qb1$CuUIEsa36U_EM=Bxtc03rTjdms6vU%3wuN zKZPbfg&Y_?I>^+)F9nv7wpMQsSQ`K<-Iu$;o)9Z`MBy7s8yfq@{J2V84ItGoamC#G zr#09!LL}EeU@dfK-H?qh?&QP+Uave}&xygVHtRbXR>J+{1X2d?-pM(ImP&2bEX^UE zF+o^25_Zx6B2IlI!-Fr2I?5gTR^fn=KL_Z_)x~r$*+p)@!aX}Qth;YybtZJG4Wt~t z7y3#iBu}(Mo$ch**o9%ShU-mE334iKQt4?sl%ga(&cshb-u7BCjd-PU%^CC{)C<9At94>=vTma6{sdqBNqe3y0bS7jP4o!+38Dijx z#*1I?&V?vV@nME~5GMnJ$|S5`zp(5y;(ii1Y4Qp|lH#!SH;kgp&zd+fyqPjioG_9o zD!d|ljUL333dCQ|6=(4Dn1p_>h|?xPwT;}_8ux|2LAF?(wW-S!ZUaWoz|e5UPP3s_ic19 zf4=}8_4!bVXQdGF^lH2lLuPw7lu2`DRMW*EspIha)0vjWN41c6&q2h}dV1VRin5`N^SK%s+g#d2kM}v3AXffwnxo87Wwz{t z5z=ROPyu2m>YxEh6XlRZo`)80=qa#|XJgK-oq1+R+o3jlxkC!1dEMl+IX=(*bfANe zfxUpZ_d?byY4jN5Aw-n+5PISrINWT59IzA#hG~f502)`8vF*7d(H|e2j{r+$Y@7HO z0F|zH(A7FTuc<~2`^<-jVgTjZy=c8T8Q^|Z{o`1?MVIhv8CyZ02aTFX2rcFdsFP_S zI-d8@!tlH|0sZ!GKZ+$xBtjDHXnnw#%`i$Zb}q%isI|k%MV%JQz<{+Ug!!U!Y&Xy5|GF%%$=Iz7jJeN0gs*hdR4RoLEU` z<}XKWE}wS0-6*qN0~K+RIlA*k-S)XssuE2b6c`2MWM4z4QbRVET328&T7GKCU2nwZ z^1)Sa9p|i_64Dt1?jQe}juX(9|N-M$o`Pje;To*}fqgK1Mht_q+>OEW|#1 zIT9~+{X)ppJqR^J&eK9m1{6s522jWJ+zYK0`sncVAt91P9fbKc71$mE_m*;I6llOz zt|2vi9abWhz%ue_$~$txwlfFJv>?9g*L+i^#|E%=9Ntj;!DHzT@ZgO#7(%7VK&4RH zy60tLhgo8CAf7}4yJ#Y)V3<0ExB|Pp@W2@=V~g|!9ASAkB8}QazkT(+5Z(>yrAhg? z(&ITA7Z9hjviW(%#cio#Q?F6sxiwTVQOt1q9yEYp^X^2B8l@jBCn$4v$Lt+-3Jhe~ zlzr!nm)If6G$2vKPN(TLmBy+?PAGuYWDZNuO+kSbKsZ5i^8&f~UK4~TQ*!F#*BdJjmY9_w*VeR4#X!cao{D+oLvX4cT` zlC>B&l|Sy#9-E)GOlZdoPmsDKX10+vub)=!*pRW7L~c7<-r`9L8BB{uh_vUMVp|C` zoZ(la`q-K6Y97M15$zVO;Q@(@+M$$W+pP`IgtUcpU1G zI!?R@hvmphdqXrI+F!g|@%gZ!2#oRu8+*c!#I-)^v0LMNZ!ywyX#>dJY~@BE++8 zb4CX1>pL49z}{@GjbJO3!znj;NHk4)@r4JKT6CUxwaFIl?CM21ZjQswaLTz^qT4*m zgjuLq?1?DZrRbG~={ARK1kd7QY&#tXAsv!pq5z~b7Sr>Dqf`A)!k`cyqmFNLUQIh_ z`I0)Psf>`AF43e&t4gL)1u1K6U%(}WG(NqInh44_%*Xd8=mzW6m0GzpDVsT?xCt1v zRhuJnEkQG>z1kZ##azTLxZxUVFz`M=UGRymfDZy4%UHAK1J%}od@3*b*h_lG2+zxq zb2CJvLY5T@by|m+H7L_qf>G(t#k9^TJT&kA=&J9>1xU&=cO(Lq6+bDs;ns+Z?9_2e z-rUBzFKPQLkvwYi&>ObU03$P2m8DrQr$-qH3gOm|iP3`Rihn_4A5Gxz8#Y$g1G*qc zPMB;9b>D6HIm&MyTFFJ0mVhx_oG^=8&%Ich=)8s2jrB{^ziwglP zE_;hM!n~1@@H{o-tI5buO$f=b%^7JyZY_X4G3Q`aEnQAs#LRP`GTT3u>dA3 zy32`w1?e49fP@~2}Xof5?Mjiq4Z#nR5aW@>^5Q&0(F8VxcRagr}=GD6;Nu3!zA zW~cqDg{)H-3gHVc6S%kZ0zHdoht}yJiTqTx*kMHB=>ZxJpawxs9dvcmchdtT&`e!CG93e3L#=rZXAUWFD0mQ&P720?~ViS(+eKV z*shXN_c>EB`Qjq5>`==gct!{_6$l5>VAR(Mj>6FVFh2@X_h-f@0c-&0u5_KylZ;bOOLgNNL`t0fsO!2 zCFtR@0zmHZ&+_eNr;e-&vv=8c+6Hh1-p}%Q#%HE#-A@|793Ot{XD#Sb%r3U|CC&vZ zmhw;VsrF3CP3ng|Q~9%;(j>s9>IqF~M}oiA&stF6$3k~B+e{T`oAY1b$?5=j9h7I} zU*JCIrvNfrkHFVMGY*0T5+P0uKf9Zz7ln#de_9g+lJCIA!Jh@73vC?Ts!H4SM#uhW z#m^V`^LYrVA6oM6{f;eq$P|9^&o;ncmCM+PM;?lsK!Q|GG70#8z(0#QNI@}?9mOoT zp}ibQ_h&5#bg(lVo(tM;|0gB#RA|9D0Nf01^=_%_FK7_`bm1PKG&o^@XKG-HTETe$ zyiG$a8vw6Ol}aQ1)ktBQ2$jqMkktvU{oBaXZ#kgOno}vLe6<4i@yx$HIr!~mr_U1A z6)hh3kGXsB3~h|HKQPK5@lVRQ6YPNljxe#bf1#SAdl7`P{wKL@rkQuP6_oJvU*JEv z2?8B^4c7s78lSW1}H{d}Ow;@&r(f-cntL>*HQ<1lRZI{pJB(6rKObbG`{o4Kr!8~C(Qo2)lHQ-+_rvlUE~bK| z1TG(!-UEH#%7dB6hl&7kyRwv)!8pN)zYeAiB=6JaM!J~cJgrsvQRaJqwPywt@tM$? zq2DQbP1A%T)X_3Pf@wN^wP&501BNYBWum|akrUnBzx`mlReZ_sW@g83vys?S@)+dN zgk8c}zhzRRw17Kj9e&&E`1cY>bE)2Yw3d?(*{d;s&B#bv>(!F%|E@IH`fY4T`%FTM~&uAB!F=eR?YDvx^}liNWV+QhsY+Xq$xafK`ley@hh( zW;teI1H+4)+i*bboCud$w^UV}BK8(V27Pp|^XwgZu;P%syamn>>__BwOC>D^b&eFa zs}xGwpFK@KJ)fKqusfx=Jf?u*DqO1&E~#jEPS|>gaj`#pl73cCRB__@@?^^v0?plH z=(&|mSYH6n)wD4zbg76OY+LO$1-_*Nw@@yQ;ZpiE8=kNpJN3D9iqMCWjX_ z)n>LnAC#gObX-|s=QnAW(gZ# zPTb)}w6oQ5+MLgj3a`$SCao+l^lO6;cDtaEJ>f}PA*%8= zq+y=`@@rGQzas`{>)$cVO z2F}Q-URYvK8n5P+U(%orUlTgm#obxZjx6QcG(ivd7)p>oU3>=PI^7sQ__cnNL%p@n zy7CPSys>sDo3{1#;`4BIME*0&%VkNGb6(dQ!2LE)JdFg)OUC3up|Krado=!81okr8 zKZ|lQaDMRTC(t*+p6u*5*O@d%7AN0S#66ZXh!pB`Y0E{$2q{kFIV8K{l6NPMipI$B zi8?8AJf7|`nxd_IU>;sL0Ze(nYV`tD6xkiW=FG?Pc<#wKVRad<MlDqmf%K zxO3$sMu+^$1_hpg&vv#6UiLuSV+@L}(l6Od6Zid~*c_3W3-TW*vg(~6xC4gKY^bZu_axa}0^4kA8cR-Bs7wpR6{}-BC zRR3X^ie|QzOcTwvw|UEFz8r{^a&en%GeW0n0D10gK0i{mmg(B;^U#W2RRZq3nIe(e zav-aHO|H4cDBNfJ-CWyF%d3sPAf;qiKh$m=J(ETW&%G8K7u0$HZ(PAnn7f=>f2<5A ztZj)`#-nRBdUxkb)fTtXeIeMeBC;`(U z#YNX7)C6R_A#ccB7?%^meiC)g(UhmU#*-3;1y;!MFVz+5;p2ya%$=(BiDvSL<2UitD4Yu zIz_+s)~q}SI=0R5bBdCx9(PO0qqXFVvl14vQ6p$1+Iw5N9I!^h9a_+R*Cqu1W%+_`jh)@hj$hw!@K!><}Qb~t;vN1@N6}* zBPEunMC~r!Mw)JB(Ju!gOSnCEXjL12<&}4)d1?5lq?YMc>%^B6J*@$|k5tYME zhBhq&mj)e6p*++l!v!-ooSv%^bO#Mwc$|JHW`$#Y@Yr@+JT5vvV5zDkrORfrnemG; zsztAKvKLpD^XAHG1@dFx(+g6=MdsXu!4*FNxsW1@wz<4&;a(HJLD?d`mPw-_r{>k= zN#TV-f)V-{bM&=>$e|Bb24=WYxu_fy|H6SqSAoqDNzDbHXi*X4m>H*C$H^8W`N_@Y z0BYNi>(2JGjxL9sbE)8sxsBe5Z6%Z8TXDV$EBE9=%XeMaO_WBa5DRKsUoMKo~#@7WX^u z7`5@Z?^F$*TqTj68nL&ThAs-54ox+XUgx7`uH>4g$ARQ;xxw`oh`!8OdWqDa6i!5jjW1%eyWsy~ubyfo_K`2^LJ>KDDX!}Tr)j-i~`M~=TZv32! zi`;<~zTb^;t+L?jt#x zcJBXUK{#0Vt*e9uv;+IwI-tz=j4hD<)lck9#VscfZfxr(4SI!mdX*Y*hL!I^VZ-8E z^L}kMpSm13LslD%X`}RB&Al+x*porO&N;K?at)Eq4fll#n@XuFQVfe^-}0_Es<*;s zzRPzmRN+ojYo+4{ZE|j}W~|ti*$OSG!FTzD!Sr}1-~$ByOkiasO2j09GzJ@XIb`v9 z{?D@jHU$ohT%M!g}P)yg>Pf4Bd%`faxaSFu4)C?8pgED-rpyZ%0t5n8I~0R z3N(PoHn7Y?4af5&(tP{r0JW!j<2G78kp25>yoVQ_B$F#?yUe*s@7>*{5@jYgQ%uWH zN&a7voa*p=gTe;I0HuwHEgJ#@`5PdJEivUEW9FEpT{9}@F9L2LC3}i{_o+TOSysWI zhL~6ygBWMWEzLdUbiCwQSy7mmz1quLX=7Wu<=EZZQ1-#GygR2Rz$Lz!8;L5|-Gnc! zjEHQ{d6NAH+iAsD$~R+*ao+jJqz9Dvk=?Ky?V8;fxKt6s#f%vn;cA+TIhFu`adLVMCE$kI#sb#$Gf$pzfjYXkWz69 zI75&qDu_R7N{Qe?^qKDQYF?%jP}r~csBLu2gP8!YPLtPnQZwe=>fFdaI}YfkaNOKL zIqyb?RGajJoz)EI!L$dj9N&Kg231(_rq(EYVGIqJNd)(AE)-U-jkInJzw#l=q558x z2wpxgs%#A$w%!x#9x>0xTV4dq>=Mf^=Y@3f2I1Fp`h_+wW!ktxt;rD&6GY1)hrIHY zMO#w!y)Qnl1F0P1QZd-%hE&!ztsZKW)mt(tY$B^t7p0y2fyiCGUDyv;pn)tg?Wo=1DCQBtLZQL`3F~X&B-X^#mF0a_n4PjFoT~N!o}bwGSJ=@Z8zI$Fmww|f!5=|Ui#14 zZ^wYt;j4eb`C8^n?vuWx_>b`~?UTM03+z_^SpscB;GiVy&{WXofHeH@pVc7HQ1=SQ zoNc_56p!alLa6PPm~1yu8^0;06aQ;&|NO10R4%+H~uP zU+Akl^q18C7&z|Ue%IGx|G@XIO9GId`-27RsQF=U4>scF+R{bF4*Dk|`_ykMA3qM+ z7pzN1cOtVR`^?)jk91hsZrMG0?UBkpb3T|gO@Bt`Kq~dg%9AcCGb)KX(L9eeDZni5 zp#D5nO4 z{uXBLJyQMxG)sC8k`B~8@i$r8dj$G=DszAB#Q#xk{t{=wVS)R5Erm3#i{F)PTH>H@O6_G`=IAO>@Bpx1vEj>iDn@&ADzKvG}G zuOyuT-oCS0Xyy5{mxMQ({f~lQJh)#mNy6|w&iEskTYT{Y@aI&@qbEhl-{*lX>mNnl zSEteGH-Os$KOz3?P)r3l!$HeDpoZAvjNOf22)Q0|VRZg5$O@VF7Z!gu21Q8z(jn-~ zO8}Rj5P$q*u>aqD2PWm*P@=-0fYNm(EmN%Q(dHGCV+&cnp-HWyL4Q62>8SpRRxO`h z->B!2qoJ2gmY16{ABQS7|0mp^O>4(g$~E%Z1oF#os2z5rZM#sPcf8=_P+||vdG>E^ z2aXdXf1|yx;zHfhDLxi|P&tY?JOB4+d9Tv~CFW9HCbh2-mqAuOzYxzQf>(G&4@j*V z%P&*U#NNg<3YvfP%dmCjfIOJ9|3_zMi$M?kpM}t!Y2y1gOGjPj0nt$WMM0#Ev*ZF< z{&T9iT3-QUSN<|Pqpm@~*nJ0nnW5*F46dNHtAFzTCr_7#;0Al9L+d|AKPMMR|NiK& z#80UM$4N{8rTDX#-~YOn>3W00+x`b`wm#+lZ^Sgt0mO^^Iy~3j=zFH?pM|MmkMnz~ z_m2`-_kms-wDl`P9xP<${0}@73Hl#UazDF=l8#@(KZXE2_=lC1+1vE;!g*6GD_?8v z3LgE>6f0MB=fQOtw2yhNoicdwG9HWVpaZ7)jF$0VitiHi zfGGrYSvl@kj!Oe(*PQoPX$#vUjNzBQ8r)$%vB0BL#$O&i*RTKt#4ECK82m4yRmR4c zJy#L$>sM=)dD(>KlOM8Jdx<#f=%~;AC&m%ZD6X=%0SZwD#^k=@tY@eJX?nrN`93f3wj}Vh9Sd_A}ZTNnWS2Pxz`u-ck5k}_tn~Na78~{l z@i^Uk!_0c}hwnan z{`70FsPgV^`2=r-QCgC(O52^R^xCQe2?~g3N0}-z+-<|;{Ej{D08RoA;==Wsrp{l! zyrhIOn^+QDxkftZHRJTMtn6;0w6F3ObvIo+BW#vJK+O!idKnywjF~Uvl0js-Mp|Uu zEq^w0zZc%7VAcd>kt0-BmU>WIwQR%h-FmBQ;N$C?=4-5@gKkZf$s1Q?-s31hep#OJ zt_JfXGH2N8+L9i?8{Ib+5_BJJ8{pX(igh4 zmEKeJZryTqt?o>!{j>dfEWiC$G+r7yQ0ee8Z2N=i zR9n)mYmb(oZ}Rf;e81x}bZad1^fC>NLgPxJ^7C zCyM98gU-jXZ|gN?S9^w6R4RGGHBW6%k5$hS<|F_Cxn%c$2>TAGrnatI>{q3T2q*}s zh+L_HG$}zvMMXfQ*NF5kQbG&C0;ov2A|N23(tGa&RHP_PN(e24A|(l-hd?07+u>fn zAMf|S_ZUORAe@|Y_TH<^HP<}*3_X%{?eCw4z+ACET0bCPqj+R}8?$#UuGnegL(@xF zCu@Wb9fn8Ymx_zoyf%7#&Feiaf)8=S)Ao$z8n*YoIVku}CFFBRhp;|A+wKnf=)`0> zd{~>}LfB6ns=q~^AHA*H1-vFnIq;@1Sk%}1dVkJvzvs$V%ylZf;+J>RT}g{h4-SU> zfMEj)V%lso*GJ>uzRe<_Y5gQ81ff!#cNI0WK#0l6mwh;E#2J|PR?W8UP;)qcUTOSX zNP=1QvVBjb=so3gry&+C5%cJIzQi&ZnhRLq$V0)GLJ|@ZemU)>j=lA93CK|?-F-%O zTD-Y?HUs7R)FTsDT50b(Q!d^*JRLxslVbL!x@-8ZaLSm6g~PL4643;*IB%I9+IHW8 zbeGAP#l^dPN+sGY5p%s?s-t5>Ved`KaRm}82NZvX#JqiLFPmG(NauT}p+siIrF6*RR)zgVo0VFc+QD zSUysB3slr_{<4zR!CN)nq}OZ2Q9KwEIQ3l5OnY`J`0QSZiOH9O{wj~n5Ce(Ce3a<) z(5lSy+&HiS?fN*ydpQ$7LN!OO(Cki>n4Ud3(<2tj5Oxd*^s|M?;>RGIGyg z@5qVCvWKI`YUfP&`T292Rx%wszAwmne!W)iiq!xU?)`RIV3X|JI|fty^Uqn=8Yr)T zKxRt6Bxt#z@sr)yY#Ty>ccQ51C9mZo)_LswoYd=E=V$$J6UO;QpyzBTDTBFkNt}jU z!k7N#<}?u}fKR%TlA}w8P2us5#8&TO$BmPk{Hi0K;)){DPct8vpNkaOHl0hWNw1?0 zTuD&!s58ian;WT0H_%L|ENy&7SMat@2|;2t5l}@tuSj5z`6dwchOMfrdqN}hH?^qm zXfxYv@OCCTFUXX<>&%%ieWg}{e5y6rX<%4$y2D(kGW#hl6^qqdN_P&VVLwxcNw~$p zPX0adKdLVZ_oZ5?)v64soIihyw_mI$J33SrF(?W`oP%`xm{jmxvydqvobn2H(%cN~{}7`dHLXwy@XC8FIOZI7@=R?;N@I- z{@4_RgnuM++Ux{06V+g-(bUwW=zq*w+D=zl)E$KUga98%x6lAQ{1BG^h}V|SpYRk*{Pn(>!&k2*+JqXQ!4tClM<5@ z50s>^IB|XJ?bS$a?ksW;UWC_HI?lfDJRic185z-gf1lmgck|CR%U7=0n&b()?(ArY zPW@JJUkzL`cjk$e(Al#JbGP;$AiEiYvDlBlB%Yw{jSoX4_4`wY{)9jz)Vjj*?8fWP z15DKIFYv0krsbv3MPOO=Ty(LR^M<#)@W`A;U3vziTl=QQ|5B5Z>aOvh$jqtMF{=wmGs_QB8BT$Lm%J9c*e?2<`2}c$`q-IZMT1y) zHW)=h!BiXcCdRL!&@iFG;KP^e(fMF`oHi>`Wc(?HHS1`HMyEn^WSVveGW}L>tdh0s zr*^7;C8}0~BRDizfw4qV-8wu!GGiRpm0-zrJX_rgyWWMXUGJN>%j@C993XA93pWl3ZH)rDy>FX8UXP@efHXMc2 zzkK=X2Ls7$&F;d~xi?KXEntx8u6%eWOkvB^40qIH-A0~Uw{9sexA1FjJ;;jSA0_k| zUsZd8Du=6p=-)mew=OZVrTOZjUSqVEP*yCdyY%A3od~qdxUrHM4Hxkcjq}>VgLQxMhvkN=}4;%KJ^S zt7!lcIz!XL&UcjgpbD6WKP!MdK*9~ZaY|Re-1#n91X`SvqnDo#Kxy_5tLrh0QEsk_ zoKw6_UcmIfusTrgvf@V^ExrYiZwA~JB*2+mWLkox+#NDABPq`aV&zy6aqx_i8-Wl_ zPEmBxIt7?S|Cr_E>SinpkBVcEE4I#7!M1Uz$?t>ro^pHCCCtjNBz8|)F6HNg<$Y$! ze`K@Owlm!<1v!npa`;EQX#c_y@3nUK@__V@A1nyzHxiH!qs3E=Jy)7JJKib|c@mrA z679dpYlzK{@kN1GQkCKJGQ@`nZC(2vzCCdWu?pO94<7QI&Bsgjl@msaIup$)gzyTL zyg=%Dv052O18UT;7c2UeS3GhzDeDwd>JXiagD*W$B_Z?py=PPz*M0-wK8_>;kO34L zV*@R-5ElaKG*vT!ePxi&bExBoP#PhAOTrpX^AjB+TSmn)BuV3%chiz|O^#;P?mA-* zW&$Hk6jsh>m`KXr#*SUk2jG)5r__f>FRZ(y(iF*=A4bP z<@ci~r_}@;VPphDa!$wlRowGJb{B+F$d1|XH({^&I5;@+rBaxG)Com)h9A~6Ei(iN zAFS~5^gpvIkA(%2OfgCu`GPU5}LgGVD4UDb(OR68{| zSb4vUtDL}sGM4t&f*LYMf0*Ad-N7jgeZ9V(_C2xieX@k9j*H@IKgceG#w+HlGcQ!{ zMA9dE$z}8C$wx5q&6PS(8SzM^h2o+)c;uaO3+pZZWQ#nRz2**TCFG65Y{zg#d~bO+ zF5HQcg}r!XW^f+=1m*jN#kpsZ_IcRXGPhs9yp>vDJA0FE{^KT9<;&49RqfPI z#kY8Als#Bt4t};*^yif*0BFSKwGz8WFe-f?_3g?Xu%hOt>!hbd9Jb^&`igFevIJ&6 zePAWP6Je~3$WinXxbNfm$Gb^@XZ&jI4uj&Pdq8Iazxdfa!zm`WuMdr-zTet+C^I)R zG7?(T_--&fKZX40XRCt=d2PvSb_NN81PVkfy@D+dTp)4sdP*NzqY_7@5myOaxy%Gc zfz!;=25O*W9Nr(8Zf~N1xw$#1;}t5$d?rSQlnu)0X^GK1Z*iwT&nb!w4uQJ29I@aQ z+0Ig0u|EkhS~McVM4La5>O!g34hNLO5Ns~jfao{-?WlGpP8I;)9D_+4{d^1c!!ug_ zhN)P2q(r>5(_?+J z0Z=SGdBF`?#!u~-<%=0nVH#?X8^a>c{;S?)zULc|UF&|}2-5}2`XnxAu9KeHs`;i5 zvi$x097cX#$I-634rHBY6l7}DuibkT0bnk-+U+21Id{Z`>g7_Bkei!3dSW#@`rK99 z60cs9-bC{R%# z^ca9@KmOd7dFE)YNyEmo8c{V&1Hj62Y5 z<;NR$(1_uLdh%Tj?N>PRd<%}|rb%BWksmwVX^NWWTmMsENCnEW>ZIDe{P ztL!S9K=W~Y{?J;HuC+ST z6pDJwEHY`ia-?i=lYv_aEEB0)YXGsx$vtipTS>F` zKv=sm;2PB((OVu8ZtAf0Mu-)2kUPE&<{_Wu`gGbG7jrQ)ld>vcTT|iIB`0+5Tt>Aa zKrIeI-Hn2wlzOF}oDD@!U(=0cZs|T4jaK^P$-D`QBO)5GI{BkMMpn&TrEM(d8MMWO zcC4Ja$IpdMuz)=y@slj1&yCHvU=tFbw}thqjW&cXDSi`N|Y;*$(MH4L=*CRbGop_O6oL%N zOfsw9Glj$1^ae0ci@fzn15Bw`+5J}&r{o3b#uo40wJYsKZRvs52vG2QZnXxgA@7cV zWB@}HoVw+a?VV&;=CVSuCXK!KSMAl!jFEUGf+MY9^1Ki-7PU-wzPF5 zMLz5_K-#LfjK(bY{sGG8)qv_C=7gIJ9KUr5%8Lh-T*3vfYz9N@%w?_p*!OTNp!7iL z8Bz`~t|%xV9Pm~Sm8PXkFh3cWek~A1<@(5TBYEC@*ph5{>4xuJXz6^c{K2*%e4z)z z@qU9`h*SEIm&LfrK`u`Jk8jM(%-(>XyyU2;_Xj?c-^fEh>-j%>wl^N)ep;e)%}ElM za%7#(ptJ*ar>Oqo+amz)@4wxb4e+02QfFJxH#5uoV3BH|k_a=;vnWkI%_KoB4FfHX zfi_T&^yPY3f$HaMZk(98R&>4jXYPiZ&0=Ry-J0oqcQ<{;q9_~oJQ#DW_h`iBHGPnZ zL=0)w$09FPA^c-mgJwDmKgpbW19EcIkNdf>*6V8(-lzb;eqHE;`j&^A!-kqtJAhL- zFe$6Z+fm&g#yKD3b@nlO?mAla@k=CUsl$!Z z%uDMVGxtClAxGNxkC&Z|22l$1W`ktLc^@7qT78ato!&M$QroB7^|rq&3F7MEcKJ2H zC8!3N2ByYW)>s8fyP8lwX1B3nGoqEz$|Dxc++S#6@3GJznJn7}5P)9DDZ!Fzz*woR zZ$jrLm^J#h7LgyO@%S9r{y_XQhbZ%SjP5g@p@CJo4Of+i^ z1U7t(gU_aB8sKtGmAX3k8{rEnxP*K(6aeWO#6raf3)&~sQ>^!9rbm=jRbc`!{K3>$KMkx_t0<;~-8=?F={~GSF&59HpY*!9+`&wwV&pVQOX;2;uFb!kgwpW+9ZnhY>r?Hx_yXQ7F>^#myp$Fe>#H))`zcFy|*tuDo5^25-!BCw#S08w^T_zEhnMNzd15| zd9mXjAo4qI>7Fii>ifwO7P*%m@N?Lt*g8WWjxeje26(OzzgjJLKK_8U5a4ny=5vc% zNIw<6Vo(ei;tUdn1===tD=H~T+53mg$#tLNqYk4R>&sZKf|$8gnk_DYu#6qKkcdfA znHs<*fpSa=X~3iETl_r+(J3)=d2Ovh-h@uTm2gf?OuU|kbeMR{xS0$fc^D z(L8tS3AC~x0I~XW5)uYi$P2SQO{I$d z(^Un4TZuX_tu(v)HKT`-L9!Fgpx*c_%JpQR+Jm>yJ@2o!pC-3T0>VS)8YdPy?Of=X z>VPF?xT^oh4-o71y#+B*wp>`XUf)tL>J4%6QO_d))DfYD*^Elp?_$1C=-R@Cq(Z|6 zHey8>oD33 zvJdnNQ{b}05-Ypoje*AmnpF0A<~x!UPbe{$yh;rv^EiUi>YKM(#4Bd>P|OOcd()hB zJE&i)BkaeZsyvUzc zdCuDBi`s@=iecsGLZ*}4Ka+YnA?+BGc5Bi3Z9NK6Oho$Xixp$>EiE7s*ce0;b#)vwOT!ugyx+dL3{bO4H7qv`FJDkp{9ZOsv`QfeNlLn{te8}3 zsr7R&pSoFEzuDuNueoVqfPD^Mm={N)i2B#Jx-<`K$N3sW*PDJWKiV?~xGNJt5aCS7 zkf-^y6ZxQijV;7vmUQW9EmZ+XMMyj-s9$+Q$IHdg5cKNwLE2{!<#HXlI1qupMMzRT zeZ?)xbwN9?+)?6}DgV#Z+MIqyoFBKW^ziZdc_E*}@v`67YwFpELbNAg8fDF3+Y zKtVfiEbUuVjIW=s)7-NKS+9N`(4{lVX`usq%g~}+3%3wSKPRc054`@IX`xPTeZQ+> z1~=4oBI~cmcczBFrSM!;=uxemYoLy{fCOm#Ih+uuN$~e}?FWsI6W#^oH-PEHiYF9A zxb+zTw3)bhnsD>>?Vd$8KhXUjDB?Q)7HaO#a@$Z<11%O?;NH`Q!EDupIi=4zwF~b# z#zpybw+s5dXmqXzo0Gf^7HZRREv5Tg@h{dqN16q2`uI;Rawb zws1I;wnyD~L~IPo5DWlpAAY()i3q0ba1L|1N2#1mHf~2t881nR4!!JBpylt8l zc_pRC4=W7~ivBoti~mx)|8;i9%RHc_a$F2z1th@zk{STYfMsPq2^N6$Shq^xTPqB&}Vy#ImnDqGB zn*Big&1+z(b?|@~0DcETr5GK+`O)h52`9SpQmCJ|V_K6a?0fGQt+rMR+dF*ud<`x# z=DakVJdX8?NsUFxu@NmvjoQCVYjn7chripDk{G0<)1J^*<#@OV=w*T_D&$aSJDcn8 zyJ_D{R$baWj+1s>z268n?f})0Jt!Q!eHT_1TR&7{H?IL0XAkDSXEgzY&Tq7OM&q3N zI$wll?T|S0i#JXaNpC;L(7D`T8tD`xirE!jerkQG?}%pBE(g%_eYzdzWEpd?ZksKl zmxoWwjxv7+8WdY^*~(l=yM@kf(Yw+?A$9xSy#()%ns@H>wVqb-0+Io*g_T`OJ%Yov zfkZbJzgm|P)r)iyK+YN9pgyXsa;MJO^Jo4%H<&f?^FwGnyytdO>Y8gtUsD z?nrp=VW;($-vg)~7@b@A+LT!0^o{9ChsoQTNvj~`l%hxVCT(4MF&7n^dss@>sx3-9 zOU0Ce>{LV9i2bvXSSj<|;rG=R{;6U5@Rsls&VKnaf!~kD0E%5-1pthCpAarMJsf9} z>AFV`Xeesm&49K&#nVR>w3sE0F@PHKoN>Qc>1Lseh#O2||>CDixZlRQol{oWyH zgyYQTM4qKVJ^eg0L6ik3!4jmrUM2L4r$PfMpZ~Jjqs7TZxeTw7(Ruhor7@v0vap`! z9n8?`e6em75!+`9cr(;k47wbjsam!cmx>>RWqp5>`(`5ih41c_>aX0_H4_vRf+py%2%6!xWtl%$_N)l<@Sn#Hk@sV z-wImEp_@$!aCVob4z_2?*RG;V%Kb@%&ck@shi?vXN+dkMf^_8YW7vg}1-P*Epga*! z8Xy%LK5B4x@$`c!lCj-VjuA8OJQ#giRO;~M+xN&2f!W0PTt@wfo5z77Y19po*45G> z#qwBKNXP-ifV5i4k`P9xHs7@{Vg4j9h=JHnV@WpwLV-%1n3-f#OOr8b0RhH>Fj!n( zE7m|LV1W(_HQBM>???c)D3*aX;)_iHP0@>iq1QBdR&cc;eu=C|RCR4Jt5J#Fj4cvf zS&oa2WVBnc?PlU^Y%7_ZX$+MUgtuE8;PG4D;XeUt>YkjzmrB}w19j`|Sc%NXYR!&> z{e6e$IPIhUko}|xYUm%I z0$rG)SJBzz90>n5GV*qRNcVl*Qm<89aU zX#S9=Ay~rr0vGIBG_I4>I@FmA$$*$AibzY36ioxEit%BD&R;DlMKukXnO1IZ%RSYe zRdS!du=z%ScX7eI6gh6mCu3ghd! zrzGzht;9O(+#lU7mtu!ci!68U_Ee*;6i#R9C(eh|goTAA``5<;Ry39GfSY~azzM&S zuf1HGE!Wg>jgOPcolmRM|CzoqCQzv{#u*CF@77UF6=%TZnT->Dq`G zDSHnW5>}_|p3X_jkKFFr-GCcQ))tVKku=FZfNt`@KosCvNTYGf@aSxEE!=9|_*b7cLlNX6LrS*W?>O-o* z&5;40i>84YNeYYKMTUsy;i*eMEJ70b89kTi4DlJ0gAU$5BUSLj$aq{Y2WaZ|)(M&F zmHFIC>?&O$r^tE?8L1)Rne_}zms3b4kqn3BH|?p@9E<=r1xkW#@f(C*)!+>{%Y4CK zjQDGf^EcHP>RfiF%8QbRmD*GSj$2iFTvJz1CyWHe16p?#g+9y)q$@z(Xh3E3qK1?} zo4*MSxV%e3wegEhM|%10tAkcdGMDSi;xxYwKNIBAa|mVKDeQ4``r!uD2dYwD0%t4p z#KZ%V1-5^vfh^xk0)nBO1tmeoB-&hh#M3zVdg_$3A0u|;$l~7?Bq_MoKUFD72HM6f z|4_;y-y_yWE33=>?F;hw>KUiO0DcYm{Dghy@-4I3b}i<6kAYR#mitix#M>f5xmvj7G4u4eze4+k(tr&o_+e!l*) zYi}-7T0Db*bOj&;ROAoVr6pumA7eV%m&fWIFfHgVS5UKag9^2SHx_nt!6qyt5fWkY zI&g#f?xm{n(CL}$&9!hsO@E=Wb(Ue4o+iqvzceQ^F)>k*?4upYE&2gQsVjK4zHUtb z^iYBdRYL_z70RXT={&}}c^By5{)RLQ10+7U!lQfpwS)6Ido+XC$EW2TjVFVLSjzlc z3PWlJwdz{^I#X1#laqMP|2bP=*#U$dx^@M{!wcpD0xM3j7nIB;RsN`Wm~TB^*ShuP zsz8=$C`FMv!`@4>OwGswEk$pYnaQTx_LRPEIg$dXoE+do=u{x^9KI{LcI~{^g33UK z$CpbHfCmC$Bw_RvaXW|v8pJ<}nR`?a&KrvZv=0jjWQsT-Nz_-N?s?<{df<$%y?C-J zswfcP{e1IFP`=uFD}BU2{{9Ie`tuy-HjatGO}%2ON&+EJcjNG}{-j~~*C;EX9|Ii# zkfF;qPTDFFZ}))qS6Q_@Q(6lJb(m$B%Pq&D5enaNI)k9V_Y>e9@w6CA7r>Eo9`iH= zIlu+N7NrA(nhg035nI~fi3EQB2cl7AW0_MX-_-A3sO+I*KJ8_$=bgjyCfB>Ee!0WB z8A=HM&2`72yz(4?>M@;UqrWCHy!k!L91KKw&FjP%NasgQzZ&Q3waL9b(f6-jeT7!&zff!Nnl@;D!nh43%8km^ z6=VoqK_r|n=&FC4jvn^(_+tG@6|ksT>}q~I1^Q_SSMT^*pHg$IKZD|*7`URQ0#wnp z$~J8viZfI^rx(0s@{%B4dfN(XIRyS6JywvqDN#|#YwYXYFv6urRW@TX@#aR3bUW}^ zLX<6dqUe;8h)G?V12y3rHyXzYI51Cnb^n0D157wC+T5+)8l?9iGjn^P^i=y(JHrCA zqP9y+>b0PuKGZ;a;;=r<=n})XWXIhG(u~|!9u87#D*<+5P_{Ldm4%GyCfyq`ap)Eu!TA>g#VZKl``W9@Zb zEm^nzy$pf?d>xeYW!5CuTCC3_z#8ekrQ{XUu2z()6otN&(?5wm>EI zjNqL;;f%W2NB0S+)6DIHR)DnDc*LeRS*a0d#_nx1yJ~7rz(_yoFgP6$PvRjbzJi8N zJ;m<>X!;PIeTzy`)|oiZ@Kn&Ok4AN+(0g5H7_5{DTUpUX1?kF5y$wBpO}Gct*_QdB zx0F!oQ+kL?WFpFgTWqxoxN~1)sMI$+BB`{iD>pr{x60zX;@ZMs1`TQQ4?aoJ=$)Zv z%_J92J^L1fD0ti)xpA4%F|4upa8I@)fnK`%(NytfwYa(e;EHV?NNNoA?ZfEI=g%He zf3f}EN1{!blp$)(Oi|*17Y*vsj*-u&dvz+misGLU-z#`KR>Tgpf81DjEAKTn=g$qT zfc8s{ui9jnf8)9QRUmTqR^gTw04rWyTbnq4l^YZfph;NL=Bw=C7vGPp^VtGpRojHk z5|hR6?2!RvIK{Tv5e3LEj&o|>lk@W*GTR`z94)NpaK>#FKLHvrm;@PToNl+oi{Hbq{NmqWI7r5E)1vG5Kp7S76 znJXZ^-v#1;^0t&c3ZvSDIDG1r=~@xcgt_a%Ma==t^P){(VFdZe^K6uiEQQhtmQHAOPHQMdx+JS1FYc9O9%PWkk*$Cs`)!C6j z0*T)U!@-mnBM-e|-mq5rArLTmwfjD)U2TWev;pqIoU$ik5ma$Ja#e{AZ^cd-@^`#z z&;gS$4~)zldAIg4Xj0uWMVM!HVzA}a^cSfI?hv$NeTJq-TaSZiz@z;BY2a|lXHO*P z1IpM?L_+s*(@kS?${EpdsN5==Az;JT3rFx>z{u7B{TqOdE*JMHnBG?ERRx0A4&yrG z>tQhuTdOr;`%||v zl@8q3zL*iwJ+_PQP9yd@KjNx}0rAWhORYZu<-HV8Qzp)*CGsC!T2cf#0LLSL+Li^j zFrwGeFKNPzsDzh-9tu@T?F;rbqdM=UfRfJzze#A;$0-U(hpw+Hgr6MJ;Aq(TA+u!; z8c5}y9sHre4UhZGz%vp=)B5{T;Ee&;&;$jqc(q1sk1E>2miN#zAj<% zd*?oL0`&WV+ObPw=ASGdq@Jh*7!hwZrjaWQ)~Ad%In-o89@%Ph1Z1U5A3@H3eo>NV z*QYz>-1vlk`8;!HkFmQHVQ2THFDKMg)Fa;Qwf_ru_G^n%Us0uu&6huVnM{G2sw@Bl z@uogg)5|kc6S^HM)#nE2RTif_`quediSqf~07Ed7z%v3lcdBp8kwPYuR6NXFpt-I! zlNF4#{p#&|9V@%m4wXrMRuXtDWqIZBg+9iq}kz-n4$893?P z>gBHZf_(E0q?&* ze5fL;AZZvOWxmko5(L<7A#KS8=49se7D?5DyFi)DXhebHGex76+vOfm+FkU_poE(w z^czYfTKP>n`+Wt>^+#XbJ7|XAW{mzbKP8px>(_#Vn~k@8)J-<~k0s;56e zC3XnnD_bt|E)FyL@>0JX_x(Yu7h0&5=Y&Mi^`|=gDd>%uK z92Pk6!7tnbARqcHm>CE7=eln=+SWtT_v@O+mA-oB1C-w_hd#-`P$B^~ONB3>u3l@;<8L`eP6>erK|9vv zP>(6d&0?Iy7~?UAP3o{H(2Jq?4<0<2u-J5$0pdNW;E@H}*3^()pI(or1X@ub417)@ zIa|6Lw!E3clwSuzYCZ6zk_XYr%~L1%r9NH2AI5KCXf7PMp)alHtOhxC`b#Qt zS9|2XC8;tsO`j94eCOfnvErwqof4Y7&{3TN85)s;&v+O*8r&RyEfn@(8e$rUsT%n4 z<2V*FBfX2a+QHfRWpq6SSz;HdO1axU;F0UI)g4OlDhzg6nH=aM^2%Fm_Lj_K!l?lZ zUyEKUZ6*r8f%9SRr)pYtvXGn4=~iTY(L+?yLUbQgN}GPFRaBZhtUkv_rq9b$Yq|td zd=yw!7X^#$bxb2m!&MhQ5BSF6ug||B$7QCxQnL$Gus{%}`0d06Z!|TjR%fGOGC|5^ z4b^8mm1b7|jJd7SDMufZb4QWr9MR|8^n$;gY1TGUf_PYOxcO|f^=da;9tb>Z;X^Cr z#FW<7DoL!*LL|L~OTEv(KL|Dw?}mdPJo0p}%< zi?u49u1H*hkM;bXrFg-HlL8nbhm`HyIzje6NBDWndSiZ_zZi2|W~RUUJt z*bh>ZpSqe4$YDhASdyzx`n~hX0b6YD#CL5EI%BwFFh5M8P=QRumHjI36vBB?7Sw%#6ztrT% zf&$2N!;)j&R?lJhC~Sm>V=~XfKSYHI^$?%8GEr^_eQD}elhFdYKrl1k4Yo;q3iPO{ zTdnRLdS=ptB(HNVStxaNyP0Ks)5RNG8`_agPswz-Kv)-FH)_y$?NWbYnPod|(51Ua zTABc5&8=#)OW_9A6_^rvo;&vXwQV~~pu-$e1UA3LtACw|fY_wZ__s*9Rfz=pHtH{I zK&JZ8=)<3K=l-f@`?>@*sy>BhW1~teSyhgDXI42Ah7IvFD7`ayY2t9#8_fF=6p9lK zrAAlL@F`!TJ~TeqS}%Vvuo&y(@omCqD#jOi1G}(3&_a$Zd}k5Zrm&|mx3Il!m6n98 zi-^1E-r+ULYiE8;m>+gO(rpWm$G>!%ZjWI6o1Q)`1^%4s+xo+(rcBTxU_732O2`6y z=={%FZ^vJgCf8Yx27EE08eVtSF0sT$W3m&9JqDvuGF~n; z;QDaxv<7JJLioqN3Px0{wo9?dj&uRbTqf=#xFmHUN>*03CDM*=_|ET(rA>p>3?I== z;zcHX>srIS@t?;gR$AWiw9wk*o%PP?*DlCjw1C@KfPL^9Rw-{IBG%SdbR)@|$)P7{ zP3v>qT3S}hLHa#avgexTQZQWV{A)|=Akf9a+j$Ftywd`9eZ&XD$qCvDPa|LU*3X;& zz5Q*E-5!M~e){X^rzisfK0`CO;apwY=)#6YqANsvdc?==PC}i|q3B&{nZ?EDJE`68 z6v*lxA8o#7>CGEM#hTgGla8s@QVNb&Hhkm#|{X1n>nVeFwVdxS$(>GtwZ2C9Nu&E?@h)<;;MF;F|n>DJ`ofa7Z;p7zzr3c zp>Co?Io%>ntsVpr+Xb3q&?9^t=L(`fKV!lTxI~_CpUh`#VcfN#dVc*qvc02Y1S8hD zR@u0|d$??@BPN%oEOePDdhC$t7sXvnR!Py!oyNElIAFPfB2IC3A=JEDA6E6K~k%nPHk zRIH*}-h*)Cx#%5mk{;vMQb^l;F@Q_;PgfS&4nYV*VWtE3bo17je2vL)LJO+F=Y0!l zyixt9VvB^puq32rSa{;|=KM=2mKIh;uUDFs)K*~+<0_{%P9`LVeyv$BRn2g%c5$YU zV)c%1$_ax3#e%!mG@gn(k&?t`CjK@sBjdpYtD>ujP1$A!2!!m z6+bfpRZF5-G9rA*srjIA3a2_^$;rLNMZS4EGSNR_mNJC}A_@wY5e9tV$N@*nT5(eu zTT^H4JV$=Ml}CI`jJ!>0{sRYf|42e=OWt3&6)g)yG-LkbF^H$(azwHfFK?oBQo8&; z)3pPdp{R990zB)(^h0Do{e$ZdR9K!XFSt16M0E?zMfD~HB&G= z!3bX#a9;~CH%Vxm<{KdIi1MNug;^v}MwqMpnZvxp$dYHgQB!Pg^9A&EDKj z=S;RUbFNylE$&byo~#8K=WW$=&4T+Q?*ZS)w{%LbN%h)`4=|$)V9rJmW}t*<5lK_ zk5$#aH=U(z!W<*n+1*^MMjnCHm|7*$y9e{aemyH8cX@6OiBhnAnTx>}-Cs>ry}C59)C2y|qx9e-*9utrWm z<4thkJ@c|f02B;3VV^!IgtJkG%Wc|XZ)_%NJXl|3uOGZ{fZ?RWwHwZ5-}=mwg%9Va zwlrNyfyl8^R*Tu$y8+}0<1WAMznR!QFmOx|UrXqpWf-?jVUd+gpZ#_xas#ESsn(f7wMni_m49aFWd?qZx&P{Lgh5w?F&4;MzF zb5yoFq!;Xu;RSEQRX*(pXL8=LV^6Ez#Qul76n?nL?bw#f+Ht^zUE>^*8qLn`CAxPU zBRK;(dg1=To!28x39&DEmS-|Ks+pJn5|1;k`yR3LPMP*R+qu`!{h&V${@(f}$kAtf zV_!GMT*TkN(D3;Sr-<*qe?M0mWc~L(Z};y~zRq(uf2oKlu@e{9bjJz`&nW-B{nh1? z8poYmj9sP=?AT=`D!WjCPls~lnpouXCL8{TeqZwhrj(CexV&=!B_yrF!6WRsBxMPi zsY}ckictDH_M{0KGRVFEH9h=UpErjX_mp{_~f_az!{VNJ;fz4 zM}lC7!A*<)V^-Tkxj#1eh@$9Dl7yfMzD|UqlbOa-V92C@xzXh&6O)7o(dR)#Yrgy! zI1yv?xw-$i&-R&QI~jG||7ZLUz7+r0NRP?|fj0^N_YD7E2A0Yg7-#N(woU^tDOemK z5i%#fP8Q%u0nNKizrM%}INS2Vz~SJob!mpf?zpM<50a8F#YOq4=#_N7Hjj6yzN z*ub3rJD8YVWg3b5mi5QjK zT+yG(+pll9JNZAS{q$bOy+a4}_m)Vt7&>G-Lg*I?Rnt$66~xzuZ1)$EE0 zcHy(>0v0$?uddbkpV+rE4l^+y+4-xrZU5}^DzZ8E=&R@H3zQ8(_EJa^;pV5Hb33lu zs%3R858blS1L-k%PumX|4;Fle5pKgD$X2z>X4}=Wx zWv_m7l@p0yG~?zZep{Z`azW~L5>`yIYQGIWjb%&-eEa3G z-{Y6E54LnE$!%nWu+g%%bva;qWq4YlJ4eJ}kIxk**59Inp7Z#Z2vCFjB9pZ-5As30 zj^SkBm3JUp=w%fA<2Kt9)F<)pSuBY@62v&}x5UQ>j?&vX*CmYMi0mAW_utv*|M$KB z?d(av(&}$^F?V+F-xINO8X0%T4Pw!6@n(==#rppf4%j3TP9!Bw(aqEA?P1&RXo^aB z#>B{~zov=#wy6tJt6cqWBMAk6H2t4HZhsh+bXaggUPY4IR^f>8vPg^bPzrnNZ=!@`nx8tT=4M{Ti8786&x|pAfwE) zk`Veie<~l1k8Vp+A@!vaEpos0^hEeboC(QmZ>bP}Zg_}YK0~=j)u=v?F!tPD#J{4> z$@uidvRFzA-j5i=J?yVUusCXn4u563{4Vq}fvBnkK~9iVArM$L+F{xIOYwn|$JuN1 ze5j%=e5+x#G;(@l?uDaI?^?Qx5eRjuN)@iI&(m05M!lr08J%QL5rcVeilaMLOf-|_ zOjC=}DobN2>-`f~*D3NFK7?{gBa#p1*&O@Zohc4Q#?AJRXLun)hfrro%v{CY*K$l_X_@ic{g-XJkdC4E~eB)Brm-oxl-s~M-qU7R8u~!4Dh~6Z->zU5H-F>qYk=XkG%fX30!peMpwEDk=-2u_Hmrik*WBl1$f9S;0Et-zpj1bYa2MMH+4py zARhJ{t8dA*zp{9#zd^rnHv74c)Qs`{w%O`8nWAUr3%-akyXLbO--;(7UOb<9l)Udd zwOZ=TgR9rt+k9g!0%~O+7(=0M6!_OXyx!`kpqQcki_bSWCi1ltqADMqme6Y)_>-=A z=q?NG!Ka)Dq~`(+`5bj6Fi6cK2k z!)xfzOpe`&*_A7@9$qc&#e2*eB++DCqC!gd$Ug@;5XKE*?a63h2)++X3ubT{FW+7 z=eTrIGD``5eJGvSJ{7@ZwLwpoo$_hHiq6z){Hva}jctqmw(_K57*TG$#pqUH;}shg9g(e?>Q-U=?fODBeZ~VZEwe4jNhELh z&!555keOvz3tCy$_ghgAJ!(@q5peb1!iUJJy?BbiksQHDQ3M!9OMYHDdI%yh=F$%gJg_E11|<;ik)OLJQ6 zWPbQf3To-L;<9&&^a4iLu;CgzJGmw|v{`4EcC1)#H7_@NdUX~MCz)I0^((#7`xUU` z+3~zj9&4=2)|^_oS?sUR_$+nR<#Cxs<>pFZi?Fd{&{W?{$$&&{-B%rz6Hl(DoT!aB z`_-6Cf!R*W^qwgn&l#QuC*}iaj6~Lo`E^znCmxewscPVik}Vzhl5x&J;juUk%8S#{qL*=oA9d?Fq=QM?u~JpTAw_sbd3D z1kOJqZSmca_8|yrm-bBW7e7iH$~XV_SKWosS9p&jCW6GxVRyD-{#V9VyVsl`SPulD ze-G^WlWU5o!8c7OL~lvCn*E6Nyu+7fnv&|j8x9z@Qc+E}{J6IL&OdLw#57a3T4NgY zg}T4`zDeUBC+lsM*pS@JP6nbrKG<}YVd`qZ;xN;Vfq0!%3s+%z~AqaxQ4PM zE~_C~-K(ic_Pv+AKU1YWoC?sx z)ej(3a5qcL|J%L&z&P7IS3w>JOePn-wTH=PPouJO3BaWO%G-W$jIgyg*sq@KyhZoa zdZ&ft7+*6p0I74w|3wEyL|)rtzM=HyG@-h*i|`~$xZqz{BQxCh8~yNBcJS(ZgqWi+ zy;%eY#_ZLNfQQ6ih<~FPXhGtHJrldTs>N^p`)x)@V zyq)Nuq~{V7?f2Sc^j{Si`OS?=gWFPEO&&=!`}2~TpYb!zZZS_zf}!Eqoz~vahRCR4H>`2W0UqD8=kW;ePrZk1aE1nZ zl&wPVLotd*{lcEB8~}>?*RY_B@vpZfCP220!~wg3mm5fR1C;XD9NVcMj5^q@j^Cm8 zisIxn;$_hf^MKxw&>I?0pI#RZRXlenZPu3V`U z*%%FL5wbICiLCu3NWbGQtc~^1#k$$r&f1MSR9eA1{BnB;B9X&G{>yO^{N9AtB+%@+ z_m4yp8qiyQKk8s;9M(Zx`TZz^=;Qzwq+|5AlXR+vSnW{dUW zkx072a%+=X`_5Y%EXnv=fK8e5rg z#%l-n$yrV9Ke2ay=ZAH*q!iW2EHjE+(8!7M*C_w~x8dY()S;fs{ic5?Z};C0B0{0Q z9gCj5`0G*qLmgxXUq!yM*KeqTzmKqzXKIdiSGQ?1@wK~uRp%c~ zsA7Y&M*hD3$NzX&mv`tWKJg+xCzF)0vlA3**e-z8)~4{@3i|ER;d18G#%8fluN^TH zDR}BPDuVgj4IzisUfFN&;QEJQ;{e4Gnd0m-C)Uls8S`#m86dJmyGHOY&%PSj3ev@= z1WU@5B!r%xBeiK1-rv0Za7tQE#>wd<@8vf)iH?wbT6PI*)$Q`7pw3&s2Jm~q`cCbN zB(tzAIBn$i>7mm^Y;?HwYMM@) ziO)P$G%^|u@FF=v0%t>v(Bu@b9rqVMA16EhCDZ3=FGXUCwnB;fP|nx5VRA~^TTPvngECHK#YN*`m<5Dq*x)Ij-_;$5d7HzXpt~5@yH-O@8?9-qp*tbG{ z_V^{2+S-~6!i+lDV_7Ur=Wg78f1il$cv=Jh3+CI|>7_D{?!Wp*o_H>?sPqU6{yzTu z{8B?(_QK_b-b(#Sl3D(gYB!RpZ!dzM7E{G{kE_?#*EH3)N{ajVGhgD9r$|%zOdBvO zA64g|TqvderrF4^D=IWRDd9TSoo;DiQGsmk%*CE2ikHDJL&75`XF1ZLDg4`-!%_NU zS%d?!vJkA+ek~_d>ND#w9ki-g8XR0M{Z{HigvzAmWhx`szz<2 zNbL@#8=Go`szrO9F7M=0c1MZhdbnO@O+!bM62g1`Ka{@FzA)`i%bvt(>k50i(-Hnu zr1QB8hsm;zU|$i$#y0X2%&&Djb04uBhY{J&U{$I`=x3kjN1JRuBbgDlACB>R?|zH-f=jtsONjdc|>ES9?QrlZ$w$T(&DgqVULpW4#BLbkZ)6snx*C$Jgm4_ zhsyNQ1)Q`h{*aF@pWW4iJA6!1R6CQ-A!sdG?F~nTp!-5Z+szc%W0`2rJ04D9cN1lB z7pX2gJQVA4U3qV8wY4sz*!DcG*VO_o)`hPZ!_c=cqzsd2bDno4nM}osxDSkM^0&WI zP(n1wDaNWR6wd%;xgRm+wOqwy3aX-Cv*f9ge#(iDXz z363{6UD$dqDoNaGOM8U2q}u$BWv3vg`WEWiZ!tS&w~YU?I-uO91%Bq>w_G2E{n2WR{~Rr*nQIWxwUeXc zRyf`5Il$ z3)A9KKh&f<`Yi(Gd^IfcReG?WTuJE> zR73t@^0EGd{E(k zx9DBkR3!Dtlp^Pdx1{cqt`Bbx=Ub0nqZP3Jl)0RxQ<63!!ixP)ABw(~Pvolqow{Tb zU%IH6qs@aafh`F=TsJb76DSNUYPTrDg-iRVh>=RGzj3VRDZbm1y^_n_+rTk{DKF@2+e#+6aOe#C6N*p@V1CvCFxAdYw$ z8CPp}+-#yy29sz-SPye+=miM^`0&6SqL(^ZojZarw9j_nbfMx)rJjnn{KpzPA4@^b?cbr5uhh*Sy`6UEj7=|Z|X8_skfs!ipLis?5=HL zpImejang8An~Cs%L3gZ|EYRkAgH%3K$F*VKz+8c?ZCx)qypl)X3g+>c1QWxR+S6vE zHK23(#!Yl#GY9K8!AX!D^4jSG57Jrb;pH*^{UC`p<^H~LN=bopTiaIk@qy^u!Im4d zi*qzNI-QwJ4wj!aDnD&9$YI^zym=EYV3@kGWb@++ZTGr zZw8sR-wy8AK7ji6@oN?(S`DpJ;yPhkP!ATBg7`vse9ItA@RVpa*Fk4<{x7CD&y5V# zoxI)wL%xT#dTo-`!pKbR*CwKw?!K=dzQl+Pw2lPEB_<{CyKDQ`#uY1#nts;zc@;gn zMbZym=9q3wN?s>d^4y~>le&i|x3&)zB0Mc69K<|0dH8!?OGykC;qDb8^MmBX&(+A- zBkE~IoV9{@y|gG>v>KEwep2Ec0hDb12o~j>DCJ)p8X1{3Mlw(>e`WG>!arQ>cWI51 zekPYU)&Feih{f&FX48If9}W?n`K3vHQ-hXR7YqLU7d@XmPBoP0%U~x1bgY=pR`v9yxUB0_@r5Got4ftlP8WEcon2Fme8Ni>qXkqFB`6+|A69U_UUZW&SW!vQ zVda~K_)K7XID=WvO!wx*V>t(Gxl^i6hwH_3x|Zi}-lQhtSTSzwW%c=IwOY)1&{`w5 zh?lvSEx*38&U}$k)>tkYv*1%tjO*CRcAU^GUtfx#5^ziJn3R!{ZR>uopT9O$E89mn zOQ~~4YdO42X@Jo|1+3Vkhki__m_#o~T_~|#cuF!Y7z?(qwZLq#vrS1Q_v)?u$?lJj zLgHf&`TtS6pvkI}R`fyUAxrE%@1tLj+An`qnHeZhGYd^`o6t`tZY@-2rCRxPNqmqj zb#ggv%ymaQ!g1n}EW5$_!$Y=&U=*zvucauG%cF>{C+DXss zr&{eO@g=dIq$?f$Y<45VQ^8YzE2^sbL*1irblW?bibLL;>zfnk5ZxXRyzY5?`@FH= z?EtK~ypm7-kpj1Y#~fr=_%DJRZ&Qn-uw#=*4vcQEu-MF-Ojbdnqye{TAz_{Q?18bm z`a1MoYcce~QA6o(6U!D^Hn?X>NT7hD?DF;Czj?^!kYkLtjb_x6c!7biCc+@h!xR+8J%hREVR(1?^8&k1oWjl{B&R9=vOtGACDV7bGV?M^o!9flY z#$`2qayxDbpv1udM>f-wBN?G;S;D|y7v5~dZQ64K{7;wA%YYx$(B z%XE`t*6lL;1sYmPdg`q4rrAoz$ffE8)@s8*j;)>{#H1>%TKlQe-cFU+rgDVE_~|j} zCAJaGqk`K)Cy$ebqKBK5nc@p}%+Lp#sZuOEN{EgSaS2{LeetSD>$Zk&z>YKsfDX5=>QF*Db(cs3fFd8?EweeNBr)pIHVgY@ux zi_rMfPMvuobbE6I1%#kSR>OPgRX&8ms%DddL)DRrhePsE=@;;w^i{z&Lr5JvLGg7tE$D2Az;C!rNDR4v% zy&En=6CEsMLcKmIzGAfKjg&nVHMh)_$Mn=KwWc;rF-z_*I{+{7Ak6s ziTLq-HQ4i$pPq1f;ndx@CB|f9ILjE{H-9+u!IlVjs&y?W#^E=v@=$*war&xthZ5iVhK7Dy_$b9JapLp!FRs zyHhhNEmYz|18mD?A7UBDzxMd6B4P~BHuXI-b$#?+lx;}U#FT^XRDN{UM3_sZdb8JJ zBkyE?vfbMf&tE&txw&vf67M^}&ATUbZ^dQ2rs+;b@&`mq}aVO>V0`E&mnP_9Cmg zREVsv5P9uHK!zkCOP#tRm&f}fbdGZr@6pD+ydtyIRHmCZQpm=iH}>by+&<<@O!8v& z#F%y;ndLi$2kmI_c)!A+Lc|Q8k){^OH(QRwxLi2)NYq;W-5~y(1zT_FjSPB=DD?bl z<)h<=F?lh`hU*4N{bk4H=tVLfaURzUh`7lZ5Pg{+p_6>!VjStHdn|vzlzKDx{Ymh- zA2F`Krj=Na$9wY^gN^nY3@9RUi0Qm(Hb;Z4j?@b*&l;SdYIx%HK~EyoqwpqJ*%?jB z22y^J0gafgr6))>F4l#%cVpl#uS^~4ujTBDIz!;3iLbVu>CJ00EikMP-#VoeOeiZ*DS{Us=EP=pnVp{l;+#jxRVPJdaYj?rhY^F-zNOkzy(t4tLS{~B;>?CesqfQFm{gb_Mn~Z zfOywT%>qQ?YPI3!%e$Sfks|?)Ki^FIC$&|?JsxdZd?h{v)3TJ?2 z8%K9#b`%9p@}jM{qagxjz_B)V^j2kj>S*d1GV3bI4INq=Sq!7CpuCf{lxKg-(<}#5 zr0X3M?J=yutE^n~h=Nopxa$^8fes{Wrr7+bp?*B=CT#&J5u;=!Z-Hw<2m~`2XIsUb zOr4U+&*k#(y8AqYSs+2dS#R~H+I{?#H_%_Jmwj)&Y{b`2j>MHiE+6q3*n9Kp0y2 zV(Y*)hE(hqo!(;4WXxJ`qS+$NrGw{EZJO#Ju{0~FPe@8g(`YohnAULR!8M;F^&VU9 zT3Uyuhla<3t2Oa4IN3A9Q!p>b}*)59S^`q%l<5fB4vg<|E%n#zZ&D%cDH=b5w z@1-xA*>u&dHhbZ9o5$%5BlVej#7p-KoavDC)hWPP=*+Lb9{EUb@xT0YIa82)}3y ztf?d`(7tJQ@v73@Hd>}QPG;o5b~2wuT8&*>MSbC&;M^}f_7ORVQ})Fw?oR>~(Id04 z%#(p(6&ZPAUF=`AuRBm__%$jiDY{(S_x$i?!5k-zReQ-3e-?sgx99~1<|Q5(ln6U$4K)i4e%)x=4 zEm^dUf9;0=?w_oE&I?G~5A0Sn(13!^+Q2%=G$YM-*l(52v71ixsw0357TUQOQ^D_n zH^jT1*o%o*HD8P>P0$E7(g=`z75I5)W4o1@;=P7mX5ERvV?~e9iOGq^>#j$Lh;41S znLcG|6~%q}bn}NHhHVEb2$(l)^M;)7yqlSKmR)c;@^c&@-Je)-!;5tO^Wj1?tE!4Q zT2j>uoL|dnmNq5u%k5C64Q7 zj%u3w1$g86HNn4HRZ%FH=L3|*z@lyhJUAtpLo{lLQD~#n5Zc)KzTQOAN67S8@ud=1 z!qlG@>e=s2GspaeFlE|yyvqCgr)%CG)8w;zi*bgWzY{_{%alJ_^2|CeRxfB0n}PC? zJ3{cvL6ha7W?>olK*mC=xXro@U^P4Y3KroYL(G${@B4*=ekzP8odK3WaKKOn#bix` zW&A_5f^(u-N*d58_nT!$hmVCs<5#)G8te*vC#&rP4WmrPfcJQ`)9=EyApvx%kxX})yIi3CHiJaKF(`9V6) ztNY(H3(oJKEz}<%$5$L*uKMV3!|_6dx7bfftIH*tNCBrO)w2IUIrb-_7>n$pKZ&eAU(9v@+1 zRo%{$j@LO6GCWLOXqtX?j#zP~)Knmw`P3Neaeu}#p7++XiI>?M4LFL6&hROLE>$@1 z9Ih^wEf-iABMy_Qh)$QXy2%ka^*L88bl_Fgg|k9pNM_%7_I$qWd+C5_5yj?So{le< zeN+;SD8jIWSS0j^p-{CrOyO=t>s;A1&4h#sQ9W%8xGP%Q87Mwj@Zseoe=WEZwQOE| zPGaPQI5@|6hI8Ip{uM_vF8kD_NaoU&IIqN&Hr@AEE{zYr_Cf5(SY7!`kHYH6k7*rF zfZdCA9VB7~6I?F1V#p@+PFXi&>*+kND8+nVIvRf^s>h@ zl5vVlA@|V5@4nuh}&0)Au@ z!8(pBefYs+Oh^zwG+++tZh_!8e?9r3d7WjylF zp#Xr)QO%|0GYC>RFoNPuNKQ2Semgj$?iOS4fdHy+zE8j0Y^u1O1ku8Y79o+ZF6;Z( zK$_&LGL_nCE*+yMTZm8ah}OzbIN6BzG&MAQ2K+^>kZ}NkE1bdz4uby!QR_ z>jyW+Ov_h-3VCU81&$F(K~d3D8+iX#{h#D~xhD=tiiwjU z%3wPw*j2Q^&M<=utMIHqjFYtOQ^W&6Az^YHAK#nn5X8}*ThYbm_B}n?ZS9Ij<%rw* z+IrD^@_hk8{D)x#l!Ha>^aR3Ri^-500whLqjKLSwrWhF*O$PH^HXsG|T@-hJ+N}bc z5E%fdg7*NIZx;_VsWWZZW-=5)<0U)q^ z`%|B<9b}WLkVAwN!*G=Fr6Sux@9mj4Ee z5Suo@_ACIUKw{O@cFclgPAENDQ#i3WVr-QE#IxJ2fXUghc?bvHR9#}-fg#bj8qM0_!h zYB?Z=iCv1}} z7p`0VVfg|`Tk}LxV@ipNFQAUBl&w0QcBCT72{q?_Ocp9myPKI=R|(uAg&j2s=}yK% zX$xHptfktSadvU;-iYRQgV4*gFEJynGcE2Th6N2_2r{_}u;mjb6B|=Cy1m(!eqF2@ z@larC`p(#=e=yL*VCMzZ=5n_n=Flo)+)oeq0!F#fS`5Y-NeCP>s6l`LGL8F$iCl`@ z`R>D>Z!*G2d_q{XneJZFnL&+%g-YO#U`l2H@We8j)ljfm=7r)t_fy#$G`Ee0!Yktg z0J&G``Dpxe7K@&i2PCkxm5oYK89`kRmI|ei;@0Fj&$n<1TCODYOs?y--k!CYv@W|p zccin0SRfxTa^FR_!WorHzl}yncQB@EN)vt3O;{Y9PCNKCC_qiiK2ny3|1EfyM!oEB z_gd#4TT9}>&9{Gl5o)@AL#DcTF}c;O$?A5VbBmsZMtQ9%K3PL#;!}($lG^UkZEYT z{%Qy(0HfG&eqRp>{`Kfplg^wMRQcww&~|Wx%3IC-Dk-X0gM=1e2ZEnLuv5=<*Xm)) zR*iI|uH>1!;gU(2>14m7AT%&)!cfDY-n{?7{>cvUn6!I06iTsPrt?a@_)SN|y;=)H zY3hJ5hdh)tpO&3fOk{Z#8dDjAOs|Xlve{TYhsp5^v;xkoeXuFi?RyLIrBnNV&WaBi zkNsYS4-ote$GmASfSt*bbyk5$c&Sk!M!h*XG06nKv_2`4UP+zi!{XxXI-Xk_Gx6qN zbQ@H!as@9!XyRqQB?h0ft!}>J4@X>xV^1+_WG3(nV-yfkf^v0yrW2!}q;=}JEYLOc z`CUadmm^Qq^&x%$y4usFa?|TP+&z}2BU($qnuty3s|yWmm>{Ov6kuqx&aimeFWXSr~> z5t6~M=mctef)`*qjOm;u{8ngk!a3jEbe#$=M6fA{ARjd&g&DLV`?kYZcJvj9w>&P5 z5e{t5ms_T=x-kYzWj*r}Z|>vfjnv&~a;??zcd$`u@b9RXLpz}dH5}jWEG5e!1!li# z$g<*1MC3Yx*@Z6T_FUGTffP`c)Y0v;b>QD_=?**lZ363`5hJSjD>M@%9}qF*bGkD| zkeFn!*?pA!6sR~-XRR1m%P{3hFcQ12hg3ed38$EKwF})&Pk?Cf7OK zDv}8gHv!}jDd<3IT|FPzW3F1;$HKpG9z_%iIA?Hj7{CXBBO^-8tNieT(H6^a$P3GD zq1s$4K{Q}xyvqNPl!hp=VrIj%zJ%6ykq~z>C0W;{w^rrtr4rYLv}nuiyg*t$BW`1k zH%lw$tizY zH{O%DSwln;XSt<1u;G-u?(zxhJy4@ZVA0&JPwh|jSvoVkcp<@PkMY~#5=^!w2E5>} zzdQ7D2zF4%Px~Jf4*-B^>WzB7m0toYXxIj3edE5Uf+8+QVALR4XOMcb@C0!*Pb+9L z09a-SCWlsssxP7;S&BNs6~ew#C-yr7h!N)|o zgfGr7eTIs81p5cvP6~t~Q04W*6t#`9^=l%r29#|k+lysX?Ld{o*S4<@Knp@L_AbX8 zX!01K<~??5&&5>TwnhX2 zS`)t%$nj9nAG}A-X~~t%`kGp!7f6@XplPF+e{6oRy2N_)0cK6)tu5+Gn97Z@?~j@; zX8z~V6R1`ImV2Uw*xfkRee0PO{wm&jqMu>eqE8JFgn}O?!ElSk6&ye&`;kX2fY&U4 zB5eHu{@RI``QPj39qvq0qUKdLs)T63cNjzf4=&C|qGY#}7$jP6hH!Qw_)$!X4Z6-U zWqPhvpL-J9fVqO$;~}9guX^5lT~!K(Kl5a!*o#pz?GUaQT+ywtjkV08p8oLEl7Wtn zhhy-k<3N={;(H?S;DP-mkc5*<(CRZx%x=y(+AxUXDK!N9!)w9A*1Q6e6LrY%sDfU5hq))N=AEoOL#-3?;D>JMj(?t6M*9C3b7 zDg|3-wY9bV>^y5`2H}-L*EUn)3I3XSI~(KP-g;1f?VC`ZrNm}J~ z5c>trd=DlRh+kF=yQR@0f_JAV*C>oW%u*6!@R@+dyW{nMHp+XeF{SCvIY==PIN?7~ zKW6b%zspT0&n0?Glh;N}TofM~9%;%K9U4CRRa##CXXZdW25G}NQn}kWvoEUoR-3{? zZCi(`=L>^kf`o4`ogA_%s+kl=FPoPd6IbIPp5K5jkwwF`+b=Vhjs|n{lB0m*4)8-ZhP}-$p=d z3U-ZtVv5t1w_(CS%aH;1;6_{5_mu@lWbntq6Jb8a$g+*X_Ln{(wd#&147Xy3^4mb7=-&+0EY8(D1A5H>L z!)@3}US0fN|3K4UIrj&owaqEoO%lRfRXeCSbx<}{%0u%?zx+v}V891%xm&~`9VbKX zkYypUUI>%YhuV-UT`Rak>cFrp#lhN;Q!H>dRh!qtQMni^KHbgC-tZE0(+XlZBW_E- zdZ9kXtG_nn=ZqJ<8f?OXvfOUsLp7WR<7jIEd6n<*YF=r5ZAk2?*O%}5uFQ2?aeE>K zcc{;U+Be`3D+R$HZzTGJMq4c=_R?!%$C6B)GE?rscj98)mY8l3B0EC4`>>eD0-n-$ zk>V_i>BpQ4NHd#1i`d;@D1T)ME<9DesBXfCOEEm_!L@T18s|!iIO_R5rt<=4MNGMo z+81L+I7oL(&E33AXL>8{uAjM-DJDCluK8q`m6fl~*0P?(mP0(o8KbGHa>j!plR{^iVcw zHY(qG--OV(lN1y@2IU5nWHGp-=ml z&D%Je=2wrg3%+e!JU`YqzY0J*R~gQ_y7=v|?|1TF`x-THM$lIM#D8K@)Pqh%5Hw$E zl6_Zz)`Wmjmuy4mLLhLNLvh0gmeR zKskrbPdFpybAmOsNWxIElfutCo-V?JzsqgR6T$s$`?Tv^)9Sa0k=}#h5b`M62}j36 z1B+iq@!i@3Y~ke%)|q0hBqV(YS9(evvXFblN=Y@EAvC{N(@BQ(IdMcRj;Wa?2gRsD zd>i6Euu-=VN~_tv{R=>$`EV0zz#ZROaf$>D*%*ISwAc)Z>r5jS$=gb?Jm0|Hp=Rc=vIrs|aVUG zQC)KPmS{b}mUTwQGKJ((V^T;&=kP2YKg4vHNW_>%uDo(r45dn-GVm8{J|$G5%dKYEX*io*6TlY%lbuX1044 zP-&^W$~b^@#{88!uh-rHocX8n?euh@65MRb4VGu3R!9AP`MxA z=O&B&BBVR1(Ds#P>>rJ|^r6ep<)h#;N=&28V`+ml_DRV$Vy*~a=aivz%f0616Y^)+ z9d7y)G%291P3%>z3Woa%%eDnprY3mg&=&ax8(+8C?bo+Pw4!2Oy-qOEPeQtrpvRS0 zFln`^97#0EM)vVOqvmh9gj&BhC#eG2&yT>D&Os}P+x;dKfpWqZR~EV+79Zo9r`@-0 z9S~MpnZBkzwVDGFL3qAVXs^BLuy2~B<7g|V>&Swdz3%$vQd=MW$piOtgQ02%oi=D7 z2ZA0>L8C7Mgd;isX)fJU3gHzQ+!p9#@(U2E9fG($B7EmaSLmJ1H ziz|bMnv0MGcz%D#3xyDo!<%> z(Y>@7q>BVfck(J`Dk{)v1s%^;G!Sny{OF@mv*>EK3ZwEJ!7G&BwJ7l#I}70iGy>=^ z^2M7;$|ThqVgr$c7-FLgBn9sDQr{8GBE??W9MhIGnE z!s^|zj+G##n#n6q-WL3UKBrmEb(K%zDk_nd1X95jZ_6yV&0AT+&z>Er)q2v_7=Ip8 zY9oZfrMz=3-xtdvj@z8BkWeW&If-pO=xosTd)>;&8z~=t-eVW}`v-`%gZO z8KgB@0d12ps(l`w5C|>RK4piP`&(7o^OzbaJk)1-b_VHgGf6=M_j9kwV| z5Ap%Hb|t_DN}cNm*I0P?Rl)OL(L_T~zufb+_1o~2{^p(jqc5}0_j%2nFx%`^cu8VJ z_o~q#$BcAh?)k=#aDCai!tX~LM{kh>V5mrgfNk#v1V|Zkh3;@Fm#;l_9Qd>zIy=C0 zsu!*X5x-O;%QA1J71HO*!rkr!wM5!Fk~3o5g`Bis?XYojD)~9mwlR! z{V^-&j=&cHyP8c;XFFo|jS1v!K3BrFHY%0i*`N)|--x{(%+xt4$OD+5fewO)=1TS* zHuzu0?MqV7LEntQ|FmwX2=funU)2!DRLG1NnwsW6R0Ut;deC94Doid?Xr5@Ed224 z+v$@cZx(it?oojHMG3m}?~sDr?m_o2m{psGa0sO*cO1PC?h6W<3nl)iK@&1W?)j+u zNS8}Af7`xwl@6X;NQbL-v32c`nUi~3yiUwg33vk93Lc`upG^ouS}|&yOnj`}wG;&2 zX8(C~AobpjHZ9!rJ%3Q%jfz1v0KwTw<%D(LJ3x-wxw>58YWq3(5kB8(OsLjD=>6Iu z0Z+WU1JPg1J;lyiP~qL&Gh9hfg{rJYX*EE44gEfIAc8+WW z7>Xp72>YR|eka-V6B-IZE1t^Q(Gzi1clJGcrwbY5`K4 zg4`LEsgU8wogq*ti$0#&{?aP+USF?;%OuqtAS9atxU4Zr!L08p9|hhio^k_cs#c%O zpSI~e+t0e@C9L6GSSs^ViRAAfE4LQO!%@ypI2gF}CjY3mF@{uwr=RjsFw9I(Aw0Ti z6#;cg9lUNJpO^L!u>rPsQ*xCa10^qj1(RW|1$0?_H0NRAV^xR#C89&53J{8_z%q+# zhYE{$MO>AjNN_vA4G>w2R_HiO1&{@)P(b%9^^XE!`-lwMHsE8))L>~R#K9^VDi{;) z(_Z&ny_7uo=Ai$QnLCZo0oOOxZ&{QT|L~#Tw+$M=Y!K+IWOc~RFk9W;x%IBarbh(H z+?8}OHk5pH zq#oALR#HpV5U;>jxLi2AL*^ox01d2`REtZtTlIzBu_#Q6ZuQVquj1t#z0B5BO>`Rc zbVSNG<04%KUd0IYPAOnYOQSK)Q4$U`71)$43B%2bF;=8suFVEKsq4EwALIk0LJ$uG zKcpS-QbyP~F`OLoB6@i>59**Qi!I@%E25l8wWI^5L==vw3UrQU)HNxy4uAI0TF{9M z>9_xS5!!59LT9@PxreCK_~e#*BYfr{`1nd5#Baa4ZC}jH^z6Z(Eyp#^D=K+KGymvgE_%%e zErU`U0yM)=+xnXLRDdDfcPm3H(H0H~jci&aW+%%$Nat2HvN;MyRT0+s0G3vEIrOi- zmLEX=&B&v}M^&H(4-J&CxFP}YBFprmJBOhoqKP}wFS(x0W2PIj+}Vq7Kfhk@yBRjE z1UP3i?lO+SZ3H8NrM1r3so=e$)I`FjofCA{8E`FR35UR3@nW4iG&5vsmn1>M3i$qU z*AL6oyjWjml_8)Nhd-WO$Rd^1v+P!}y%d&=2g&IK-O6Ro01Y2%c>Db#SposqX{X#=m^_-h| zbgf&JJNZXma`l8z5HRt5`ezN@&*#S8$#(93-D-V{7DaUCzdR*}48;pW`cd=!*HFZf zm6>o>yKMgH%f z1gmWkP{s3i5}G7XS`!yj_le$zwZVJHKviYKZO#8PSE7;L;ep@BcO1!-pq9G#X{h=* zWV!0^t3}n3)ty|wkL-WTT<4O1uQz_aS`sDb7W(nb7kk7Q_zv=p> znR`&$bShtRK)WvEqr}F54@mGYJY&z0MG5rJqM~6z_J1QX^zUW9zc1RR?yIzJD}VRP*Hi zd7b^%cgh_?X#ZhD_dKgdB71arW%`hN`|)`FCJP?sOKtC7Dxl~yP$cQR`~Q*hou~n~ zKL3SOF)J%Rk&T*};m+LEpV!VQz}s$1_UxKJnl~i~+{=C&+9Z{0*>wUMbt|GT{|v&! z&>V%6`u$t-s-U#v#|ZC<@41**1x5e(v8KXR@2>dWTgj-Z642Z!zp!f$y@W&*30J@# zCJ=oQ?O^)2_saPmM&ZcC>0wA<(7`_KOsZ8s$S#kjo0RvH^O z)`?lP05$L3>;2_xKL5Vt$FQG&T0eUx8aIOxQ7gqp2C388OfJ?M?bCd+o3|Y7mShU$ zg$rd?j@Qd_-|>kyO)v@kO*Kk%YJBd~n)m%{dMGxT-8%e6cE5FO>K+B2`1qQ|o3MB{ zUFSGqQ>4$zyP4H!4;S158UOu~=Qp|0s6pKuM`8_k>%lqLy!5lyo?8tpQELB|3v7HF zTfBQ5FJYh2dlz?20dE7?3?qE+=rz^q4#GJ04ps?vy1B=^=T2sjwbGtZ1s4;PRX#r< z+N8KkoHu?SMPolI6GieZZa1OG&c1egp7uM9uv-sT*lr2&YoD~+Z+(h#&$vv%sQinG z4Dl!(&{*5X4ennB2w<_9^XftTCA!pY@t(`RZ_|mta3jy6-eq`RHuj?Ewjb4?G(&g4 zmP3QOiUr=Xmqo#_?KP<3|1((=_QXO31T+ojhtK>oxOYj>6od<3?O3Q=>I3P?BFuTx zs;*ayH-kiXYnHcz<5+WReKJXT`Owz*vBDsw)vy?*No#TMHZYM zN$%5px_dYry6SXfO*re=()4qpW|O-O1Zdc9`cQWW-|o_QuzKUnf0+}}lXOv~dYh>b}-)yMriM)^BbDq+5~t+x^;NL6l$z_ROt> z;A{eS-`_43qo_iYDX=jA@i~0Y+fJsTEH`=xyZOZEg4v5#Qf zck3w6ew}NN%36$loFyDR3&q2=o7W>>&brgi1@XMnjdg>2ImkjSU7uw;-9;{PlqiQn89|@H+GBS_o-u?vd`J;?!TwCgyHh- zvxw!|V`(qzr_A8UfI<6q>yngt8gNKkE$x`fL1quKw%|$kcfP&y@tSfB%rgFm#RRBR zNYc}t%A8cJxX%cZTu|1v(#;=Szyv7;NfIgeYgT&^s+wW`2ofja`je2jQllN)hoz?r zA~)8kb9ZqTRD2#dKK|tKi)ACiZ9+0Se=emA4jx~;N^*deX2y~0HBa;IAHYcsyXR|m zp4oJ5Igp-}l{MrQ}G|(p`|XiofcmTNy*Fm{M_Xi~FXe{n8qhZ(L_w=<+sIE5^d;PHYzi88vt0D%SO^ zo=Wg+#gLst@o`|zt*~?yzGIP5YrbQVXZvQ_;#Jz6wtMfC43l94Ts5Lk*W4nGlKGJe zJGZ@|6mo(8Y{z^Z{ycgy#cAHVnPkoHv2)57*1STgWs-}!Iqr8f4ST6XYJ52&ts4$u zC2OAL*nL)&;HJ8XzPY)0#z*wJd&c1V^K@={iDRbW=n}y*b?L2a^hIt`aU(%w!Fi6kChaYYj zJhlGua&EU_+8@l!8beRFVE&x<5gjn$H^iR z1?bcBO$-luV;D0%eTMGT=MYwz4xiOq%@M0IwPF!KrStG;QJ)l^-2VLM(X`Pbi`Lio zHkNaStXcyfYZ@=k#oRTO?jg97uP_9y9ofy3yi9$Mtt|}Jx?Pv4Uo~U1j-0=p;TfN? zBvB({=y$?Mm0L4*g$ja?!oZw=W;!a*7nzeCd!}kzm~KrKFFFp}A1L^YW%_US_8A@&=!})!J#ATC|gp zEp6P9%zz{3;X@g?^q4Jy(beSRA4>SnL4*q&mZ4(_A9%8 zi&$UjsWXA}?$)#YEUmpBtF%1qr%7ifC__HV7K+!%_#BLv3@Y&)`FN!@=Gs=Z16>T9zcJt+sIV+Szel z%H=&0)E51PdbQPI+>7`N*sBL=H@E&5XKw)&&iU8+|L=3Hap^ET^X$Fvx~}`$ z`^nTK#@sVqd8suoQXQ1)S+Q`pFfAnF{Oh!O*)N=r_b;C^usHD0%ocpq?JDk2#9^YwB-&A;0z4b?q6~clX|IT)U>DYU-+$wfeO* zp#RPFln=V9-YRLgH_fkEDLaRW%+57Uxgx-XgUeSjZcv8%13x!r{eEssOGrF5rJy@5 zW1e0~EW7PeVOCag|LDez0+_dgQ|C2vMju~0PgFlo@Y!EFU#!h?NNIiS(cbo|xS)W6 z8LAu488sJ~@8qSMibUOxE*=twsBflst;?hRyTxnbjVJVZ_g?f1wBK(eCdwTx*I_bG z&d%0aSjN)ZczW>bK9yn zEtPlUc=3QuSzZpqSv9QORZ8NjYvQGz8(-G1HiZVKTA@^q_v;PCD@WKO55}4fqy4xi zARyIKTu1xdZNgH3Ytr0Lcq}MCpBnHCYjo}M`DOOe;CyAs?M!bhv)wqUrB+t`mX9h9 zO1DUR90#84-QS`xY8H4;OiK#^yK}mpgC}Z(lpTg;tA5 zfxQ2EveR3SOTHtPtEeF;a3?!xc~I;3Tpws*T1Q@JzGrL2fqir^U-{VBiu|e3u%G|f z2@cq~AaR{fp_=nl_Bn}KOYvXO`DgXf#wZSzS@N%%^5kb^nwlFO`v^}ETG}-X zxCy}OiDX&;QU6{sB~n`8KUx5I=Mp1elV@OPHvhhsCFI%vyeR>`GPvvhzn=9~N6Lg< zZ~k{s<$kPi=;x1JMvt7Kyvx25Un-Ho1C+ih?ixKHsulXMKg`VkeTNb-T>IHyc=6}x za!2}ncI52Fo|6m3*cLQLj((e}i-dN+5x<~ed3ySTV_*Ad(s z`_Gj9GfhAe?YfMwAdHHLq>5cD^Ad1bBH*%JPz#x6AZGvd`}_yLx1(+ze3!HfVf8LF z#jJZW`)pNGP1Z9Da45)lO+whDKu{zy@Vu>GJPaJDE}{) z5cE6mOQe7E??wCXwEnx8ON5L6Yv%u7Kcf4;RIS6r%JJi=m{=!gwSx*jOU1&!fNcEb zX1>LR^{hu5Lw?#vA?yGC;O84;9ipPA#7~_++RcpFIHHdF@5Xv&BM0*zPF2e_9FCM-0${n zvlpiMf93oCyi+xxbJ!fd5EZ-xY=ab2wM;Qf|kUE=QEj~aRRD<|z*lG!UB#%|6PQpKJeRG-;b?a8%-~rPM&0HNx8#>LWbP^ zmJcZWu&LiU#7h*AbpGaNcdaDq7eBje)x9BVBK+*`H({xs?pmr=SgJ$6&%rt}2fK{5 z`tLMszRRlNncutpVGCk9Tz&VaB9zENe^Q9Me54vOn?D%y5#3*WL^!5#5?FDj=QyF~`EB8tQ@axu3=JCCmRB`D?ZtT{c?V3bNOXKSxhuuym{k%;bI_ zSXr#MVc!AY)wchmLhg4D+{Mx+D^_#7xiAgAC5d7#n@T75Pf%VUfAW7NMQd~1AZ`km zjUtP`sDJH~`QJa?RX1L;5g-Yja@N{z;X173wd~n-;Bbl~J@Y}c%fH|F`aDpzf~+|k zxAoIQX{gjZJa`($<-=K2ub1ZBWDw7b2HZR=2_E z7dR(&bS+YHoyNeQCHb1He~5Ig$I>^`(bWO`^Lke8h-|uj(&ek696@LdYdQN>}c7f-ZNS* zwJMUgtgP(qxA{)*87zvl23@eW2CH+MV<8d~bzAF-Fov)xoHxh$*SBuRh)Q!RFw+lM z6{yak@!5I!Ds(N|&fdOibDoPlE@Cs*tM7j<59^JteMpXjhua5pNeExn zD4cp7DKPmGUL&pxpWGHdQv`iLZ@!+w=^epX2yxy%PH$Kr5|~v&dfaOqF>lzT>k=^C zi9KvscZ^unTH!`9mK==>E^}ZDtY`D#f5W58D*xs}(BfEqU2mQtvgluI(DTR1**q`J zm5ymsH10!8t&I~ZCUy1?YDmhqz9_Q~Rg^B$B0gJhT(42X>T&xyv5FY`mW|jUKV(-! zRWR1AjSmrXU=8$Vb(eH^SEF)^M!rCLbM6S%c5S!OUZTA7V@TD$e}p4vzIs&z94bnI#g?R|X=+uJnb<+i6tD~dau zHWiB@`GytWCZcT_c`GhTd@E}ao9qxJbQKIc&b`s*34Bc5FY;}@AX5v&B(wI(cySxQ zb9#AE%3(tH@L{Di6@!hH?NJKUT69r)OG&t90WJ`%sc7!FrRZ`KZ|#WxjvQ`zWhL`j zo*|ZX@80U2EO~!cajER`8LWLgngLhgV8iUt6!AgJYq=+YZKEx|u6nC+QvQ}|)p(qc7XWE?rl$0z(wUHyma)e82w3-S>>p+USPx2^Bw z5w!`SJZ5WlLqqbXP8qbs$d1lrnBKVdB{^Clz%W!wQhNPc=$F-j>ZBJH#-%^PxW>RW z&P&uqTa`~g5hbm$3&>=rn5s5KIVldhjamW5W3%B+mO1Z4L*w8oC=;``5p z$dJA!d)Y*AYabRc9i|l-ax`svyL?k};iF-m(YO4QwgT=esjiy?E+NyM#GtWIne)Yc z$y@gxyljyo<_nQngqa6DmuvID>ls^6-fng}KHE8?{g$>tOg52~bwLN1)@ylfytZ4( zSqg1Em%`aX*h551+vxYKtghB#)LVn)dCK^0%Eo*0Jl7lMn6jKlo?-*4NwYMc8TcvO@_*;z|3gxpkqfV^d*=n7)8*(bCe@xS&J-K;Yz{Ifv??qlG zcV=6a+4cLd+o-Tg24-}rF((M`O&l%V#F6`L^}@osZMS;hE9E_L4)t}i()Kr1&c9AJ z`dN;f30&R2Yj8h+;iGup{e$17q%uZ-gtuOhsAH5~45Sgcu%8D41W(zINxMGd>R=C? z+u3xC)8;%C;x^H?Ra`bz>)C4!>Lj5M>5aXM&9)@3+fjmi*Bt`_0?657=%Kpkvm;;x z64aLe5Qs9w4a&-+@e;Vmqdo+6l-4Z0a7D6OMx{5E^jxk?AO-K1AN^=%u|aKv6KSX5 zFE9;7`#9{D2`Rb(Thj-Q@Vtg*=XS-y=SIt>?&7mO=@1A_^ouCD)K*T5DcahiB)1l} zPETs7_vm?Odv1-T)WS4uxes}Ri;a3<(WgoCSQ2~H*7(uUSIW|??6M&@WAZ&GV;szp zaEdsg1a7U{Z{I>y6{&P4J$h_3$cMFLaB0@bJF}{Id<}2o*Zb6^YUqe*VeKO>JZpI?&ohf4_Jpw4EViE zNpaE8quJctoMo*Z3lUp<%%(%9u4Cr~z8XC%ZBt3Wl@hwqh7r2Op-?{#T%~JKo|@LA zos1>MFJ{^59%_}To^WtLYnSDlYDm+OR|nvP6lJz`Vth#BiwSJHhg+pL4YD^i@;;pL zUM*l6HI+f1q!#<3Yu6%%3M{E|vd?y?YXAJSIw&EOWB_-$BaU4~(o?AS3I%*7qE69! zDYm#w_@`P$upMxuNHG5&xtF2VyOgnk->Kp&9^Ux4HfLJRP)#E2oz)?+T8%fvt&Py^ za5)bV+DcdZ2aY5q#%5`>A3YPh^1RnDlzlWk!$ysiY#!$}@wBI;if+C`J}2ZcwK%7X z<~sZ+q>@Nlb{!2&Im%%ux=Hk@{xJ8KrSZ2gW4m7c_-t)bGC|jU8Z%p{B>dE(i1AF^ z8bS2Oi=*A>t?e6?m0o;?b;L2>z0yY@J;$CnIcquc8C$D8%r6xpxm2*&h-zurzVZ|@ zn#kZqiPgTzuWPF%J5oJ8R~#lJkA$CLJ66x?VGnMt`*S4s@1O7{Ek_#=hiF16cuFOE z%FIF(Jq>Pb{W#O}gU6@3{VI(V>*ly2l===*QWSyinkQ`x#;y{ZGJJ7p$nDLLH7UnhN|2swN>Lyb`P?Mys_&t?fq z7f;Vr1una|)EIR1Opr#g)%BPMpQjgh`q22P)CR)*SWja3-HxjfJRKn&Xvaj6eTg^E z{&D{Li&Kw$Q*WwXyZ-5s?^)G-FHPRlCp|vV;o*P!Nmv|_#wU*WeNHafnDZpIRZDZ$ zRmLOEYtksPsYR!?p#J&h$7u(4hg-LAcf7l7Yq>gCs}L)~!EwFDUr{xjv(jmGjw7Yz zxqr`dCMAo((uiW4p|LhepDjBbMJYms&CoNuTc{G7+ElmYs*3u5U|)SMs4F8D>|OTu z>1ONfIY>jJ}s8n^GMrQ$_ex2IxQ3aLRimS2IJT$#<07#i9?_tNtP9 z_?LvT^rQyTylTp}wmfO+=n`{t?~i{SNtv1&5ceTHv%yw{PmE2pY^#loe2NmBeoZ;s zjD;smyuaKKEpl5=FYZ}LRhED$Pcr(f%jYMW2M;zRM4-HRYTO?$ySls2EY{0s+<0EE z3X}HKZ~r+_(NNrQWe%5mwk3X;ePex+rQC5kYGh1VS(z{zbX29>kxy#fh}M5IFjVnw zPj*d_=lX_V=#uIZ0AGo`~&I5;?FaYG*BZc7!;^WuqAOx^`+;;&x3NX^#ux7;D&X^*`c zm{`VEdZ1b*m-7t_45;ea+)h`!ub5?&J7uKae7SXynp#CgCAcM~EVVh>Www#GT0p1p z5EzR>te;s=w($~?SWw3MH{>Eijt>Yr%&Hilw6D) zT83h^D|w9KSis%cZYq_G?xX3-DftKKTTGpA>*!Q?Z_dAy-tl}3<+t_m{ff74sbQ-O z2|XywR{|;3L)$gZSnth;LlOt!h83*`s4r&FUx-w9m{cf4r@VM^DI;Waxi#FP{X=~1 z(5J2KZNdAO)Co8^c*{;OomAC1e>> z?qX|AcaQR5LzY49!8EyWEk=Rl>iv|i$`o{&g3*SAnP#mD*XQCcHgWpfrq1IHuRG@Y zYhP|`#WsSPb_R7YeFvXtJL%lJmv1w) zu~|e|TP)bvCSKjZq2nEY1h~11C$NYrQuAHFNLl zMTfM$?L={FcPqz=zgA6A;CRigeT9{kX87892v+_y@ohb*oQ@bV`3qI8G2#RYsclDP z)oh&>9BD`W?p>QA3sscUjEdTPKdmY_K!IUcSeVoIk4nw)a0a<&o{kG{P$0&#E7b*4 z?&Jj!^6R-uV__C?L8bMjq&e>`SvKx2B6i0>jZI);pZ}GvP-%;yqQa7r2(9AGl&@c% z(^1t?_TvX{F0Xz0avCtL+Essr4ot>`3*AjQx%Tg$jux4=^1Hbw6No*9Nr{PP`R!Gr zM({9PvmaljEjkj_%6sNr@WVaNXsf{;{%|I~>LcK>n$6JzJ9@SdY6`tJr3*Hi-X;)w z4QuD)M8L-}^=cVvmn+?!?gr5*reAs(;20Vj7>Mz}H+M?loA@Z#;w4-(k8*k@5{H?L zm0LTo_yeJ=QpRe?7U!wkk9i3%Cv%9)EmEDR*Ihzm*XvTFs`0-WlPL!bR zQBKPI|9ah?Jz~rU7nxy+LuH0rGWE*r#jLoSH{%JtT z!W5LHojKLGu22~p{*28vS4&K~qDqb)#&Pm%tVGI0Yka0JnUB}fw^Id+N(sZN{?vDV z%*PsgKNnYhf5i<`Vk?Vgi+}aX>Nr^rB#*1h$)>a2QZxNdr8dLC-9u=iz?>w5`QoS$ z65U-&UUES26<#T2e{6WvrTZPqT7s$pIOJ^IWg3vkt^RKbrXT@kZ1BA#D@2(g)HtPwTspoaIMY z8kaYjn$^F5pXd4UcG*e~m%Fa60hrL`)zy0uJlvR4yE{S_UGn5KQP`rXj}H^HimfWe zoh(dTe8%d1%I^qWLg2oLGqO-Y?06E<` z$r$3b@aZ^^s|C|7BV%J(U_6-%3-_s5t*TCV^%s`8FV^xv#_XD@`X^I_{RNv`4u`JL zJY?4@O3%6KuV%5n^wy$%R4&@(c!o|{jIdRtsa;7`nL~B6$|rdvJ>E*e%TPsJ%s`IV zW+H~sU5K<&USoPeszP5e@u12-_T;#Xx3B65euqHX%$b(iIcKdV<1q1|YJ2qzdgJlt zV3~vBWQ%S~{s?}4fOwAI{#9Rf*?y{YbQ-(Sldi6=+q9%AJN8?%-PS@Gve%xNZMiO^ zqcq@PV)MFSrGr#d{7eHSc*UBb+arv|jc?lei{dRdS8cn{F8+=+*d4mVhdN zu9>8W@~O2&Cy2*6cVG-qiewg9$`q9z-EqP8?daJwzLAO&wF?>10NW{Ym^3J|9%!3c z5aG{BiAzt|-mLD45j)Di$#^ZVnRV{GyF)$oI5Wyt&p znca19nri!!>Am9}W73@O)Bcb2-N+F3*OdObXMytG`zz<58q>+r5o?^$*4ADk;`9@! z>Um(#n=YDKOi+f^n@erWpmZSnbaSjkJC2P0MW0UTgX@+(QRK7~bWIuWud-Xmwbs{b zhjUU1F-HrS1~xD6Srvzr)nCMvT3WhBKBJocst3|xX&RRi`D~A^z~DAo7hShRAmn)r z!)nb;r$jS`FwD0F2h$!olG;~*Z6j@CGt4{tshh{a#(1k-wISkB)~ja=4&UhyyYh6& zeB^Ulf1cq>i*C=)?}s7mw+)sZ9UnI)iIhNhJ? z{PCS3@$%yti{3Uj3HxHpo}1T$=meSBPd_d^&B^3b z8s94rZ|A7b3!C4Qe|qpO_NjhnvTnIMAz9bqkK%y9K-Jl9UdYwt@wRZWu5?wlMl81V zPV7kuQIBrX7i#%G*r{7}Avo7;Jf%=)iDN20r*Sc7V|Cu_IH^GP;U9-*y3)!{s;Q4-0{*xo^;shT87@Ek)xErxUtfiWJ2Ilw<&$kWJJ3> znbVeMXxjACj$WOs(ZwEOJ&*EU55ZwW<(DHh3#!^zrX6%UTBC&OBwQfIHsQpiBqh7@ z3`!oHZN@V><4QvebkXj?<^ptq1mOjD?QTbUl8& zY}Onl24JZ@Nxqxh@5MT#!|5O22-B=R#q(q=;*J+;Hp@KM%k{wo790PPM{nMc#X7s% zl%f)D2(8r8H#X0xXCIeI(Mf|*_~98!v)x5$d14e#o_q)eU%%B{!)vCW;js)iSe7Ce zJ`st5LuKFa#C~eQ-c$#Grax3)KQJT4KN=+)2GwLXVYcKgMm?)PwcLqILQv$FeHpP8 zR3vs^-E?GRb(m4mbmrW&T?T8YLJP5b-^a^ZgB92HOJxKUNPj-dw*Hq1X#APvtC zn@zU-vG3H%m!qL#f-Zo1sjkj3iI5b?Bq(;TgU@l*lV2r0TU9f~k96 zEpwN+y4n%OA+R!)aDAwYfji+}jyIrQhlP!{4W3bq6UbCgT}ZvUe99r$aej3C z^)R-AKW=ci>rZ{dx}ZqlSRrh=%Hl$2pt!*{w~CpX1h+qQ5lkYCf4 z;dr{@qesIja~78;Y1D7te0Q}HKw{dZhkq4pkhXo!pFG+AzU)_{^Tg&~@W9HC#y6== zPm0(w;*Ztx1m+s``27TrY(nPW|SQXBlJ6G;Kv>3nslKqSml%WOgU>GXNx9!lIS6A~KCim3TD&C3i zF5W0}ooKqw!O8g+6KmJZ&cGXY=hm(6=}!6>{(la;lib23)02tpu=A4j26DILACe!r zk-!o~CbvP_jBmCek-VYse#2D0hrfGq%#><2R9dU++%klS+wk&uN5>Zb&S8=#!>s+0 zf*AP;IqedhQYdS}tEi}rOO=N8CX7%AM3-N2Rz*8=Ao0C1A}9Je6^pps<;!K5EN#o^ z$x49Th(W3OOuS7#NLgqtt7oL}#+#S^?ER{D4VVkWIwwrc)WXQoavzzN%s2@b1=L7N%MzSj{EDSB>6DSlMZ2EuP%y~<>jx-ktSbKfS=Tf6%#wn#WM zIbS4zD+Bak!7;q8fh0gV`*x(?xISbXDG7sJDrCD?foP$cg^V5U?@ti9K2YISqS;(i zbJe{@Q%X3?{(JiyD$&3S9=nfm*smm2<`pi$V? z@M~*-TEpo*1I6?;`sLMn^xYadgaE9 zV~yo&K)8$ob;VB=&nUzQWRjCl=4I6T$j?Uov%Ls52`HZ9%i4<+9C!dzvyT2j{@SMfxCznn1 z?LWp|kP5weRX~_5Zn&E5BO?%N?h|h#nw^~}A?{!@Ot~&Jxstnoq^+osEHbE-wP-tW z4=4=*$%&@7K{Fl3kvBqOk|AnMuTM&xhpM8_4ji~$ptU0N)vH(JGk2o8I+$!JzrG-i zxMMw+6ATRTQ5b|Un(xO^Y5D*G$ieY;M;8be{__A{W|^+|Axv6-^-ikhP-myIF1i?M zvd$Dk+&t5szSq;y0epWE?oUzu(g(Lc1h5M~dIQeHMOC z;Vs)QyJqzcoI~RDU%sY$$f=nTyP>LwauGjj^FmdlT*xtm*&Bh0`zX|+p5|n}jETvN z_ZfbV^6pEs8Pb{_azPcXo#gv|i-@mh=yn)C_@H5{%wbY669})?bIa_TaQmw9(uN4_ z$(HKj;bA`A!7vvPeEX!J;7#pf&m_}$mSiEzU>D~%iBKMyK`qHBvAVa&N>dT0`e9h54n0#Y=W2Zo6_0tnvr9LtWKus8lt`0g_4{kUhkO*HT z(evN}e|{|3%ME!2h3Wm`mm?f>YX1Q~@ z2eC?d;+FyY`o~A4yn5BW2g&RZC2#YbJEzH8CHm=Nsy2joprUK2bWd`L+I?Q5Ylg(F zYG4p$E0`Gu6dnxIVtHantIVFRgvWnisLYW0%PN6j*RVA_TvyG1;Oa*u+ls}PaNmoU zn&E)pz{P=hpfMu&rou3Zuv$c3CDCm$ig4{4^ovQdskz3FUsy*j$%Hb~x z3N<4m2?Y4zz7u6G=z6TJxk?Dyx-aKW(f+c(%-3J2zmw_sZBm%pBZDgjB#KadQIhMl zB92coM`tk6euS0JSjbri|N5#=aBGRHO!TAjK+Ij3KrT8^=~1Wumn}Y+`YJqTXPb^! zF9B}!EvEjthujdl#QCc1rG9vt5-Lt7MYQ&X!Wb4Fbp3 z_M!Fhh}bCpafg~b;8{uu*?cIU%3I45Ubdp3zrF+<`{ZcIipWQ-#@jc zsid6}ZgwHeP}P(dz|p%mq4VLp$9ATYI3ebwSE_#RURXA&8kt_vt(ZK==J3Tm53>K~ z3E|??-fPHF6P>wxT{&0BLZeq8w^7#br<%bnv_O{w;ljJKA{|3Le!SeW=*fPWuI{5l z%k@SH;0w**(t3YUv^dmDP!}ZGR;?=`AuDDQ5PFfV%w4n#Z-Hy0*$MWfmKcE^hxLamayL-0`+{@to4g=k@XN z>ttK{NM3iE=5JbPxsH(HepIvLe%YjApB*K_tVqj)Oo;Z+f~|f|PY8=dLI?{=%|3q} ztJwI4TYnjc4Rf6D&vFc11RklzPe`TOTSzrsMJ?$Ttx}w%*y}TjJhk;_&WekxnYQS3 z4OjXTYG{~>oagBZh-5zvvEemWTHSNY{y{GOc*r#yOO5!I@d)fWFnM>;vrmNk29%B$(nW1ipYPW|Tq@t-bir z-`~H#(EJ^EfNF-?b$IAe(DD<1|Fe>k*Muyk--Ah*4OifW?thGidfBrl->|-As#!#) z8*p6Asux-Jty{Mg#>8yb#cU|#CAv5{ImL~=jd+o!(B|r6U^5mjRVu{ZiW0HC7nRfO zi~dr7W(uR8GP_Nrmt2UN1*bZB^%Nv%7H++Y8}bp^cU(^Pwv8< z?G5fCt3K?4&{_3tGH$)CIOrT%$BBq<6xZfG+P7>m)ppZqw)>X8{wKfswT+Flr%qiv zeE4L#TGk^y*AdP6;cb6+0;6^5S7BhsTV;02Ls)gK)vF)GwzZuAFg#Vg;{~+LhYvPf zJT0zv7PoI_Cg0h-Qeev4?ax+~JsD?d*tvdTsJ*eXQ%q!SdEsK*nM#SkUq$BEVQSXk zZdtb2Tv5Gh?^1CWp1IEN$$X142*zAMs6Q{8cKl?=9 z=46p9y#mx$uA2h#RGzs$J;bIm)OgRHZ;xv*W86ViYrZz|wD~B-Cn3;XLr4MSYnt+K3qOZ=_TCW*uW8nXsrOgM7 zLrDmmjHU1doJpTk6=l%l^ulO;!{Yl#8-M~&bSaq6tMjBZM_1pA7Uo6rhRK*|t6oP+ zJP+pM!y&6UrtIa_0p8j95|nTTs=`&3oQ9Nyr0tw4t+WhvHk}hknLN~`+$++d@-TyL zY^F3Sgt?C5j~Lpv;=)p)6DR!tC#Nku5cgP(n`p}OB;H4%LamOG5f@%H;UhO?epYEm z=-xJ^DNkbFT~6ddRoMswAj<$!IQ?4S+!Dp%)%;_H4M3R>z4!M4o<|Ag$=Cki0uPTK zM8yYY-XHZyq`LQinm#>wPQlB9Ql0XPOP{NhrG0b9SORxmFp8w%=GE| zxl~`CpoM%WY^^8gVY4*`v!YfX(yTLx!9t$Hq$K`NYlvQxr7GND)4d|`wm_^9?}|D*^4V1(S!e_Y8I3u zYorjjCC4ti$|q^FwMJuI?pIv6)}F@mKYk03?U{8!T&mTy!`}QkvU0tb4 zyg?FO+?q?QC--U8c397CZ^aa3SPc|YLER%&lc$;?EI!Wco3*w593On&oL)j(b9hh8 z#XmDkjJ`2i_bv?V6+)rdymq$zk#f@`>W>aSv$lc$DlhC$j$j`}@)U5*u@iOkL_wZ_%>jRAG23|$(XL0W!TW@1;SCJG4|BWo+u?3f(X8UGgj^^FEs5fkknEwRe@ zN@Ds*??}xV$C)lS|JFT3Nb2w9!u8rW@zo}x(vDN7p_I2K=-eos_!T02n?AEwl8H(f z?D;uGUoaUW&_1w@m4>HLHbMEkJgErXD+0Jp{wev(_%4;nSavA=^t~oq_9_f`QRY5P zy89?ech1V#O+<1`ca4mF$J&Z2Mf4B z$`Q~|L7tC|;&7RRgNUPF=6PA_F`B2g*s8HY2SIBsZHRxjZhJ1YoCf3z?)>2yJ?~th z!=CQkW48i8698nixa3ZAv=UuQqm64WswIX5J6S!TLaiKf&^S1gsa>M_oQcVw*%YE) zJu8mO>6Vuaai(}-yLMV`EM2S0>NAzP!dM){W9EZN@xzBD=(nwxi`SNSM?JU{^f?w*mc@p`j%;lV2h00vev#TIVt`1cv7f8Fd7g%Gn%hW>E{ZYA3F` zbIYh|8)hJ+9RK9=Aqfw4^)9>rT2C^b@eLJ zW{wrLQ%JZ`Y3Vx5BC(ob(tL(loIHjXf+h4YdP=Y)BT-g{K81L%)nrLY9iN1>$Vd$& zw-~H>tSt;j@f$}5p|9L1gO)rLbUiJxM)OAD}TIaxm@M=-|&@lJjiT5GB zk(BD(jDEAMTj{P$m?d8H9EP+H&9oyUc>k|}lA)NSfd>#kct+!^X1W$iUUe6}Ue5No zfYKgv=okC$4aDVnt-^OBy-z77f--iR?_JvJ<{pbhTN|GvvoU}8>kwA5?^sDBl`;JB z-DU~YDTE*4LsTw`)DW9qbD5?AMQ1ZbNfUJH`oZJf++Oc2X?%Rf1}=HH**WYfjf3za zborp=@k%}Ud*8z9CinSf+7NLvl(WVSuK*5%LIY_M*5t{ML~*YiK8j`Ql)W!^LQki} z7c+%~GWW>}n1(nvwqOy(QLMObku5gf#BgU&329;S;3*i!0O>$67Ea9~ZX!GZt%|1< zDHdN}uqw#pBw1!ei^Lu+e@&{Y2|Mhvg}zevEZ{GpOl_?P8`T$dmo>`O@-XYm5md7} z%fA4ZZ&5EC;y1e>_kk%>t4N88apfZA=>C1<-HI|^@00IXqTdTh-afD5+LcS1jGvHb z8Q?nK;A%P^5O4@t$2UoLKSS_lj*~cdu5ZDH3Q<&1HjOWAk-cEht+uH!YkHgGVcf{* z|1Fjw{fVJMeAPP`Y7#?koZvLzIZo(2+%B?o!2k`|T<7UoL1-4~?1E-F1gzkNO+2}3 z&ai`D&?abM3W11$)J?}=kAq$^L-+GxwtlYjGsXH+wt8c^7xS|d6HnJ{KqtM^%j$;S z@=bmnokgNs+3e55dtj^@^>FT=Z)5JAoFHzE+Grw^@TH?5Ae}errh<8d9-^bE*3(dwi@p$H&*6YjfvPv)03hWwFBaF?euw z_nEXwr|Ax%0zNi2TW*buebz4AP*=Ku|6bzb%QG>A*5Jx~30o?Na=_Xc^fBqrXS&P- za6>@?OcWs4QO%H6YK~Gg>RpGM;FOU;)z;R^+{IRI(g4P5Fya^Uq?V^Zl@`0NX_SXh z(se;L#)dXzt@{&=#VWq2JM4aqrJ$JsuhK^q;Nf_bXSHB7brf629m*5N%)* z>NEUC@E}u3XOW;gO!DglgjJJE0(=_7zXJt|BVp!Ff%~OP)KC47-t(QMJ$vXqI7TFf zh?DvN9cNKNVzIRc)ht3Qn&}zIfc=BYY`!Z;(k1?W!I9-Nz#K6NH?ad^ ze=9W0goM9~Td};TNMUQO7w<=Gr}0>9k!5r>9u57iRlLm1D~GuOmoK?CDo!K37aSZK2!pA5u#3Dzq^QHa?L|b&nNL?r zWg*BmSwIFsv=P+JXsbT)j8<|o8VdQ#g&?dFn`fSEMe$|QpFK2E=sqU?2dNE6O#<=g7sLq$sZEI@`&jewUVt;0 zlHZ7s$JR=xaE&`A{ZH4Slh9NE4M-|!yPoUZw=G*mM7v;H&8-Hrt~0C+O0f+hTMnP$ zu!xQdoGrNzMsyPaRO6MO))B2DbQLV?g4g}VV8*(-vnX`S1IisHC;TXM>3Oy;146Pl z!$A%PV&!8Z~obt(=3;mqsYiiRda&5+FAKkQTCW}RCpMAIP* zfLPT~4OQu0Kw29s)pclz6`fuYAXcSX2@P2>h4O5myp~6 z3f%E$zbj6%tSeWa%74<|dUSLYlhk;zaZVo@G10n!!o=aP% zO4ir@46$app|HkPJbX~hX)P|c7z$d8Kq%k-*Xb1|r zEv5JwdTmHr6DuAxLA?icnu3H=3rwEbP!3^~*t>Ky2Zw2|RQqNLtv7>&dmoKjm4YB?`vA!3cB5VLPXguJkp*@(?cHq>_ zSuKE00<2+(XlK6FJZ9U&uK>|*gD`6(+FdYdDegEG+3YY}PMd%ml06=RDBz%XE!=uQ zGzhd)aXuu50{2_Do^24AOiQE9wU7xO;qiilqW6+J7oZi%z8-w^sCZ!ns-6>Ma@Q`a z*k=Hy^D_)TsUh@ZfUSlE zTwx1>bTH|d+65ctjvbUrG&?ym#Rwdq!AO_`hB7e(ax+TWD-n@&RaA6r4w%;+2L=IX zOHHroj-n|3+N!5~kckiiD+&X!jSAcIS*U7#LiRN;RtuUP0O)PSC9%*5>w>ZS8A5T| z&%DZZ@m+?#*HoJvbZM+RbwFBeHr4jc&+vb1fvkHwVS?)@l=A83^=jU+Sff23sS`s5 zK7y7K6xB2}GzT6(vbThEx$>C;o?9qjB%2^h6c{`#28lS%GaucZJ!C-8K}aqrT%2%& z#s#pu=JN`4Y(=}czEdJ?DG1@sGmsXP5i#}Y(^^8Uz_|m8N3vJ+bA;%pJuf-)AcyQl zALsAI>$!+Z`h)}6?KQj+4aH}Th z=>Y`oG>xw`UX%Q41}vyDVWuv~!ppM)6sXteFw#a*LbDk^DQ@sDGZ1YtiVJoS?revG zdJH7wCVqxFRpPqrH*PE2=Q~kQgSZ)?(C&~>B8FWkS(@^QMF0xvG1WMnm z9+c0g(X7}U;Gk(_bW(}K(J8&XXp^zHxHzrS2kDKrHPl2j2%ceRKNS<7a#@)?M23c@ z?I%`B#2&nXtcrAy+7nD8pL6T1Jx17F&}5`T;qLb^55R}lY9Ifd$cyqIAmd{q5(pq* zVYi++K$iJBD#}9D42j@HB0@r#bX^&+B<-PAh`2qCyu`MyvUwOPktKR*f$ zA_z+zk|sUbSIfP(-)MsLM7zM`xiTor1rkMkc9;>R%JlLnuNyt>VJcOg=dv^lG%dTW zT3#%J51oL?({P$2XA5ozt+3;0e-43dZi#v7Vnu0YvvU#%uLQeY9M?ARa- z%(+{E{U&=fEsYCcKye*C$;$U36deBp#KFkt;Da}*m{wItTO;Y90yuc=FZD~l)riP7 z@Te&PpcE~eEwffcB7?vUhW%16)V zG=0kV`efhhQd-+<`pFnjVeG+EM2TUQa;KGGrp zHX4RdTQ`gW=|-XTfF8GIz8a{4Y+R{r;P$NDK22IR|k(v~XwS_bWexD)> z+Coq#qFJNiveI64qGbs?Id`J{K-obfVCCIw12hs{O-IW`V9GM~en&Xq;yEuNo598h zvXfYEiB#xCfn@qGWFG|W`B&=D{p>ANm9_ZJ|SaiASAe#S8kIQxN{xhWU zxW24@GYtC8h-?z>e0_a=W`m$z?z(7E9%RIUEE6QjWJ#&!z5U&01I6#%iMV&IGAJ8i zXArO<>?oqVvA`@L;1--!-D*xZR@~__lyiy>pEP$!u?Sa)-uMUKlKEO5A|uZa1g1^N z-u_v#V!Y*IBs)A@`|Hbawbp4oK1IxdGu5(3t;Ou{14dq6MOfUb8O-c^nH@oI1ys3X z^TnpfH$Z5m`Rug7XUOs?kq>DJ>RR_#7}>SALP-UB1FJhRqS_r;w5*3~B=p9uFk47J zaC^ha-U3VZLJ3rkSFm2h_u|gXA0m&B9hwIcfpHogQ?ao|RdH677==y984XOvi|H^W!1ZBPLU_i$Vrg%OETj8eL9Ld-4 z{(scEWG@ya2ZzYWdM-jQ5nQW^n>eldSYM z2xtpEi2Sd4Q4J$ykg{)t%q1Yg+BnIOeUC<%L9rC>FI%_uEz^V8jYvIV@5tnWj<3Ao{Ef&!Jka@MYH6l6$OiU;XNsj;)s%xd67MT zQBie3+X-}Mx1>m})09((9>f7Y-(G5rK!!Smo`u~C3P^VygreeQ5@cVsBqb#UT^AgX z@7ID29Ct7B0E#lKuSx|Ob2{{;6y}bQ>7-l>{M=vWkjHt){W>&*oSWOhhUWVUkn%80 z|Dj>8&Elww)6x(3=WH^Upi+MM&B)%hMXTuiOayAeg0%Gwq4|%NZ$(#E$0PF%g6B+# z%yUr*4@Nw-D%Nzp*2g9K__u}%Ch;@9cIXk&xko} zNNnqf*{?CiaV0?ebuGK)s|L&)>}sMdaEA^+#HtdagITN{K>96oJUU4rO~?k~jEj%& z+rrw%k2)5;xqb*w*b*BJdzi=~R)bck*oL*0luDXsy5~A(0){IkU|+}#gRoDTJqJr% zO=F{SPDO_@bh(1*04{(KtEbp{^B6t7?IIsA2Wg{)268=e*j51ZWLL zVqkkf+iTPpBcC+oIsL zO5FVX_!~=l%VEV0&;TWs!1f*<8B>$)bXBkMRyG^898lk+#9KmtmzF-_`-)rVQAS21 zqTx1dGO{;ft6aH953I-)NP_L4jN}qt&91F~1wB#F!>OexG=tvX4c!_$fyt1u zQFEzN=)dvo*g1qs>?pP4orbo&R<(CD(oo(@9x?;`M!5?wPjfwNt%b035MphZxT9Iv z2t_IyHqM#Gx!pqMQUtq|`kcw92l@mTSmS{$nd!+%=F!zcLNkN+eB|3K4ZF)qN`X+p zE*W8WP`^qevP%u%BrfX0+>=GJxIr-j)VMQG z>El$P?Sbgij-F|m98&QfW0JTMJQAY7~-EDlOWL!Kt*T&?-?XrF}0mT8N5DrCp0?)xLLrujj;kI?VTf zeZSZBpX+m(&m8Bx-_LSC_wu^$=YA1ei(;`okU+~W^<*5&mGEnuo26}$;uq4*U71x^ z+l)Hht&%FOg<_|yg3rXnozi*?#f-YMI$SEcfqMH7J{HW}Q$dGHeOVx3G=TJo?5BsT z4Nv7c9zuOsB~US9S1=CZDk7KLYa)K=LQ`%+T`3pJ{(Bp=kiDq#i2xiQEPX|XWDpL& z=Gv>+q>iZOk88A<95&7%MN-5Vmt`XPcXhSmsm$bKK)!CH91nLcyO5P7rAMfA62h@+ zM_vahw{Yx$S@5^htSp}E9bqtY{Fb-hz$k5KY&UyWNr4iR&Hl526ba|#_Sc`|kwxh3 z-HFScxG(s*ynx&$v`(8xS$>^Ua_U&pN7i1G`IPMoU}tbY>+gn(>*imvwT1J-OVV0d zS_v;+2@j5bgRz$LRInbsp!=%zamPj$%A)3##(#aQDElfz&0dw4O>*ws>%J#TIkO0e z*Eivs{WquHL4Jw}owW~0Fyr4z{5cze{&DIo`EYo5RV+0W!Bz@ZtRM)5ceE|sl6a;b=Xt={^6#D&5=r>!W9nx%i7 z=yQ6(4Imwcf1LHp7dt26u5HKqIb9CvUunK`d0z8D^8;*@#05VN40GxI3y=Iaz8E|* z5-am>EGYleCc`dmpO&Tnpxqrp%K`#RhUri!vloZ|eKKUxuKc*on}R9nKHB9A zoQ?l_)xga7Jm=UBZ^bEG>@ss}6*Ib#`IIB=5N7`JUuXVQ^ZJsj_hhmXv+7=K#v<^u zl11R|HDP=vWt|&&#@>II1PIU+O+CyjYEYA>I-B+)e2{^gqAN zhP-W4u-3QRHQz>i2iH{VkPS>O=)Whn2U&0?Hmf#u@PFTK^Vv!{v-JBxIF~2~r9XJ- z>v@usN8;%QrZ2Q5=Li*0>xbTj-=6vP--+pvtu&H*`S)WY8v;R%{Fhx!p4a@CHoAbK z3?3WCXFd}#T=4AuG>5Yq6anL3UAm>gPHqfItoq-J3tn_!Yu7yaR9sSEeA=`B>F^Qe zB;cjrEo1W$I$;rGK^Yc3w;7Br!r$u#}dM(bdXfV=MJ zfmDig@{eEKBB)v}A^5JGDR2X^6aRK7yABQ|BBzl*DoZFK$b zaArSup3W{`i$w6V$N%z9dOg$1AJ#AH3Q>+nzdt^dZhs#giuB8k7b!1x{`fR^VvJUQ zeV8+?2qkkbHLI;#X|K=uZe0BS&mbn&TPeSvT;}T1&T`=GKBePrV;cnTt6umeUiG|9 zR6*x*C4n_p5Ak?iOI^*nTX^qKzrurNa{=nn|9slC-sh561n1!wo3a8+PA6pzPV)I3 zw6fY{(f8WHU`KqlWqW2#-)P9B<9y%u4R=TFXAkqb1RvICXyNC2bk1?x|N5s(>rTz> zRpxS+vMhpuLM9;yZNwPJV%j^{^$SioqG9>t!XC~DR#y3UH_d!PR^IVN5(#@==NIBJZUy(f^1r9RqUxvL9twc5Rn=HkTjz%!^t(ceh{O z7I5yscZC>OMKV?__yU?O)gugFB{IhFHA&X*CB@*o@jAD4x|s%I%NV$O%&|<58I~zd zfvFx#%+UVTM;KiU1OJw}kkVQn6H%*u~b+oaJCZPAWG+B*l5d)J{n=BVg1>b-} zj|!Evq}A(8oTFfWb!HYyXu5rH$#?Rt5l(SbwcaJ-e3IdKLte&|@el^FCwpQF5}6;x zW#_+rmB#nOr!m`dWwQ8#*T_FnovYE}YJU0>LVXdr>Zd4X2BBLe>}>te|9hz=pGN-h zDYONnSfQ=;eg=9Oa|lB8+;i-M=EjWY2oh&DcdRa(qur?5 z-t#ld56-JxHdhHMEaN)XLcwWqjft;xsjchMai_8gTgujG$?9GnEuhxNR}}wtu`WTs z;|6aX_#%cHm)!R4`fOxSm+C>=)#kO&(=DRCJ$GkjX67KvhurG3jf@PMvMjZDZKY*>e5MYunEm!4C#ZwtfLdsoxJhmDS);KG?;&X| zd#SWdym>o<1%3(S(^I(bo|<|w_(OvCF|pOc%X2yD1JQPwU!{;gBI@(h>C>lA7j97n z9ePabs*acFoIZ5BRO?XybaLf%V-Xs2?`sP^=omd!!g6iq5zRYHg~ra}bmVu3g9=kS z8w4uT#TD}h7gXhOu^2>hENBVkYx!edSJ9v0^FFh)vc#`GK{EsSkNN5`J%y>zd0l-T zRNaW6>$O$Cuw2*ia$LvT7-+JRTENo(eqI*{H|*3(e^dJWnMysq*mUX@HIsJyrD)EU z3og_>6E()}Cq$z&tNHbv*jTDposiqXn;T%hT42a#=(0lgmTQ|UQ-K#IuDe|=}!td7e z=6ad0-kvt*N1a;k#(7CUKm1Vin%^B14hubXJh5`^Id#oyX3tMG>TS;NSlm36`Io8+ z3!R|krO34WQ8MlMlLI>&%k!nNG!2Ez4>3h`9u`xfr;RKufk#W{>4$%5a|z%Lf3aal zRC?y8X}!bwA=aa&hb5QZ@}L&Z>)NK6ALo~(T4&B;rf_vQn5F+o+vEJE*Q8&c*_NgTIdQkO3E0?_cReB^_JtwV%sd+J@|63K4#GCd>v%1n7Q4_6aku}Zi)D4|J=FPTw{qbwhTYs7KOo*Sp z8q2)I)4f}+P~n4kiG1zUOz}*c*Qd#fDv94Oddf7=a+AgPefXfX$m_=LjUQDlBX9o{ z#kFel9LFG~b)1^MzU!B@uL3$xgUf7Hbx~2^KRE%4s&+@%3PR$?s5tiLz(i&q<&jan zvA&Kk{E2zTHJyEX^LH<(62ETh6JeyPa7*}U?hfA6M?nkN`Sea)9Y&W<;dTgOCUuSO z?+zLY#s{#!RO$!(LNUL0c7H|gKeIJZNR9|vu*|Witns8?nZt_c4dUxZq`5b#=1Gm% z)8fMG$3EHZ-zUrKsL{~noA4o_!=NbVqPtAlp!~fhGTfF0AssgBl%DIAS$NnPxl_3W z4X&Ccbco$;s%B;3*zw}GiyZ7Md`n|N_cG#_^sMGn!*Ktku;zIxbJ+)b*A{8^!!ZW2F_q)Lo3ipN+ds_8vNO5*#QGv`gQzRKJ|M-K z^7&yvTV46z-)aGLF39$#w{CrJ=TI6XnTO`gfh%&Om|t!_@ieRzt=dX&E;Y^(=T(0g zeDmJUO-r%`WQ=Q`K4R0cx&J0`Wtfnyt?fq@^qt)ey^u4CMvfn249Y^L-~Oz3k+LRR*;M*{-Tzh zQdUz%PR0{T*XQT_X7)Xsz?Xd zCadgaX|#vjt|y0!@h;glcDMN-q1Ek-9Bojp+Q83+eYnTeX|e#FGtcN;eUj%+HI2ZW zMt@T{+-THu+a1ZZ%>l1^a+V$UF6)S2E9W?MhdTDL(Qe1N*JI_@d6Nyk6)Jn5pv1K< zRORmWvwIb$-s))eaEO~s9o`x+`D(NI5j#wH8!A+3Zq%{eS9{77^VyDi{M5y#cQln{ zA+wN3Ugae<`abc92|3v)aOylB{Ht*xGy7#lYwOUarA_QC{E-1SPVUspr=GfAwOp$E z>3x`nVzVeS>|}QQn+Y!Kdb5GocX!BzSaDyd4&UoG)2AffP-&EdObc7CqHo-96&Lw< z_5S{IvHsuF-hOT787Uh_JeQ6t9zCj|F?y-{u1|HOhOWb~1B=)gM*{%?`bbT zR5yGM`K@d4V~JGD4Gxnr^V%y>rz|ZkY0|bspZ>6m&$&Mlg*|<4;wCFAX*BfdE%OIE zF+p~q=%E#7yE;1?eabpiltq?_Va;JHbyrHAt9YcO_|ZHg?||S6vDmn{Ue{bllfxR; zj~6$?hbTB63vZxXZl-zpOf%QG{Y-pP>Fyqh&Zq~u{+0_V>oTzUrPOqZE>2FH&MrQy zzS3O_C~tHXakKtUd)d5oU7VF3y}iAmXM>q2`?m(XQi2GEm_~GB%ThEAYMvuHahT&; z$iF{%(yFldcHl(4+|(DA{;D*OgCa*(lhA6eSK`-`P^9C6_K8_#)8m7lE*lS>i?}1O z)bbjytt(d;ym0MPUwu-#YrHV(=rtP>CCw#x*dJk_>M|c8;CG)ASBin5f_Ec7JhK(^ zqXg#+l;Uy+K>|b9aqq7IEW=ASVAv6OBz+v@k9FRNH@p~#Nff@Hp4VXq7Y8_$Epr{X z6)zE9M8s7}snDObY`-Fp%+A_6sinOrp^|79C7(Wf=Et$pdz+Q>e?2yNr3oimUvexT z{a5pKUM_Av^*En$fq_?&H-n31ykq1f=PH(r>X{6_c6oVb2CucvLe7=Sb2fNh)E0*D zi}HKZ+z^uTeQYqdIXvYV_0X6X2(_yjZRzlREE-nLOC2Ap!^j6A7vwDC-XJ^A78hLQ7@G4fQt_Mmpnbi4}5 zNwsidWf70OvnYy*VH#_~4*uLyVjamkKMFwvkN}gx-GAvP;7r=OGuroCSOJFa@Bi|W z|HX_dXHf#_xlzO!64TE;?_P($#q@$3Wo`diGD=w5U)Q?ykk67GMa5Q--o4it>hkSC z9VF&FFU+{luBq)rnu%kTNTPZ;r4iiRKWGR50k+>CIUm6zls?3!jN5+~U;T@yM#g0i zr{rpV_hRQW00qQS4i<`5E;t}pI{nqyf^*4=H-Je|DInqWmB~ zq+}jFz*M=CVM4Ti9@;AOKDG{>9PHp>J>>s-zsQkI2Uk8*BpAf^+7AO>{cm&A1r^mX zMj0$v(mY;0LpjEP_H4(ekDTToX9$}QJ9x|Bp+a+Y)W3)TetPQh!|zYU4}t-jM@Fr? z9V^TzUZChYs_~BkL8ofoeICXF>DFKVx~4WuPxG_te}CkB?{braMWP2?SbjFnphgKN z5=d=t!lJJwq2zCtWF~FpwOTDHkDXh>IwzY~yfaIR_r~f*Em5JCF#BjTMo3Wgh+FEp zV2Z@0cmF5cWcVu#_u}v9>LB$^Lz7J(Wrc;24WWGvX05W&xFxDJXb;Zl|UtN%vDKefoZ;AplcbQgopA(k39^p5FjaCg3?KO7nYk=5Va9MVfLMRG zWJg(_5p4K4!v;L5{E3cOuKFfSbOB!&GMZy*9;+puS2lg)#)|1rOl99~l>GaJ%j4W| zGceJ^`+j{G)!y3yJJK2TY7RL2?3w=eOFi%v#brQw65FxX-_7)^O|)bfEL~c@8)!q8 z9WKj4aWOMr)BE&he#WB{z@0A>2TO9%0G}{@KI9M8jiU`|vS3B%l^yLUliTFK`L4HK zcqPGcl_-m%!?%9LO6fnCuL=tR%NVs}?n)1km7dEr6J`(1b9b(5BM|z-J`!w~L2Ulz zF~IG~AQ*P>$7k!#Itq-75`T;-TbSU2P-y>5RsdhM@x)LVcROBzDVxm7bs}~)H-F}I zL+1Eb#CPFNa;D%C{PPr5*&ja1wcul4sCZd?-{qcD3*$XMjmIB8%Cv~V+$L_R9jTQw zekqEB#{i^Kp5@LRBW2CHx$;g~Nd51qp5GYx^!X)QeN4=&f`|irKYDYGqq$CQPqeI8 z)f*Xeu0V^i-Ni1m<31R}D1#OyRO;SE2Jkgyuv!1i&F`Y3n!;hv6UWY5Xek_aIWcr0 z+S~cw?{ihaxGVDq83|t7@+I>sVetO>sq?@$K=>nrcw%+!ZRmjTT)bN~7xohJ&S=_- z33?m_*J#yT?bi;N*h%vTu>)$`!MA!i!v816prJixTVmuC^D%eEQ7cjUl(#JSPU~sJ zQW|fcToT4OWOA%o8Abq)k?|%d`76#I2H+Wofw6V~ggY71l)d`{M zaI4FfmIYwx;P#XmIbmF%E^_kZNxjLDp0_nMYg!B4-O#IFv~jxEx~TH8T9U`Xd4b}l z9%!slfKuJo0yf=SRaI5zFJ5#JCg|D$-GT zmqu%7Y~*HUW+u}$Md)**|4I^(;b(f$k?CX zV5W~9Pn?*T?UJ84A3Wd#RY+y5{?LH8r~L+$9G)1ugHhVFc`LT$PWHOt z7Q0+k+^NYMM>Pfa-1ynWS9zCUsr2A$kWlQ%z7w2Kp&}cVBUz=@8=Y?=L}{8f<#H)2J#oeR`yB(xLaa5R~%Yk+e8>yfi0m!P3?FEd_3B8R}K2 zk7J1pGCx=)VmtojrW|L0j;-O|QZc)cZkvIZ{JOMEY@9kMc)cz9+&+H%nBHH=(MlE~ zH8s_z2r$=r*|EQt7mjy?@&H)4ykv1w%I|;uaU#p=VwFha@8uB(Hs+UAPMd2E}11qeF)df!*Z!w5-YsFa_D^ z=TlkkYG;+_4&08A@ngYz_wKa>J6lD7@b(2w1j@fDWdip`pJ^m$s{G zO-^OI%<`Z}PDg8`_L|5!RVRY0NxJJl$K;_B9LJMd&5F1*yunO_wwo%_N358htO$YB zp2)T_+pL=_4OmFFsTWIfsvcx3W|KW>MYt)*PQWuJ8TTtawJDPg4o@FEc+hMs8|oQK zo9ZAF0uR@f%cwBOEyPH{I~4DM8E)O0)tv~Yp+i8`obs$pYM!nKJyhygRa)+aC_dE>HsqN!tZhz1NbAOKFf7&dOub( z&?Hl^YmI98K>Mp5f=;-_FMX~wXf4(!2;_2>>Y9RZeRnLgK`N%1>Kq-&YET6?}s=ugctiM$sHzh@IdF8yR zsb@)`cu}ThSBtkI_vbu@9bxp1^%;?JMoK!M`&FamH3P9VYU!QJf_Gb5@y+%exvATJ(umUVb)p0$8Xb>IeZc!@9-wQ(! z6%#XM=LLwLhuAyf6cDcj{)Pwk;k=QN8@hz-1q%a@#{5aUonHu-3K@4prE8G*X1|6`%A5JcOZ8$Ffq7`81lDo zS+-?=`AvGf&9^_WY3fl~T^bf_0h{(OL^T}m^(3cBI4+%+C>GaH4kCEYv?`FBpE>tz z<+J6xK8207u;twu8`*|h`M>ITEGv)n_j@`?_h0dp9(ds(n;I9lRathtjTrV8nZ7G3 zoQ`83_IlF#JU{1*)Eeo-jacBBF*We2bw1CSyy(uI{s6W0j4imqEKXd@@kV+63MFW%?yY3vxiVAUFO}CEC{gq*<+DWI;j^cOdwa z8mzR88!|xyzz?dhHQUeZ54Tvxu`{;2?(*f!`9wHD(6^|yu4%?98?SeXJH>qQ;>G?p zUzL5h*jRt1BY66r!pW|4ukWzn4)h`WNmGX|t%UP$!*#lrvTeQPwl!0r|H`2T1F2oR zTEz3lm7t_I!nF&>fx($&^^}{jdE26=4gv(-gaq_t!<&yV&TClX&&myh4p!TPfWNJ`y}zSdaoAskFF&S4?ajNh-olIK(vxpM@3>L{S8n|v7l@_e}`aYK|b ziaW9nwgABdZ!F`Qm~b>OFo2tMVt*D`TAv@It&Hg> z%c$n$Cq=oF1ARs!a0lJtP7j}?)#Xjs-2vl4%b>>^5xr1Pw2;wz9V{h2(_J>R8Kiq- zK6yrH1G@tpiQ@VAZr-XXr>t`&_r?YS@;He>c?FLTYBN52;2`m|aYk1{_XRY~_9=|+ z4cpBkXH$bW{n|R5#ToqMStC1wN1|j3*iH&?}`RJU_+LZd_$&=rivJ(;#T1KD4 zzYtM|x91u%INDR6k<{GuSbM8RiV^pV3AIhPsAF$E9gjVw%sf_c5W2CPr!n4w&Enm0 zje_UPO(RzJL@*UFeRyQmx_#p0ex~ zA74MN9erK?i2m_R@FKvhk=Dh+c>bY}}YF3D;^xPfySBtg2k1l(0jh z$miPj2EwIwYdSx4L3&5o0GO@)@#r`TYQ;!cdjI<)ce ze6H?^&+LrWS?~o_Gtso(?Pe|c>7T;gz%cq=1X)3c+y;>%PFA=CZl?CF9Q~tCsCe$% zL7XRjq@G1=zBDVmXJ=<`A)bFL@iiW+MfMK%AVa#6XYAP`a0;q;kTLec@aYs0JDGU) z72%%zE!=oA2_$GzrQpZRPooV*%5f2g#rDZI&BP5P#+gwNetiG_dfB1-%L|BSg`}>) zuHB9=yw;15;{h*O+x+Fm1e^XAV$YXy+u;IAQIMp?l3edpFA{9_qvr_!gmsMu{QBvM zQx@xp*ylAy)T1xkQ;IA?5AqPF@Y_R?P7{$LPBT*^{HUz%n^ZF-I;pjg!}J#HZz0ih zf0(wQ^`4=&)%&w9vgwYz??&jX1|VI+UC;KJKgEyV1W$1 zwP%^+hW;!2+}T%=BeQnLxs^eBBM37DoP9In9fxE3%MWcEK8ZSj9Xs~#QNI@$s9)d; zzfs^5)UBJCQPml)`C*%hLyomP$JJ`7J6^1wAs+Uv7C@urwua8<6xq{%|LL$5z7#?y z1)OMYWY=>>=+W9(k(|zent7B50+YhMY^PST>Drs+J=zs&-FO9}N-Jv&zNx8MJw2cH z`ftko`P;kKEcs)}R+jLMcQ*WfgJWxi-kmJN4C(Yu0`p2&hPtPn?;Jmuq|LWcG=_CHOrQH^#CBLFt*X&gPbbUu|6Te4NZeQQHKu=yj zC{}+V2OYGPS1orLC@U*-It;xv!|B;u79!IX{3I-F9o^SP_`yEdQKoXY?Cy@p#*Rm3 z?d|OaL^HP*d3u6WqjJ0-PJ;)BN&0%UA=7M2nmhU zs+KNY+BH07C=GRMr)}4hB4R)GWnpj!fhE9WCk{HtOuzSJXv6}+?q!vBoPt9NlHBy& z?}=%quwVGn%netjNJFx(QgC{cS>4S)vZ;xk%K!*&f7DyI^oa1@y?eoRx2*_gtU7F9 zl%EU>9_C>wbdo=Ct!%mFk)uafAi!4AY(l8m0&n=>Iu^>Cn&RT(=z5van{rd9gI_g; zrZ@kww7i#sh8!P>rRlO%W`6`0qJG3Cg~S(HcsozdtT&@$AA-+{Qpf2o-Rg0B;@K0w ziCM_WDI7~k>{N2n!$Sd&x|LN%9PlO2_elmtU?Qw)9vDObakAZ`V))9Ib94oS07my{ zRUTAGr6Io~d$nXo5G$0D;id7(iViqar)uwp&LXBtnpsv0M1Gg=5TbRb>(@o_ol`xl z#PJ1{J!>COLe?)>upnWuR7$*4k~lEQUBc?I=PSG9l}M2Zl4z%jC;nW_O2&6pfg<** ztjv?ks^)&JTu)t^%C1euJICx#L!1bChGk7nOiZ*dzujwSuv~8H5`2M& zkOfCn#;`V^<4f`&D8G0?LHa2<3DO){+R+8SY7d`7;nUO4%i{uW-!4G2Opf7`l@0kW ztOyrI&ih%kx3wM1cr}`RWl#?|k-K^D4FE7|^{7A<>_U4eDkiY)s)Btu7Tr6v$;LFO z8lG{D6K%SpbV{2JyM{fk_0f3F1W=|>w9z#2MS9$+tW8`@dM|x865ZrC4A_IuL-OOD zpH_HBEZvsx)>O(mn4(0)SZ!c%kN|07+~SsyyO- zy`rtQJn7u>=lul4NZYv4ZrX2ndbCLnkeIhTFJ+xtbnW9SpqswvH^>8>W>}35>?Qjo z3h zp{*PMsJ<}wp`CzztB05ib~#K8xd4OM;6*(=N%XL3&ais%ga$At+rHV9fqZ!}(qZ}F zDrJe!897PdS-~z?CJm%z?l0aDo^e;qNIe@6lVBH^M$dO++KV^LqijEmu!Kao$w`H^ zw^OloZxM<44THdL?9&5J_ICCS9V$)}YPG|KwYzh3L4C+hqTpgQA862r|Bbz^IC$t# z%+#H7I2xNH$31a5UqMq-vv^{ahBgbD7?9l;5*CihHk&}C{>q%4zNhReaY)Rp$vbX5 z50L4a$Y86JegRG+gS)e=dRi3aCXW2}_`GuQt5^C1Z7&78KrST$bNbT?Cd%Dor^YV< zI(nO+U$ien`N)wYwZlOF^4?mp^RETvka_JeU`zg22WIqfIhgofC-NMp4XOqQ23kC% zde0{Za@3?|kADorFTE2RaX|BBOJ9e|$-(gJK8#(?Dequ(9xRn(rC%$l2qmxS3I7Umt&x9`L22Mrs7A)SgjLT(p>kH#P1E(OsyubMt7;4UodA5aUt&vL;2(edasGYc+1gXjP+;|ZpRhBUuE^5$ zi@p2XKfx3zs)P7HIcbBd2PV`1g3mMGPf)D|r-k-@qh+F_(78`EG#ml+t$AZR!^6XQs{o+E0#Wm(+P4u98hrDS`sl4MScH8N z>CL0fkmz;Z0YejXFkcBiaJ6FF-Me=aw-Um7o||A;I}A!=`_reUrqEEyn&dQ=p~jE= zEG0{P&&8hP3T5zt^hLzd03CQVSk*l_5_ja?vgXjdaqma%y;*(AS*-&=AvlOdD~!*B z&Jqw5bh*Bit&nHt%S}3(0C!KY2wmoch_@yIY<7Ey%NbN`t_Ojz?xSEXME;t}gDQCd zZ}mWSgmVTzxt{ta|02GF(?Gc6TnUcU4^XWL=)Lzy4S>e2jzbT4GF<4_p~F7Md=3~S z_Uinijpre$2|yvLC&udQ>rq1Rpp`5xS^x-Md)X}4o7ojdP|@NE0%#*@vY6*W8A~Pz z4gQ0*FMCkA9!?WExM072)%qu^G8NB>Xnp(Va98!Vi%j+i(@F5KFJm9T((<^-x+_7C zKESJTTf}X%uBY2iP5EVw<>b(3R>c1?!(f$NM$b7+41M-ZIJ}_`>v`Bt%@PfUP*usI zS*E6=!%af!Vp}Lhf-q^8?RkF6zQ2GVknbkOP+}=Ua!3TWUaAs`(%b zHmq;*oM>Z(;<+pYUsbnyeN6?eLGl4Zsa4g%k$@9`^FR?BFOr*KVbi{}yB>Da3@Uvu zj;C*6ZVsh7#W+gSKiy)9}7}8En4tE8NDc7O@ z+$|C=(Sa(2H@@drZ%5nVMmMS6biST$;9;IXEzd|E$tTet?C?QNxq%mat%r0cj#dqN zab3TDT?A8?z#$`M(ItC?F7_|{>a(ep)`iok=UJz3y!8D~L!T@7(M5m*R_}n~{ks{^ zGZnoNHgFDWuXF#-kp|VjM$-HY3C2GQh#pboG*f8nh-}=JiH^2llwKOM*|fREbaW(%u&ygFLJ+(bz!I_K*bX0^q2Jf5>8(tkKUNi+Pr0{o!Iw?V zKA1(3*9gN<4d9CQz0Bus0HVb>!C$5(JB+)QX&2!fiEQhu@Pw5 zmBjylE#l#XGjH@{i2@Jkm2YuL?OeV2gxB>pV^h$}taz}`{h${j0j_ z&z?Oi0)ux)&dIU%3M_D^rH;=aG7R}RR`;x|iUlL{p??yC1l}Q#T^Vr7O7mxEZ33f= zP4_v4Uf!_14NCNuc%u#9Ss9GaB%|G*sL84w4ZvnmSU=!5Oz;G3RN%1mnKF`pB)fO-{7*zT8Rn_Dw?cJx*O9DYoia4-woa!}q)(V`J^xoQM{>MZg;Xj4N;um3OVK zLx*Ah$mxfmO4H>;E@OkD0nCy}GJwzf)}T(IR8 zU_LB}$EmP0$FBs(zzG*cBpE<^w_N(LgZTinQpHLG;%c)PEDU8!gPk2sF|H zEnx=6c%-e2I;Hl5EkOe3ErjGVIrz4hyny!NBuTMbKvsL~`&$Y?ugEK@suZ8QF9d z-4n<9kWUfV45lCtV3JNB`#5$QQ{juqk;tG3@H#h|#@LhT33>*?`}&z<=Vqd`J|PEL zXyK!&B0GMDXiq}}9dxD5?db_{Y%=9RF zBq|&@a3CA@f}~%*p=n5KOx-QQUvA##$xZhFZkNg6$oWW-ctXWGm{yzNRRw(@$&XUvywb5P_EUBH$(_>NLd+^e4t6@ z=SM=Gn#i*v$jW&e_a4#kJ}I`lgP3vwfaMb6aUMN)5q&~$@;FM^j&$FZPb97nvGhZ| z4N_2yt4X$*sL!ovYwDLcM$Rr`4f-iUgGaCZI_$mGc{7$lZ~~9$giKge>g3oK%wI0; z^ex5i2Z!I6>cP70#-9D(sYe0TfCo^Ds+ zIBItGz1(w5>kM(~O~?}VbOSJP@UM6(BiZh!)^eRq2bCWCL_bN(*bY&(OmoDLfeTEH zeUBb^eG-Z8z)wb7YVEW`prR~3v+NydckEbxHkn$!Hnda}21 zUt?!O1GMk5!c=oU0|7yjfe%JEVGN}yYvE3$*lNSFwLE>k%q?`f+W<8ZruhUSB|5jf zyxdP84&7*>hY}ybI5~kXAk#F(ch)~Nl!v6Nh$^{yCZ!sF6oM7LqgAh7y=v`{qg|Qj z5*1GX2VxCto}S)Q91BsWJO1$X@5v`RWum9r1GwU6r+p4>b%C1Z_o8kfNFH!VKdYUv zyPG5F9$T2%v0Ci(VI}LZr|y#QhV=jXV}W27@UA|Rr(C>2&n|&@Ex7AcUb;y+XpJQ3 zNR@w*cVLDw?y=4MdsAi6oBMn85q^^R(x&T4S_|=uVGIb;0`h>ZuCA`(7~Wf`yBc&d z4A;$b^bV!HHv-u4mz!Vyjc_zC9i#eSLqy;~dY`rJv%@ah>$Yvc|J2`1rZ z+2{A>GEoX7{Wj|Z!2zSs8s87btS3rL9a*=b&0?`FK)Tt$RZr_zfQ|$YDDD~|&LB}o zurjO%tFlW%9DV~l@F=+bY8%}-84Z~{E4g@>q{j2DA+GH5j8&lf^}wSm*p-oy@ipXr^9w*k!|K6-3loj3i5)=x zl{AHggrYU>2E9f*b^`*b-ckzO`S3Lq@GrP0Mq|CUkon*`&1tlMmF$^-E?)yDq;dKj zhZQo>B+*S5z*M-HMcW+v-H1ILx#m!OYweEmT#IT{XRIY|;X0N&w5!gH*y22yL9dFG z_Z{k@);rJ!tBb8dw_NX--ZJU!{P8y?d#MD+>4^xwH-9z|FTkWB({C8TP?3&Z&uthf z_7-G;4ret&$~N;~9fCyUB)6xLaNv03Gx_ake8^4kcfWv06XiGXibxsB1C>zO#T$(7 zL@#O7N;P)D?Dirwf_|$d#Zd&5Ff<^Vg?{Epoc8LmtPx6$%v#;W9|fNR)bAY_7}&00 zY!p2)rgrk=z4i_CH5aXq@S*N^SbEBNvns_@FIwm_*hEAiKsuX|WWnzHCpN-t5<{?J z|4;IJNC@9!dt9pVx6}rBT!z)2yE>yb^WWb^;4`9Tfvl*VL&91MDQLa~1eu$>Vn0Mr zB$rI8Uj(~IDhy!5Mlb3`rQ=c# zUl*K0vAj=d%%6f+t&$b@X0HQ*Jpqm%tx|#d&Trbq$2IaNR+6hh+objS7umk zjRg5-{?m59nl@(JpumEjb3hY{Z2%i7%*O#i;zfPsrG7>SPQnBdY@?^dz#zzMUt7oI z$OglQ4-_{NQXUY4R_n> z3O`M(SW*}M@YqWgM<1&ZTr|x(62~+=jB1Tdn^Z!AtgMFLX(-N~LlqQ{>I7XbKagj_LVIq8ANuIRUMd!|V&MfNwM zK`?`4xKLfQM#lE?yqD2Ci6ZSY`4!f^27AZ4Uttd^j3N0#BqPozTjXM~NL8Fr&+DR) zGd-DID!{Nx3=NPJMwnx8R&thbLcXM%62b&!?22jvSzwRpC({KP!`{9ML?q@lcw}{ACjBz#Yc(Dqx%Gn{fi^p`(ae zg@4&D%g&Vs!4K1aGbdV%Kh)lw?&Dbz%SdWNiZCiakTHMYyzIqipcx0*34FHobJp(K%Mru z9UK9Y%8iUgUBh;gA4iCyN(xo!g?BJHkEUy*~POdG34-gc?ES#e&Sabi9E= zDRG-;v#{ju4u1I5+=wK#(FrF>Cr@-U+#fX+88PC5CJ&b_>cB7oiBwVYKfGaHY5%(DGjgzh}k(L_PjR5h@L3c_mJEq3uTmCqzz~aoty&; zU4Ks5iLCOP9p?_yqrt9B=y{Tn-{5siB^$KTq>8HuCCzH*NXDlHge)E(p5Ns6!kyWv z4mnVNK4|sYv&;p4&tCX2!DYk)S|jIZPih1WJGPumrlPu2>{mf%F$fV!de#Q+wSp&S zGc(@NDy%zx5b|YBQmgo<81D+@ChtLtL7!ALlN7PYrRHY@>Cs1^I=rjQS4DO$pQ1Bzpr?n~$n=t6fPl@%L!3||eB{_MzxzYRp5O4-+V|}Ny4+7r zrWBj=I(L(bG88NcBRLayX*COR%Lrf^?O<$XW`;ZSx=*ZgVR7iQMS-s;G=C9deKu0} ze0Bb!eUR)2h^5~mI|o$W!G7$+O_JrOpH;-wRFo2>7Y{o280os9_AI9{qnVXN4#_~Z zNmL8BB6=VlUR5Ddc)!pl^Jp9>v^$tpXQ-fnN4KI@&IOb>XN0z=JO!?sT<|VCJDU#L z5dajKvVD0bX(kOVklpwSeH4VVk?LSl15QvXGDvdL5Xi8>$Osk%1Oybp7`JHTO&ljy zjnvi)l{ugUP65$b=alq$ZGvAQ;Q$R!BvwF3$W_d!y4~-OZ?ynbq7#;NDMoA=8N*p} zGo*NmxT$AzqM}}u)YiEmtSKPHcTf&g@{nc7(XK&Kj$~(!JJPaIm3jxj0Vzo(>m*c` zgXJiM2NwMJ6I}?-=+sfihPFv(*;@taNA4t%N>UW;B#BH297J{MZEV1TeL_VISw*s~ za0^`tWQ6$}NjCwl$}Y(n7OTqzN+*o=?jebd$Rg|txYUf`DkecS3;tAc7f>oIcX7`8 z%N0sQ$=jagz!{oqqD||j6dg-h+C;+l7iIA?YHf(Me}Ri-os;N&i{K?|4T6ru7eOOC z#r7wVgcPw^(beN}rm$%JEpFQi5nrB5q&Sd;F;aFiT>P6AQ5p$lvXf`Jr%2?f2Q>2WU@JL)I825H(1ki^6)Y~wUgrgU zWz&;V-I7wR<3@GLwU9@wL7Ps9g!Lh6$_BBn9#BfLka&dM{iqI8B!$1hpJ5y)MvMNA zJ~lk~kf5?#Ge3o2;E_W5mFTgYL3*@iOcNTsa3{ckf6*IGL1+F?zCMQ?f{@_uhwql> z4QxReniUy3IHxclVyksN43a{3yi+HKdlHCOwasD6EcWU)9@>~U*iDdC}B@DxNYu{wi3>3g0eChMb4#b+RyDB}1km?^Y-%5O28 zG~$RCqOZfT_+SphMpEsNoFzh%dn8+gJff&BzLe19I4L%9MGLuU)=h`0bf^GfzUajG z{amu~BzK2Uch7j>Nkh0X=pet7ucP$UD>qUac;QQLmZ&bd!$PiS^mHSfepzD_(ESNY zudq}Gg;)gk*8>3bx<-tCSYND0BiENlC}qyTJn~7&RytBUdVn(B69ct@K7u=Mmkw+d zv6}4bHP9KO zySehLY0{|J7MOZ&nHN|;G$HL1S=%;o}bC_i*& zDAER4v_7O>EaU-HBQb?*;Bf_A`g`$P1ZKC+Y_tOgRGzyG&76b!jmnUqzQco>?#F*J^zcA9 zwFcl#vF#@7leeff&@U}8TxB)m$U~{c7m>9B8}=_mJm5YOLp3u!{5LcKIjTq0)kp3Y z0YOs0h4pYnPwxJQ+Z+UQM^fU+1*Yv2P5Kr|kf(_0pd2J?&JJZF9bRW__7r7jNUO5m zzWpxe`g^$^`11tQl4$eVqX$U(VCpa?%%2azmre3_DeHpgsLvap5o}faSiJ~coD1)W z=##3|egL*bQ0(-=KSVhsp^R%+356D*%_xFqiF+E_@2g4`ver=z#{-)?eQ9l&_(?;EERr?<0_0o@L&9cfbZf`gt^lK~7!+{R*nPhDA zHezFAD}sB`RjoG4aS~?*nH- zp4^CWZL%Pa;Fms6IbxX6!CmITds1@`SFGgItZs@@XI}7yWN-BEDKXh=9aUBR1yy+( z-7r=M6qzXZoKb23S2A@_+69U|*m~LNK<|J6Hj>%f*VKQF3Z+Mn%*>xWIvQf~Hhgb4 zLf->L>vlt`UcM-8rRxPzN%Wsy;Tw3F{$KPzoHr39U2pDH)XpD2*_1bt0I=%y+zYHx z91tuQhED?7mo(!I+ksI3^M){!3j)qXRk0Byw>jq)Y3Aemln|puba0n0t@K}XKDsf_ z1~<{YP{Z-hBPf>o_}>5h6JOow8cdGi&S#|(vy^iOnoXcOYtB_)aj})pUZH*mxtaf7 zBaR~TNe~kjbUr62_xZoWk+0Z+dOu_-y^ojLjhciOh-zx=VUljby9(!CiM7P01g;T_ zRw)nL8Gw>8xBZ)=o3F?Sq#n^kzFgZZ^y zcx?223b$60&%E>gbELz0msXaQ#p_Vo?%RXYBVGQpbGKhkl+1U6g{>UxU-jOFNmP+x zGu2KpW%Ke1C9V4DyyKiFQ#v1I&a=5vb(B)#!!T$}`8zS2x^NDa8~f(A45>s5UQ&HU zzvDxnTBVZZf-g@r4>5@zVtD{9Nyq|4`n| zmt|?z^pINhVUW}GWAp*?Ix_n<`6SUZ`#rxwz2yz#EW*)J=#24#q0j9}ts~st7WVgc zXHko@sX-~4oZJ#L!l>cCM&W&hyS)O3FPn^8D`xJ8$Cs zCcg*P$l{ux$tlfR07F|4q>3PCK>w!dj@h4tX`akX7OjeXA7q7Vv%CE(W}j2Z(9GhA zQYQ19tHcv*8C~zfq*mOtZ#xCHsGXA7jZqYBsFuLOqkc zk-8qGgrSq{6YxmxXZ++{`uy}C-hmG3>ogg5si{ljSJrxGsyNm$o3hAPfof^kscS{y#ufCVSL5^;uAY45VQ!n zdTVaq*r=3ZXpngHY~3DxBTIF5fytjo0d?QJBVl&w_8`;zT?QgbJKNj#9#a=5-8$y3 zLR3;?PF>Lgwr=0cw|)YFz}Mj>!xAd{>Tk4S59d=pfHE2^RKUTGL5)1dJ|x(m}%Q#pXFDC#+OG zZb||*Qf9XYx1L(Ur9r;53_~V|V z6I~OE>WfWLM5^cPR!R9C5mboL$vhK1n@C(qW`glw#(r!y> zC{Iq}_{pi{yE{BR<}a&BC?1!clwNr#!2g`ckyd!9*ILtCt>Vpb9?J3XUF7j-e%IRjSI=4V^`>n)0oOFFf<6aYLw?$|JFvnn*wZo_aw ze?_L%763lVG3GP1M#8O6pL4&$AX3cRN3rD7%-$gT@!aNMc+#I$EJVCXTGDo8^FgVY z*w|ZJPxVes4NM=;UakM}^%^;ga|7{3DyU!ngzIQo$0cbkY&^HXo>hvcS@h*JQ6G5r zYPH+9z0l3)FcmHFXb`LB{H1BKF#z+ls-+dGspL$))UDR&w>7SQT*0Lw>X>;0)oM(r zSJ#LMLjM8r-kebt&BK*8;4x$c=$2SKUisLxFr_*-h)gnXI&obS!*oK!cT~4HQ)(ds?<)m#L zX&5!YOSHA8jTNK=FE0rj|Ek}{0xY|Vzlo@(?~4IXIa)!V;t zzTdvK*Df!dWLsQUt<7F$%=Y!L&YVT2;eaAtzVF4IW-*g5U*GxJof`Fs!aa#6nGRM6 z2&s71tYGn7y)QqO8q~oj6zYB_SuCmg`lGLIakK8hL#SsX&+vLGLmU5p?7ewBly4V5 zJ~Or`gbLY;ELjrDzEp^^g^Vrx7RHwBdqqNIPqva0W0@iQHf0N;)G+o5S;jDfjAhKs z@7Cvep5OED_mA)Qujl%syym{|YdP0B=Q`(oo$Fj>Ta}6PsT@GAqvC&CP_aHezg3e(YP+cm0&(xx;}eg!`G}PMD=QLFc5Mt;$d2kcs~sKf3mkX7bgS?6t-&zOReD6# ze}-G{?IZSATv@X-xqyQfOx@M3!TPE!MmE1IOSw=DlK+$y9G2LD!%+IgyZikRbGWqzxwaNN} zWgz+>d1bQRzl%($vExQ|*y1>MPh)-lmCGE}X;`Q#yn2i`@G~=I z{t4HCsDOw_0_)U80Gyf%3jYe=E?PbSp2JWW9r%teU+$2sK2 z9ki}gcXk}OL<6VihcuR6O0fYsb%E0fv^kHW{dIzyq^&l9H%kEfD_IXyQh=Ni2Yrnl zXsuNqUO8u-`r^(JU_Q5hCSq0t*9ar|yVpH+@I~K&e(lZ{HcX8K*tMSV1-bTaK))#Yh*HLyVIx3ftwv^QI){iJDK%Xr zVq_KQ*bK*J=qqjCq(na8aE3-nZSB^+bf5Q&DAH=nOmym0KwrbudZ0_Il9aGlN2}ng zi~ns5Fb=ATl++$Hc1^fjNZ0&|W#(vBa$A`c5O%iG;pgXgEG#T5{OafP3om^B+X`h> z+^o4J{-xj+!F>+`BgA!6*2AzUPDk`>X#>X$NWmF969#`!bBdQ!T(|_mQ&r zSGlA1-*tkF{yTXb=o;65r(Oen)A?`19(0A{|JJAJb5`O96C*agE@}0!${*L0YHQik zo=X@gc+&a`g9m^(Yd0W__`AB#gqgbfd{@?v5Ut67j!94g2>2PA=o6y(-|sHX+M#2I zX*F2D3-C-O6E=+-5uM3<(1CDI&rhFPH*8*B6Mh9B9WCIdX#v;2!uIXPLk`1s^=kXY z2?x+mm3+dS(aVF%Gn6^Kz6*YL=biBFySFK2Zqf{DZlh*XX7#}jZ@b^t zz1)y3+$Hhb@|}F*wMk-^{;kmqOXB%6u;AT4X@sE**1j3-%h4nIMG=Grx$V4&-H74k zx|)%Y4UOf%k+9;CMz%tzUdK{HZpWVj_^|p94@c|Ng}&A%3E7!Ws|?b5jbW75=d5EgyR6 z^L@4=D3emluQfKI>aM5lZ@!G;YqmR0++^fl{zV@l?~s&&mQvUK9jm-olXRN8+ckt0`9$Byn+vA5?no$+q8?9>Wk3$6wb`%R+AjAH&!M_WS! zsmN`~$+Gob`1gJ$0&v!XE4x@b2L~L9{+uxWAb-fc&dtMVJfgd}c>+eF*4NjM$S9m> z9S4GweLoa^{O)sf((l(%4}l1W5u{#=k79n5qE?!8KTMI_T|Vve>-xDEI0(4K@A2Gl zk$v5WG56m?WLWTSOo?&K?9Yps@6m1HKN$NQ?Cn|?rHMVb>CDuqj&KsaHD<=%wB6_N zLQH3id$Z|lt%^&^tC%5lqv4DAnRQ*XnxZnb4lOIIay;^5%VMd^?%kN^N78uTn70RM zeEc!yK|2|Bs4{pN%>S?-ZDcSEL0n<^OO05DCS-VIeatXb2wtRM|91^{R5Asz;qOPh z{|DT`U!m26+XvBp{tKuHE{I~^r*_~%>qAPUj|hrt*!4gg@LkeW9-(qQt(dA9N#kWX zdVtX|b`4>1d>ZjZ?XtH+WxWAB#3<*Va|TO-mQk+{9tJt4Qv2Y$P(OZ!Q%7GQBHB8f za+zZVynPnB`e<%d?ZM5aM-M=PL=rB@{ORAn8*<_B;#aElsFL-mJz|l!_xpeDw0il4 z-1%zoBc!#jIcojAMjyOY{LAN!;P9X&#y)lnz1#wZj_Rj&-&-oU&~{v|P9bVls!g9Z zBjDtm0*2voQqe;gbVlX+nczkW+M17F>z;u1gEOJ1bQ}e3Va^1$O3=fABOA)xi_1I0 z%02(~1efN$KIOIE{cqYphx&_O+BXK5jM@J{wEl%NP_@&R-Zf^2tbad1AoV0bH8x~y zI7gF`&CyS>ZpvofF=b<#ia{s;z7lJ(Bf)^R@TOId6*BZ z5k=aX38A`LNbWcYHYSQbzKoBkJXjWS|Bsm+8?Oc(T7t>GJSPiM|Cv1m#2bb_YCCEY zbqVQ#`|q|3UPYNRfgBA;mL3|5YqPil-2I^Y6wRk&G!6Jh!8s8S2!D#bvVFui)abWk zkWElXP}|d*W_C+Gu`mC+-5l=^cyiD=UG%%P_52EPD0gK{)Q$RvXUJ5`80bs`btjI{ zc`s`7{Q6Qr2_4|8J-E3eqtQgA2BI_J+wiix9=;FSv^APGI_jO)qioq7B4Utlto{`O zfX$KsFcVp;J02#sp#DHvy$4fy9Sh|4We=;VrBsNSoNCf8X~87sptSpqWTG!rPc z{N5ePTWIGB`THaVt#_8?GtFyixxyD9C1&_kY)yym>DZA9c&>7q#n$1O5aZMTZ093n z3hmmf4>I4&p5tv5sL?cSf7jCHRK^1Wy&P5G(?o=RTpb^DX{>>cLu;ysh1Qdx&Ea6&(%7b+kw6=I^46-G#R2o!SeY|3B>ISXT-cHNx4ECp;73Bxc zuQ9@5yQv1~!8qWK@0#$Hxv<7?4=u#A1|AX1y4`!YL$5;N=GV`?mnwa&uzMjE-1QOm z?2#cmbjSH=BIpnq|H!|Si>dXi(M11g1y`G?jrr#tNWJPj<_fz7HmBH0y4yw z`>gNJ^A4t+Xq}wJ2|;%iDX&7ZCymfro}q^MNdQcP8ODP;4$idG?NuH$zZ-J5$-UcW zi*No2+(3U+q`dvQ@*#Tp9axv_sj_8_PqwANz2)X_K>Q79elUp(dErs51M8tX17Rk_ zGZ#Tjj%wyWbvdS>XoDbsYpz${Wb5|=%l~2qju(z#4n)^ItEdkL`(CteYv>GD8323$ zphg#39KLKQ;M%iZUUWI=7=R(+Hqr3+Y)D6wis<{ezutO*DnR{(=E{S;151E$14vN6 za%xo2ShqC*f9zLR7#FK{Lny9l5z$8-S4)NX#|E^O9$X8e9zh0a1}LT z$A`Wq!fB=|krCwR(cBasurpl#IA!I}zi}7G?NhOIUkPY* z=ZCQzV$2LQs`8*19faONb5}$t%JtgpEaJ-1x@+s@Xi;>d2U8#j1RbA1lh2M-B?p%r z7Fgp5cTQygQ^I)4kuJr!AGNn! zbGH*SpVaAr)~oP_)66KF`YzFK?Ub}k-zm!|?;U})^$GM3TjKx#?NfhMkFz{G_96L! zUe_eKkuR9H)BA}WyJfMRpEx-oVPE}Q$J>Jg4k~ch)|s_YoF9}>sQTp?>8_RrFug~` zDo5M`h`_p=Hsf19doOBX)P4I)kr|~u0rICy#=Y9S3C6{%&GlX~<+H_RtMFqN}e#BO0{flmoa z^wIS#t(!~g3;@#=urOc|XD`816{!d05IDhpUR`m`6K#RkT-{IJ6oTwsT2o8&(1^po>n4bw^;_3~Q_X{h%{(qwN1;!n{S+f#JgnQc z1a>3y%RrGkKJP$>BwUp33avo&tDkALPlt*FkZzgj6`)U#O3udmbIZuB@3_O?y$&Df z(B2iYLAd2>|88N8uR`st$9h!TK|k=k$*-EK9rV#$i~T=zsX7y@6>^*s6T!S~`@|rh zFpyeYWv{N+`Bd>=+H^u82oU)BO|+EW*)@Q?KA5W!Wy)rhHJm4U@a*gfV2;8lRzVxb z7N#92cY=0~xm0DWRajoB?4((+dPIgi;C!l8zi{#{p*}mq>Ag0(N>{#a zda|wo!&fB81d?pw)K4$3=U^Y6x`tE z*V_9vexdCVbCPH!`*ihP65YL3M#l*8HTqpQwY)|+c2EE!B6omk9J%9iyp($0b2Bt z4mo=FYS0lkc|2MVx^T6)-1lq{5bCy?l}5;ufanrc`OnHz-zlsNhPjpwuau92P{EtS zxC9k4)iLN-qV<{ISJ4xJe_C5q)&JF3{iD9}y#*Zt-9*j^RNK$^TmNho8wM)%I_SWm z&h+ht?oc^uVIeW!5PW;BN6jHvrybgThC9gcVqUpHVg3)%k*U!kmNfT&dYW=H{ z5qI7xsfz98mEB}?;lj-$1?PAI;77rkcOog98yvkDPfZ8P*w6ET7E&3(IMc{*@4jQT zkH1#Xpms_CHXM68#BYbBLM}3GkM5RsnY6XLs@K_tMvHj-t?L5$Xd#<#u!%L>dBf2g zTe#SU`-=OsLolh?fTvz*Lq7EA;`7ye&vJ}U`5V!FgHEf?qgqI9^s!c}L)FH82~GNj zjcLI{JGI7NAp~l|Tyq3puwq9@J2DWqL-(?{+*e5CSnEIs4xg~R{}^pei6L#MO{Z4i z7WQ`EhuoGp|M6StZCMCQ(v|BKW(<6{(U#JQ&f3?mdrInp!JdyC!P(X4+JXJhb|y|v z&QSunuVsAtiS2M+y}OA@=g2nx>F#Ow;mN?^!dj2@`t?YK<7(q=Ol>w+4~5OdC~>Bk zFz3q%P+;+KcW@?hd5U>OP*k=HNpMsSK78uD>=_$^AYhFgjn99-B~ZY^pD@FBW$hYP z8P9)5tQ8{Vj@f`=pJT1MhwZu$+v5_BC%+}w>4`z=kRGpY=`u*r6dpB?7Yq};Sc0qa z5~K9$jwfF-Uf%u&`5GnY)mQXv_S1%sz3%wf{Vvr>iKWyS*6!3@9X!=tk|dD$w>&gp z#tI9!C+mY^E;|YdTl`?GWQ^po;!?~(25J;#hT?H_ zl5UPZ54&Nqyp6hszo&KD;KA#KVsk`k*)Zu$Afc*=&i)$L#)TN|IM&$bFL#?At?`Xh ziJKV0P8eSBw>|a}K1BMtH3tS_#iiy^^Qh3}K%P%ct241Gc2k*nGC1wSvi#~GJ@y3F zmbXEGA@a1cB7w`qJ+nGZ!&eOY10nd=BBK49?_Q zNy!nedITLrYx*!1^;FBTha7I-#8c}lb5IA(jEcUUXGyL2HL5#fAfaEaraZ*aMSisP zJEqxDU@6LEbY-v475INk0vd{&AnNPt{8PM^&caU0dYjjmZB6jZg{Z1VeaS{%@t5#t zAeBr77DRX{Ai0;sLHSOy<~r&(ArW+)41yxXb3SU&^UDF)hmHnUIO~VtTGp2BX<7&^bJ5hm!9ATqp1vrN5ESXp;yZ%CcR0oijUY z@qy~k#rNJL7$yz^?Aggv8Vgj_DW6XisZ4Y%0b=RQ#k|#$+LkQJ8^gud`T}+UE(S%j z9_BU?JjDD3{6SRaVU7c^Em++77VdjzA33fIdFz2QBN#Ymj!JV}_#9Sn+@AgtgrvQj zC45w5;8iOi9i7`7ij|x&XpPh9(-&fxAjMwTPFoOsJ{xUx%F<_p5sP`G*(!eAu`kLY z>DHHMFyCU^F?gh@n?sNNLyrJL<$)FaDy1-LgIL=0b;GE{h5~S*+vei>BNE>Y6Rk(u3Yz}sGwCrvH5bcE+TN4 zJGNea<1O#HRqeOM~IISEDn+~=__{8N6< zDT3RVkHJqhOG0@AIhHiJr4wh!Usv}0=6Z`*?VUCPKW%5#gp+S#0zYk>QixWdBd-@7 zKLqltth7ifmb*HPiVe2Y9r7AHY-cd|_G+#yZcu(B=4_9;U&AXm#J0g1E=0CuOQ6_u z4YlB9TdP_(-h0V*e6Qq~;B1FhN;KaPEPHCGZ{KdEo#G%Q!g)O7)Na8{7-&xeI{o@K zoFD&8wAy`>e}bl&i>g*}5Tlj;=0&NXOpvZKSvj9m3EaqS*V)OqPN&RT+knbCR<*`; zI{eL%@tiipz9KzY`fBG576Xfq(!rX8xH_v(&(u$#DjI82HP~emG}xba7d?F+bS3r{ zCeU+vAb!M=i$CJPclfgs@{j|&mbyOZ%Z@cjU8kkACv*HQ>1P(I5?}vD{ZL6itfFoTW^`1t)iRLqwe8@nPv3cveWRy5-VNP7oD)vD`sy#Nrj{~8uDd! z{Ha3ZY%OX6)9#ETxSu7>lv>$6w8P4F*F^p_B&$``-7wRF$!iOu(RB@$aekn#2l$X8 zXxBLHH=WDs)6-e1ko=FU0v<1)pT2tFrBoagis}#{+bhm`GzN`6mHsQE!fwP99ZUmx z_v_>DW`T-&IZ?96C$lAKdM4{P9k<)quB9d!gM?x&x;hFD?Vp^gmtN<@Jc;jT?Y44_ z02v_CBQJv0pT{FBObB-lH&@DMSR>_Y=+5QgpU@&SG{b(5=H6w-dOKQBlMNrPOu9RE z_Q_v}x#|qAGz8ypM?fBt`L?^c89AoLwLN#&~F-0W*9 zBdPlHpbh9{wIO@AF+#6HkPS z=>8o@D3yfDQIa`OzA{-2%K7?RU%#%QhZYr{!<-YjSP1IifmVe#ECg=Bb~D`jgKEB? zimBX!nPfQB8htF`L@_zulBNYmM~hS?(i3HnbJxFj_P9?{Q18R|Qy{FLGCbSRi{>Bm zFioF1Qllh*Ia23B0WpW<&Qoe&PnB9qmEBxlwCz=Jq{={@^YypuMvgH9`LX#SkiBct z`}Ht}^Gl%4&tmU&d5+(^5ysiM?AOVT_qMJ~s#>x7gY@~R!3s+sO#h;1%8d1~iYtgo zr_Gt0^c)`!+}Jg$P+)H7En*H^$FwK^WAuFdKqhK^v2^S2sW69xMr&T%mzw(X)4q$7 z1AZQjmihy8#;g+KcB=9FPRN91B5YD?n_IO}H zu_ZAP)>G10CadiJim4|LEc?H{J>p$}F5v0_e9T-d)h+0@Y{1Ug!EH`hJw5R{M(2fm zO#;TU_0a<;-G~A>G7!trM>YTGO|)>|V2^zMpr&nX!k6*P!$0-XjLy4mKP0Fx6{nUQ zxt8EWjZ$NfA6@YIAsx){m^oxG0ZgXCGAXjHqQojIGAF4~>L2No!JRo|pNbGoYq<(^ zMkoSeF5heWKKRn_nkyLq-=1U`dv@{Pu>hn;?-FrJ7dcU6Iz97Q$=5?4Cj_F(w?_%O z05fSe^k#@BZL~Jpfm2RsDvma>5@Vj$h^E;bWavTm4zje~xKI_DF-;SXbML?}#5TIf z#*Qbez?${*Kph&MT%BsR74$?CvovyMFxJNLJEkl1XCu*$ySygQ-#=;{NA%hM>8ZFK;*wH5758z#G9Et?Axj*@wsGHus_rUi@R3 zl^R~^p`DBI+WKId$%%5=p^Ls9#5l<3+313X3`pui_MoVR)RE1GHZGK&%QFsL+E~fd zyAQW@FNntWkr{VxuY}P@e3xC7(fu0o;dJPLD8OGQ6;-_6yAE`r+x z43ef~7Qgfuq=P!td#WeXLm;7ASP9&Y`c$gunk-jnff)~^z+|(p`onvA;*~995K~jv zCU2`MIkzXB*Ja&jC)>Cx14O;$2Aooh-ctayX&ppj4+;l!;+}paOrgw>4_GYjSN7G zhzW<@ZQUYfEFFU7zIkEsFP|{6SXugecK)<2*obN2Gq1PhdhZNP03kjL@L|Y<$lms0 z>Q!&$%bMB+Y2U1z-2oAt`mlVVWLQxEBZ|MjuOk|}%M@)Glvy$rm&vDWKL~EjIS2J4 zhtoyLWR5tFZ8fX8>yOXd}Bnm5^U~L>#x0!o@NSNP#0Qv8;U^BDVGb&oa(lyiVKl9e;fr z%aH{Ve5(a*E??E0#R5!nbz8>2rNZXXkVsjF_>WrTT!d3kF3FH*{Q5 z{0--InJ)W88CLY{OM<0S)<82b# zg*cyB^CY$#^afN-_J~afkFMBGmrTP8g-;g3%qkJs_BYo5;uH*ECOa#FI<9Hw!9 zoIu3qC#E!#XZ-4GsioQsy#eXBrGf%A_R^4r1oW-q4LI#`9`A7mKLFO$u^jpi6{61P z5hFJ)e9z3NE>lKbRoozQ&cxmxH9R8=8gV&2Ef&1LtBv@b-3JuF(m229b$k;Y7Cq*N0N z4o~HO*meINcT5|B&Kdh8`3~LhjMBvfRSx$;lt5C;d%Oh4-Cub8ppvGmql+keL!Xj{Z+QRvFW^ybTn6y;jjHCA(8}e7X0> zHos~V*Ov@GS5aNudG;oNeukKvah5G&|X%-W<2$>EE5JPwixLx~sXRoW_&V9A&@0eco-KQlod( zA;r?@ZVBa*6=bjYF-g4VgZGw_Rs3`@#Nm?a3!V4Q%iqQkrMr1wjfw;kX9(=5;bv`Q z;Gq@XS~Wg9HWSew9JJ{KGh4|x;-p`w>~8Ux&SV)5S_t+M_SP$tqLrtV2E`sRC7*cF zY2Ez`ITFFHSk3m~3qHCOW&t1JoTi`bYQ0@Z@@FT^1@`n~3P^}h=RgyM10#7Z%#)67 z5HaJOrNpd|o%zg!TEse?^jvO+Q9V{PSkapq-`1j$b4*!G@*3>(sGC(>N=18}e&Ms90;q3wZ0FP#!yh$BJ2=yOq~7?93hy)FkTNRomu0lG zTRJ`doU2MoFOlJXSPA%e871?tQYjsZ=Zoh)E8`DoP{*%nZ*&qWJB&7Cj)yh2F_N@W zMRB@)go6HKdUm>aI7-y^SAeVMNDV<#Hj13 zqR;L$_E#0QOVXlpVqCO}VG662-JUc2kOfO!y9BI@|d5@pF_Iq)sFu^nS>JQ)Wzc&xUP@ zGc}wIsW`7@)crCfKT-5|(HO`0b*moi3}QK+f|Tsr^}{Ov>CzH2ML(fx6L-j87CHX0?Dfl|QZP(pq4%tvZYjNt z!3SQ&pLZ!$Q`qH2K#XJeu2}(IAWbfVlEc%aM;czW4h{*<=q#GyVaS8163suo`5>y^GU=ktUC5pZ#N~i{ zRSfi}E2H0@HHo5`?Hi{)kMsX33oQolqFC;dqlMF${@kR%#C*W+; z_^a=QpcfCAy3dq=~oT&a&AEJz*7Z_RoS{g0|ydcHmvA+Fqif^!y1lG0chv={rGZ8o+qMgdX(zoZcZ_Cs}oHUmq`;=3`pTHP857pIOEaqv83N@ zjytiTwN{xgpHT8J7ufpy9_)1#mqa^+-KX;v-nd8Pgw{*PGay;))6w69Z=Z^gBC8|E zi<$RwhE5j)R*yKO>|{(KfAUP7uF;ZLUxq|d^e49G;;~xK1f~QKUcI`uf(AG9jHW|s zbw>r;ij}}^EJti1?p#f%apLMpMw|;^mYg%>kFXSp;|@=h^3G2&qS{M1X^nM>eKb6V zf69sap%1vsC!wNO2bYI>GmPH)ypSt$k&lGhaiaP-6`VrFh$6K{SN`Chikj*fqM9!S z;O`hh_TW}-m@kVcDn$jn;v$_s5;{fSyS#aI{@@Co6n*x5+c$PH zMR&HdAotwHY$!nPZ)c4_4##NS$#2gdR@P!54l%N~g@APYN9FFPfNm{pXQGUPeGUs# z)eUBBU{qSu+_oo1zNviOcse7W9ZdHlK`X6RG}h#kBy%BC0sSG*-kF@rfKWX$hd;z$ z)Bh?oz|~on{6{R-FJ7zP1*+$eRQ*Ef(My&_3%gzO&wmRSOR0lDj@rlbDjEWT0KP!Y>og($$@F=_d`ZZtF2I4){H?w$Eb8k<`Kr#jc4_cr z->F&)x@rT+-W-wkT#EsgrAqXL-89@Xv?EA`lA*kJpcp z*7z75{_*PMs#RLCO@n6$e}}1AX678=H(; zwG!T+Le-{5rFPRaOc;V6cAxY)M+Fb5pj6B0{5Wodl#)5jPy4Vn+zn695%c|>Y|hy? zn`A6jyfzboLf%)wWSL!v)jENXx0o|5{-yba*v?~-c@N{y9dNaJxhbp%V_o(`He;Zlp=O)C8sIsK`xB|eeKzVXBwURZ zCFXkb&u`Bp>j_Yj38 z_5MbP@sm01+L{gw)c|AsWg^%r4B&9rnXzKRpS%Lr@Hd0rnzJjURm2n#RNDStrpjDPvXgSpb!ODnyIlNm*|0S>uiR zBY-Q-@zxjJ%Aem;1U7ef5R0ZtOHcO>cFuTOUgV9nXinLqw8t8qk$7v8+3s)~Wb!tV z-al4Bpg5vsA#gd@t<9BD@w#Gig?OxNoR;Z<->F=liF{zQq`s)bC;jp);PjR`OL3ps z)L{LbvAT_$I$ZBWUAh%ciss`qcXe<585e>ykPW!{Vv$bghy&7>w zw+$*YPqxYrb!O-l44Lj7>`(kT|F3m9yAm+l>eCekY$b_nR&FlO-qHKpLPp7Ig>?8r zRidVJyeK$~9DE&zQUlhlVo1T0!tn}6fk-s*z4PF&9JKRZbZcE)K>1@|@NH1zg@VMS z)Tcnh?8mtjJU^T`9kI4?Ve}ri1B%ll_`J{jJ@^+9@Sz=+359qI;BXUPl)Gj-}tY&G$YX$T*x?y>du-#gcMMKzWr5<@Z@E z@BKZ~O6!OPg2zN(1rxX?qdlg^{Ll;XFQowPJhzV0RwJtWDnl{#>$=6 zXEPBDa)C05{aORiM7nZ1aU;myU92mf!72OREt2L4IM`U|!H>3QntEbsP1Gz9TMQ~@ zRz)T3=X2|Xm+z94j08fHt?6SpJ?a34l<)eE*%9$})5()k1s_UQ-iXYL6pHDLE>y>b zZ;QR}&<*~<7zMKTP~CXlV-LA z=_daz7_FrtUt**}gD$R&xFe3H3?8;E*9Bvp2Ey!D(v1H6A=M-<9s*c?qjOJ2h2u$T zz*qB3y_o`y%^kwa|8U)DR;D7cA*{BE52L?O!`Brs>LzA%Ve}=`1T@D_^CQ|+%3E7U zfn$V53*W5E6QelHu+=M3xD16!-5A*;QQNUdIBvSmNd#kCb)H;`%9M_+O?o1Ud9= zPGoLAS4gE7bKRRBc6b{(^48(gcuihuOdpz2eKCcsF%TtNcbR(HyzE8COT$@atcjz`Ba6T*9nqbS zXVkLLGJC`44c@U^|FfY`f$LhVOKC0}0vCPCxv$QGVTCW6Er|{$jRFK2Us$7sR;24h z@^(ZIcjw>?FV@f#$+1S9B#~ET&Xl3MYwAs$q^ZHlIhoO?_q?l$K+)h1s!2};JbUKi z-bkI$ZNZ?m%?n$U5&|-qA4fKF=A|KPCady+Be>(a^KnSqwGA{n9W#7 z{)Gc%kI%~OPp#;Qt2qDKU5bG8^^cMV;IxeP&c0>-xjToM_LFf@fvE~foT$N?FZBKh za#m$A&82TST4BK>+%o2a7i3R$PYgsz*L2Oz><4zVID2@~K~y$GNJ(fNG1WB0C&av{ zVs4v{!LVz*^QTnh`g}^GK>kU~U|XzgG_kH*ZaEvI$s6(h!$9e`eVKT|%yl*YJ6j+4 z>cl#tDd+#QhzHG`D+VX7kOci@iMCic${ht!;ZKwF{7p|hO=KrUT@Cv=A^psvjQD4# z?3qg{u#zSf!Yi^s8l9~Dvoz1WoGX_G_FV~qv(E&p-e+^6xO-{y)spC4JtyXXqK=|` z0DV(rY9aptVLL`(%Xwh&<0m4gKrO4dubcYo?PL-*QMMu(l%cU;{oMxf58TVgsPliakcfo%T5zfEj* z3==$=NN}sRv^#|!Q6u{`0(?pa`{Y4DDW4rJ7~dj^NA{gZ(-*rJ#??3o{b$kr`6;iP z{YI%5t*0Vh=$VD;2QyLW8mKWyi^XBC`28W>ke$Henoik_;FC)7;6vjI)38R_PEoR) zvV2t2dByV)#e=G`wiZde?;6QSzC?Y(Fz2YsOj>y*d%xjqM$L~dt574;SE!+kAlg&wPwyQ8<`_NpVo z#G0mmC&B@J>1Cu3>~ZV^ZXKI{t4M;M$6nir$6@7=Lgd(C#Y>RpD}4Vqb3_H);-TC` zXW6O#rXqSG&FpyqPHvBC?+z+96bw>y=o=sB;_OvDL%VIEb|Gclo1c1vy;Up)7+a*g zKM4Ku?rfqAQ7E%k)Ic_|sy4S?Yq#v*a*1<3M~s+f6i)J$bslt$VzmW*xjGnc8)58%Kw|OBPGjkS$_)E+l(yRzf_zeJ)INql%DNUMKL%92N#Z|NGg%rmDE! zi5iG@{$8bG>Kb8!Az? zc(3({FijkPf)w0H*%^L*lYEo?I|nak2#%&C_o%6AapmFp@n&m~H^Z}z8+ zk7kgjW$HTtW!b1N^^NQkooPzP6S)tMd>bLtp^EVt-lsd|r)x%p#K;6}NrAKK6of)9Ra~##JCaxdwe6uNR`x$2K$1_L^veRHbZU2^)b}mF`ef4+ zJLk#y*6LAT@={Pq=C13@8q6+~G?C%p3KeP#&@T@$=y%O{U?XAf&d{#)b7lHDWS()@ zu#}IhY{HMQDld1=!hbwN{l-beJJoiB-t6}F=b~NFue`MGG4WqRUg*?`w+ z>E{;HTZd5iH$hM|B=YhS;`IA$PLxv5ZlOcI=Hle`g>PrFn^uiLb7E0nnh!K5(t65R z5|uK<0|-d|dES-8vbreIr%hYHCfAmfHsCCI2n47Bo z2&fF($h3e9>!m--QAAYk*l6hL<-nuS5`dh0oE&WE@uzWrq(&r z0$pAP!_Ofp9l7eb4WIZLAsgMJP4p)RcOP+ZTr^W_IJG#2!J62~(Br}P5-c8T3hmub z2j4Pp2=l3-|=4yizXS9NWH8CaFQExr_-8*s4)wrv}u_ zxtz{|ufUc`vo5&TaPJhNJK%Dn&v0)?l~jy0{;2AxB6}xx8p>a$i$6jgsmRPDZ=$wtHJ76c?y(6vLG~FC!!Kk?AYFo>GZR{7n`eQt^ zYq*NIpvb0Ccohp zc-z;eHC5xFuj-B=uJ`)L_T*I5w2&2i$Azp!ISNDJcr1Sz z*wd7M>z_Si5J@t`+c56A0z>HWXV{TUx&T<-8F`#2T^;A=Or%eYImHsnId`FS#^9nJ z`x`0Jiu|hyA$RI<7C+h^*WO++kX;*WzJ=<9EJ%#f@iyAhTgl6x^t>qaZqu!=HBb~9 z^{%4&bFM_gY0nCa{rE9p|57V@|%I8dhVVtzGh> zQk_d1PUWAvxE2WR7T*9cHCq+1g-zdttHb#RZdmj7L$XDGjzo|;I@);K>V%cnLPJn< zsyhAG{-*U;>2V(sjRi-8c4`YGw~+ zb^p2+$;D#)oaM;wE5&7jE(vF(!I3&ybVSS04@tVn-#W#N9VyjvZng1&WcZB|iD3mX zR)^$&#{yWPiz>&!XIPSS55|NrVhatlQqBIDq6+e0g6{dM_vjjKt~gtPDcNU!J*@p3 zcG!H(W@jv(na!e(L2+}{%Q4$oJN=S<5X|=7Vk-2_GmV}BRk?@qXyf5koM&G{`Ur!! z^6oCDzsDVEVK>FoQd#L}jz5v>Dk)2Swhj!@%ZX*U22nCk5W3h;&4|%{q-nhgrEHU@ zbg|_&7iW9_#$)Z0m5GGCiWCQ?uPjOLBrH`McT)v!7yKxg@?)qx#i7smIF7S7g;Oe>T)+9^I``D7#9L`}?X z;_(LgvmCtopVTv--UZ*Q-MS}>3aOSk?kCjNcPFxlPBXdc&NiPkxa>3#e@Rj+@)BkG z324J@1s7W-os`AI1#N}T+auaY#YD@iC z3#|azlRCVn4HoQ!9;kGL9P_a{y&;TGXg3(XjqW@OZfN28yICoN)xb()8&PAZT*Plx z_!a-$9#yNLvbS+AK*al#inENBD;Vl^ywbg(5Rk(|Smzn2llj&%uTF=QbkcknqudbnHf{u$Xfu2m2tfKh@TGW9<#Ks@Qj|qnO zJKa5Z^cl)uk$coD%MrUQjR6*9u7m?l^Yy*FbWbm zH>;AXRk=HJPU?P=}vxOfId_RNPnu4De&_BL)!s|wq zeW-ezUu`_+!D#=h6**p-{9Ctq-tK!>q***gTkKyd#f=M0t%aM~(|S2g`kXp<0UIq- zL$2&AqmzZWNuLtOo!UI;Ly#!q1kn?_Y=xeChFU;5#APD99Bk{m?5V!x@lO@5H3f$-*K?w; z<=)Suo#KaX{(tPfXE>Z&7ce}75Q!2bM2kcQQG)1Q3SrbBh%OPmj1avHkpz(tV{{@# ziQapektor7FC$S#AAK;)e7AF+bDsBl{(L{b>%FdT{~7MG@4Z*sYpuQ3UPxK~a^@Vvi~cqc5;$<}!$|aQVp>PxOCLjyK|Y$GsdP|J=Xmb*Ti{ z1XyiceKb+=jO_4|wWqbbb-;SEQA=0(g(15`oNFh84*GSq zDr!Hor}*#mb zmOf6l?1eIG%2gK+?f(Jd%X#v703#t@i`;F+A-zo$-&DVQE%2O+*prd<53Q%H60x`A zji5k)-TL|Ui!PBO$@eqmyJV{rd4=9NMfnR~#ZD7TBd)6mEIZD{jCaPEaDdI<%%n=$ zP*(kUm~S>)x-rYCU8Z{<;TJD^M@~Q4czh>1V1yq$J;j16MLwy1#w4tm&v=a{@CI+1 zWzaRucysQ(7iTCR1{?{hDxEMncPq8EVS3Hy7UZd}DF1e4<7URTE|;fsF!aOkjM^7I zHP^7Bqx3?NXz|{SL>1~eKeN1Lkkfq;EaW2Y^$nbCl~zN?x+Yo7LkjLUezY}p-@Mq~ z%mfri8{Xe=F|6_4c+)s{sy7f?5m5)Y#-a_yXQ)!=1QCe>X;xis*Nyyqt2~vvWUArQ zwT)Pa2Ye|md;TT`dG!WyBs)UvE@tMd{M%r1Ae#AmuIK!|5{ zLS=@%Zq8xf7e=eb7NR2a#hVmGJ|=+ z)jkzP%xK}KVHv|g*C?Z|7n-0EZ1U_jgiI{~sTdTGo5fsmz zWOb30&gauL$t8T;xl!;+E4J$;jG6;Q-ow|Or1$!@x? zN^59Fs5=BtKCmJ)E4q1vJGLvN*Gqzc%E+0d`a<{i%2>iGY9c3WsWfU3+; zEozXYV$b6aMKib}?+Gy!@0;M@S?U*_5a{q;}k>M4K z4*7AI*czt#0vEFH@|+L)OLP#&`82Iyn}%?isvs&EWr0g)!9{f|#%IArh!&axkL^}8 z1DbhUYl|L?K_gnDzFTj3b{cb*>OB0NPhp;OPa6nan_8<*QEp6Q;_rPH?b?VPE89M3 z_Y}%f0)j6{jBN&d;P91rAx!+SmaP4?bCpc59*WH$maDi6@0;`LPeC<_5@Cp&rLSLhg!3J-2Zn{% zE^Nf$eKj!5x8y*v%p-4c9C+`?*Li+#=*9{bsMj`v&FKP}#;>M+ti9+iyuzy=$bdoA z53-GtZ~n{+cU*t;?xWX=M@Kl8;2VBi`2IRV^HfiROI~HomQm| z7X6IBz9{zaXRMj6jS0I+w$c{*oXaeUJdOG4*|vrH#xhSdAocezxzm(@OK1{kh#tKe zwaTVq!XmS;7aectA;YVcfo*||=u-7Nl=J!Prqye$0lgbu!f_9^TN!_#&I^G9IS!db z1>5^LLT2Wp_7)x$XsqO^QgPpQRUZKVQc%E4G5z>@DYps*j#)ZkZC`3239!C05@Cq- z^TUZq9!Ms(HFkET-fC1VaZ$N$LDSsUSXM{rD{zbXj1ElCC_7?rfk%inP}Z7$t~pJq zovK|j3yMb zS*WQz51uV8uA3S1ZQGIP$Zja2_~he);S!v@;z)1J0Px?#b7$#}gVTf(&rVwsT z04txrn(@IG^uwoeJ8Ru%#4hmN>yMyA%5#40=eVt>&_OZeQa=*d5@qt1c>H@gQC0eUNt4d6ggOv?meksH4^p zT`&t(OW8fOu2qRud^H~cR7RZxv3DrZlq3ugMXYHSL zILCZlfDL%wORfNub58X|UQo&8?FG-CpT(Bml64BMi;nnpVkcWwI90>qu%6#L+j7Cr z4>)D@eA6l>E);XF^~M>>o!KY=@)WWo4+rBwYE&DZ>@G%iEq;BqK{E;4y9ez73R$pE zHYa3Th2QTAY!-ec|Jb>0v_7!^%(Bi>{n{rAC9>%Y1so+PB02%hMRve5Qpvj2m3E-W zbVzl;UQd>kG=x=G^uuY>-N(12XUkN>+8MLUn$#l9l`J#qvdK_n(bSWeAv9Omfg#`Q z+AmlLJ2zQwsC*RNT}T8L2%M;A*@46+erRi2-FWFz=4Hf1IZAQOW8H?qWxuwdmx@=m z>MTITk@bvn8DeZgDoYp94Wn&&8a*`QiC1x5(RGdA_vxIRpg&LiD5G=0iK^$g2cI>F zxSkPl5ep)58{PYaXYnbRFm;J1q`K@}sOFa8!A7s|+~xH*yN7c@nrmCLsVC%`?~qrA zI*8Y99CO^%r^*3i+Khf~9kb^BnB>HHEig#5LG+~=TIqoZ06YC+8$C52FrI8p{@}$U zfE1$8AKy<^k>|)MnVr#W)}Ejo2=LT2gq3F1G*FV~Q?08l>8psj#`9;4_;Z9S} zAN(7_$%;DWt-rip9o!swDO92|N9481SNT95eZK?qXTC9Eb>jNy%l0Z@@_wkuCvO~! z6GJbO9T=$nh5N@R)|Q`2MXo4)e+wATxCaLvPNyN{oEbriQbe9Jey2SPwT$p>3^nwP z+G_rM8nI2+a{Cgas-G|6+v}ziU;)UyTE1nt`5$c021B(xHd4TZk4~o4hx&6w;#=({ zMQ{>hjg_Ottn*6$$6J|kz@~=Elgr%uI~Pypz4?9<2nFJRL+aPbUeR;QPeh05d^RGe zVG(f0ZB4wNa-$N$9=aHk&P1f+t26Zt@*^3Y7IG@YSwf%e%vkl<)F|rVIeo@iqSl4T z`~LH+3fDq6T~!rkU%2E0EDbPBgZ8;z`td#oDR7-Ck{a$|t_&m%mGHsjM#kWop2l&X*20nxJXg4*)<7$M_UHw6XH^YrDjgjt}unBgmY0 z0D>o*qx()o+_P)~&g6H(HwY^OLnN@L3quDd(2R$7OOji8sna_3t}O!7mM)g9;-q+g z#)9V>|BM@rMft7x-{3#tcTlb)xhZ}NRU|(UXB`I{E+GPaKV1YRP)FXE({^`}r@6{_ zB|^O?EkrxJ^UvkE8T6CYU!J!Iyi_uS73M7;6_*x2Jv4IMzNQJqjvc=9DWr6nU62wa zo03u5m3Vd`Iucm>Drn9;e(Fd#<@$q;)NN$H^w_iB4at&Z6ieEa2s`5&b?2S5`M02( z-^lpEz`}B2lb3fz4UZ|bhn;jJ8I5Y3vJvS)dw+fm6`sz~b;FiuPKKe?0B)&1Gtub%jWKIBZN_B2w?0fE|yh1tEo-M{* zdS`T{a^!ioQQHWJ361<|xMo@` zS}l!GLl(d-3pZx(o}cOJdgyV0&naYNsL9yBJgjnSpj>EutS+csBYUUA^o=b9~L z`w-BR^`h9Rmd?xzk{^mrWIuu7$(VZ&Wj7q&Fr5*X)|n5FTTfx6R*sf#Tx~Wlp&t)8 z0_$j8s(!C^Iio8+KgqN&CKKnJg5MIj6bq`ee4LmgBHkY*3g!E{V{>H_#nbz6ylbjp z2^3D%%00-^w|dw4=?E6`wwmk^z^RJUdJQjeYPWy);kSnTZdVS*HxbA;ZH-Gi2aB~4 z*CENW=;Cz3p_u6BP|~J#yZ!Weh1GG(Gf`!GrUa^dRe^-)QvYXQAAx~Aer(BXMHYgW z(Xd$p#mH7+&d*>p`~X+6_RkXMhek2KQ-5&}zBj5RCCJQnc#M(js!(tbhNuB9Q;N}; z3o6r4B`;GGEeO3dc_Iie*&i)(t4&~sH}*{6Sk6*fdbps(_E~)nqJOVgK=;!wYI(V! zE|=JFk$T$Db_1rcRt;18!NRT&j}2y%XOx`34m#A)z? zNwn`&2a`c3*A5XjTvX)n&3TOdzQUGt`@xx@yWmOgvW!8e)zZr zTy>xahA1~vd&>NT=VViea(!tWzw+cMBLGW=j=N_^3ozPVCa!gMF@!D@I8g^}98yY! z>&G}*Xe{T`!M?U%1E6texZw|O^0Z*z_hrald-J%13{3d`hj`B_ks;msoAsKVnmqIFILw>OBj#fJUQ>Y^<0eM%k`O*#Ls(!iE zgyKnG=_$orB)}jrdhihERPo!}?fieT)>L$IDc?l6wOr=?kEn8JJ*%M7t*^_zLT#+|+u&;jF#yDcFGX2Ry^? zyiz;~ec+#10_K>UO77q&z~#r8u#0&9ct0G-BjJy!Bm=_Iot9{@2RHA3RbTVR9>~8@ z(MwC;GW>H&Wg0A;wSxWtxTz>PROMFu2O2m_pXcXIGFo{oq@(2l17G5qHn6?3Se#{g z{JUPtu`J~BZ#L`!)uSFmlg?!~>;V9YSZ?#hX`;=OFJOk;aBK)4=Tr<>=`xeX4NCGU z*(zB3Y`nVHDTD7!>FF!9e3h#1X|7&t6%H9=l9+#svjV z26Zll_&3doSB;QnCAPz5rtD9o0E$~*pPo&<#NSi@qxO^~MD-?FY{KZfu_(2YcW9Fj zt#IW>5DSral2>Ioo>VX26?k@Q>mF7~U#khZb2Su(=$!(bn-af^0p|*p_lNT;H9fVb zcIc7_Kuu5Cl4!a@GZ_M-XyxW!bWisr2(WZbkYRimAB=ZC(zg%~!N}oXxO0)<;%*OZ z49-}`?Ti9eCW_D|<01V?uWWM3V1vW7=z@s5$8*}t?5vEcrb8v6$b!j`KFU_afpEF43Ev91jf=4TFPj0H!3=QnFN7x zN=-6+Kdh?Kmyg%b?+sOM5jK=6jd19#a{Wj8VVlcaoBY-YfP!y}mC#E~n5e8a6F3^A zMXz&zBwJsbwzN6F?@rl7IQB|1qlVkMsJ0e7K0QyMDzM+}tL<#W%x3ZMex8V)YMMn!eI&>h(ZfZMImHwxU@zWE&#jSy{b# z7^>KyvO`VuVy_G^eie!{)k4CF#)x5;usl7%2~#cf9^?s$X;190e*E})q{W49Zx^f9 z&>k=v+#6&LxSF1OM0yfp(bNo~>Rl;sc=qiKN2t%k$$_m>u1M6^M+^;DazvVa(&O<{ zoT)SwMgyV9{&$B~)0P*zf%)dyyz?aFDN#Z9Pr(>*1$5+N&sU}s({s~ACiEafD8QY+ zg-=>JmFQjmM60NDT8jaW0likku7h^tTUgt`t%6w_yf3^{5J#cA79ZIH}>->q8%5`pT?W8c}fx(P&yTj2EGN&x?%}Kd zo*MlIOpxVz!fmZ=D0=4i{N>sBBx6+x=2y(3Np2N+{w&q5v^PlMyF8P z72}UIo(7!YZA9jZeR)U3FZvFZo{G+e-7C$Ms96RMgmv_-koq5Vq{EmSGp~D}s{-vT# zpy(MEjyyU)457=I62%K4gM(SUSJxS~h8KIJK!B%|*IIO#x_Q$_=X>zG8lJfmdk%T|H{+0C9Wuu-+%Kx%uq z?jJ%=qsnmyMDMNjb^vLUPJ`1o4A>CsX*eb5t)iU^k}0-&4=CMbM8Agk8koLL!Z^#j zyZjjkR^py21)O2i=KDfUO`=e_VTf7eQGg?m31lmF)i)&xxBt|7pyD@nb^gh-fH9?| zc+f26Nq7>@`iagR{~!wAv?NRlkhTJZwV4`fgQ(23`ToEN7IQx%ZTf~h#+}$L2;V8T zo@jtz1wghul^JJOfKtudooHzi2u^zEn>T=&{3jNG1&G;sX~efwH?EaW&|o_gEr3sm zyN5T#r>d9d#h5mi$0jAHoeBS$G*a=K)EAx-QJQnmv7py}#7`vZl8r(+eYq&fjOTH{ z*(J}cod9T=3}3ACcIm);ar{Y-f8nwfL~H`G2WDkXP_-gibaIbcoVbQcF)o19ie(Nr zrDEOOQaWama0V&f1cgWKDqDtraDA&$sZY;>%Yi8rEha0JG>KPv&lRQFbUR&lr$}&N z-Np}20D)M-8Qh!oL6Lx}qdQWD%y-UD_cJIFfjcni{GGJ|e7zJr!!&3j^8ueZ%k zo<6xBc;)u}?yhL#l6!+<4&=dV-LPGB#TQZxBRZgp;)TfaWN1AH6-p2`Sy1R*5_UHh;UYc7K{M+vxVew_MN8&2g*~Q8`VE zKuA3zDZX_w)aua*tV+4+!gzj5#sh$=-vWe{=K%z9;kQ~bl|VjJQj}7Rr1NEOj{Wndl}vQYy0(a?JXnCJr_ zb>9%!F1@wQ)Lzsa9BwO3DZ?0`gv-~}0L1{PY%^s5((p_0KC`=MjyXc44X*d#FpA6T zz`net)JGrST=G(UVC-1y=H$zD+<(r5fh7N;*ecq%HaCS9SgAvF+@0G+GqrGqi3vqw zS*Z# zt3lMe&^KYJ7s`m+J%rnPmRz})Cm_J!B~YUFXI%aRNEjg1hh~PwBwOZm(CozQIbn2y z^0njw=?NjKwCKjmQ3{j>w+<$N$pX-0LRWjWjZN5D8?HuefnCTPS`bS?k~|@aLtk3p zV=+$!H<3Meg(k|X<3sA4{rEy++Kl`n<%m8{$C@u6gX_uglx-M;v*RBC@Z|$B>DGdj zsye(*?M5a?7h1I)R(c+eHyVid0iN7{0cb54s*-*&n4Ct3ok-$Pw_!TR?r6^&-6#mK zH2%S};>elGi*frvk@K^b`M{ET&SHuQy^U5Y5h%7Tp{b%+@LU+es@+nvEsT#?>3eS7 zo@TQV(-;w5l+vWs^g6A`mCl{f5jEu+YW(UCj7mrAYJd+Q394H|$0C$PdO*FO51q8h zLv^hUPqPODl>zpM8EApn=ukC%^ek{ihnKdLs(0B?XX?Q{v4|>xU0(E1=(ZJ7^uP#V zOy)Z#MO(ubz+d+`#ce-VIU&>M&I=JIEX)cznz{*O4Adq7C+2|W{OsRbOdVxvB4#fK zICAXM45)ZA};T<9h}MA5shqCKmq^=({t5K*Hz#IsN}^dY;1_5KlB`w zr>0hAh@HK6_tLp@+XAo7TdMByc|X#7bh+`}1~&@>GU_XL#Jh9CKMWtgJEuy^87rV3 zE1(#9X;A(C}#$_xe$9nqt7g`l*RCc3c969!=p7qjGb0 zpXnQ+K$|@PHB=ry04YG}bUl^u_^gwI;?)abT@9j(l9s8Hmf;{@8|n~zq2Uz}7qZDB zsI+)v31U`VLX_0!m34f48pF$q`Ei_~4Qkl8{OA##Ie>}ms!pt49|6v(MC%ux4-vs+ z^T;Z9*c<3bMY|9+Pn6Agj$R@<95;oWVsg4iM}>=^HkM<5kS0Cstaj`PjK@UpPH^?6 zg#GK2v7vF)b~-=bs}xqbanX)G{rlJt1pzOaoHs9mx0)uzd!}@5YfaGM;znsZSrH4B z{N;IC&Ua5G+K(Kk{SUq&nZ!Sc$=ITPJNwyfjb^aboY+RI+bF~6d1YmK6#1KUI_>jg z?=`C#{CFT?DM&WgRn5cCXRE87{007P3DrUpms_k~T96=#)hk2ypFRR_89MjSh46K> zuNG`ixEgih`!!P@t@%Thl1C|}5@BR>8_pjjyzg$6Ptih^5YH=(8b3qKc#k{~@@$Xb zK>yzm3ezE`88g{@M@F5cdH#jzJBsk&6fUQgLh6v}w;*5V{X~$jG2-G-Lm%lTv?*nj zl3`5aXtNHo&n3?Uf(ZeWuFNBwgHm%!d+dZA@nhe!`O$1myv;hP3MdHm5`pgEv(j?P%RY zHrKOTCE{IR&ouvZ03RfvLxJAw5ouFho+DG6>PK3-4%UTJ*)*S> z79#66k+=-+B!&u+}e8KZK#JALL`gEzIxaOx1gMQL@#=IN#i9{zSHDy8g$(?X_*i26=6BnMI}`C(>> zIz&1F{s(q)l!0syA`VBYvwm?Kdv`wf5)%U7L*&2&5igPvZ0i2JL8;w zuYo{U-Se6#SV4l)5{rl@eN956e<1XkX(btP9%Z|^S+3q1qAn9!ZTVRoG$}QE7?#YG zxaKH*x=$7s&7R7MTv;4<(}zDVYHLxubESBoPm7RU!AdD&7k|D&qK4)m`66Rd>asN^ zt@xd<5SXs)`I%oI*Sz_kZoqhsv=PdDN1C1YI-1zh8IdzLJ5mSJ$k8+W_x8S zny+m@S)cxK0nh(?AC*b*li=j5f%c9;_D_4$7Qp;6G(7y`60`%J2zI0iZ(PBN6hAfuL^4n&(KkIBVyh-)5@EyDU{R&E|fz(>4QeqiuR^5U>%+$xS z2xhABF~D2n@M+s1JUnMz*XvR^D&G`_I63{cDJ3Z6yzxoikr z*TbiiIQ4)Zb;OcWFb}0Z{Lmr3c9_DCqDmmS_IFOSrY@d9>>+--aS5p4&g*$$32SC) zWt=8eCC8}aXTyMDZMAlZm75&n$vo^++tzkNsKh6>i>WAp$fnI)U=I29?7T0}LN=alC zZ7Ny4@4x-H)Algh^+y?1*6T?r;FsOiN#pJ^LP9A?j@Onq#YgCrl+1slvp!BC*c>=h#Ez*JeMnBF2=T?;PG~V0XZhnNL>f1AQmY;`6PC znr8K>=?k~{`EuDf%UEMQA}4GUlhfnun?$m)$za%n-EMqq9Y2O;E$ay7+NVXGCocLy zyUc4uwcu5kK3QyezVPd+gL!1AV!hOnA8*zRaz z4vjlYi^KJMOV=!TpmZ7807^Q9}g09ptxo+n1<{ngZ(uZLwUs>`lRA_aRvnEBa3tU zRbls_I$HZ{`t=g!4N_zMNKG2!Q=d&ufPiDbIt$oM6=lDx5Lt#(k+88I3ZPqz~D~k6=0S*Y|_6i(G;_g39zd z4K?#-mnt*~xZ~MgCE2p*V>icpK_6ZQIl&7_CifaECq?%QeR^uh9B#Mq)k=-P>C8s1 zY0MY-kDoWoY#J-Sx2Cx%{V+#sdicAS^F8xIGSKIhN&Y>GyCe_iPHMEb;&)W{I)tmR zE<))b^y<_H+afLMoSxjekIaXzh-%vr z;jW8@%R1DK>luvbu%<(ML|DG?S15C)dDBUcA%UIUp4E?YP5p5GNI(T?AW%8e5G52;_eQ zL|5WLpF>Koaf-+BOx)>kHDno7W8sx8U*(=`IpR+|UhBKDC63^@e504RFbtfoO|u+g zckJ9*unS4#o8Vh)xeMQ~hrm8;`Q!^}h-IyE%MBwTF!kEUm0gnMdBL9+oDEq9tbH;m zYNBI;h@ne$5c!;4yK@^Ny+9OeUX;VfbNu8VlrIxriGEawWjuB{FuWRifPdb3FqfTo z(ebP8Z=C!YCwOSE`M8}dP~HZLmSC@+4cbbl%oc&mHfK)7O5g4vnUAa z!SM?igo35l4cgK4g=GjX>bg37j{up<>QO=uMZir zh=p`(msui6EK@s%+f$G!-XoilH~j-ji3=6LFhe$xp`r4S+NM9I-+RgVZ*0ZcJc3_| z*4Wv|i~2r<(*N-&$H<)O(TAM42Khw+{$6S{`alI?oTHU8gqi-hu*e@~|J2Wi_sD=e z!Slf+>B0aAbovS;gZ8Xf?05>bL@xA0s*TKarcBes1OkU3sG^z#(;i)Ff7v-h^8~Rd z!Uq5?*F6#I8Db?5&VMG=@hz6&NU=M~*Bso6>q5ZKUTECihXK#$mNZau{ zbm$CWq^tr~j)Vm-{?M&ZJJUS&{+aZJElB(0y_0>po3_^RKtz>)=Yh4y$eYJ=D-gVq z1w}>V1b^JMQ{&@4zc;q+7S{^uE=`X5u$R2YNm#Q2;-mkvh;A~}$+Q!k5jtC>p6peP zNEjQMuWZGKM+Sod39#YT1!2iK-Y=eT zeTcwi1xgQ?+UVO&7y5H97fL=$NHCO?=%9u&k353aSJcNflnuaWyx3Dc_M=gmH0baC zin(Ftg@qTL+U}g(`74TFbDnV=u?M8a64lj!boPp-gSVqJD(fW)O`)QX$rO2 zm|WsHy03Aol<9nkbi4CVQ<$8StET>|k2oFsb0EUEr~HXEu$su z(D7niprVp)`dlkiDZ`^REN?8;s9F}<6ua=o3l&w!2WoOEMA;*92Y3OK{(x7MNaVK2WJ?KGH0*%>H0>GT?fq)0i(_N z^Eq@PYaC-sdh%+u#Rr!mgJ`H5rlvZtj{;2?r9e-0wIBugDyK@(SZ6r2Om7|&oqY*Z zJS)dh-+mNq+T4$nLuV`zeLsdG}#~!DESRISCE$jsO zB50sH6G+z8{9ut!#TMyKIxh`Sw+$%$EfRa>x9bEpB9W{pKFKB5{MVqvyh?9Cx9-U1 z&nV7QCU2|+C{i#epx9C$>j_vB%2Syf^(zak&0M;*`eQ{a?@{;`2sY;!zcJzJ(RsWT z2+TGEu$^d!L5E^-h``&nX6F0e1)p4pVEVoGk7Xa^14?!Z$T#4)8d9Bg+_$@1$q!Zf z*gI}-{t(pQ-=1@Thd)JlnOTVe0Fmh3LME5$YGZqn8p;mtQo1d>??d>q6?N#0IYCx- zg~()md*IUx6B}P4^%A%&>3HDFE^!O>EAN}-q6~E22lMj0Rt;c}Tj+9(VKvC73lR}l zT2!%>r_DAUEmAMD-?fyxUFC*|;W=`h^dw~_Y>>G0gRXzm`^!|(1S#+v*B!=G^aT%9 zLT3{V>wokCl%WGqhI0=R?Cg_s>{Tzau?Zoii(QAiGtI^rjmvK^AnPD~@cocQ!0=E8 zZ;i4ogSTwo=4f5>aLmIL?Pn>*dbD<(8bn)FkOKy!BzWsU@|JDtA^tIm7497%)A5@> z?)W7ec+2SnbV50A|CFSlnyg zf&rFlMmCL*17Dmz-Cg6LAAvfZ*tNx;pjvG{(5&gVxDymI&T2!#d1xBK0+E&BLEguj z+~m=E2{T0zr!yAp`S~&?JI0Zq-^%(MSm$7b6_1~*rbG|Yno;? z6|;R=C&A0Qe}QNoR$Qr1+25nRrp&&pFI?JW@Szfw*^6ZX;YgHOuS0dUJk;_?N>4@; zAho<5Sc4+}0V{wMV=IUrC%BZek2i@L4?LFBV3s=Re3gmqm8Jo}(K zW5|h!Vl5A^i0dgZ$M}&yBpzs7qM@;6&R(j zWM$7IE8X#)S%GiE7N{pt_NNIil}miS{1rmdniwNI=nU@Z)(~|1v|&Kl&IuUw%a|HL zxIAv3FNQt7p)JbKqqRkZtVwVCUDMnlAWcq5ADcCjTqUz58A_tc2^7Js}eH%u+1 zbz}jEtqtRRGDwuZT}*?REoN~CVqm&AZFm(4tdLVk>1@B|mQ(}E*tGaE*WA|E!%f$O zpdL0KVzO|n6Qd$JM~bSLk=&b_?T!4H8(qPxvdQqq&2hICFsME!*Ml)!X(->#nHDDhclf?5%WdG6(%oi@H53UC={~J z1=u4z^?T#@!Z+3;hNVF}T>Nq1l2yu_f(MnK@C~wy<02r?Z3u|2|5^ek;K^Q8IW8kv z%JaOIxwAND(zulQ`e$}__g15jgtw<0_WHAWfTSN)Sahy?tYuP6KICD|*s+k8SPU8J zMw;x}WtqRiH6u|!!}#wtO${AU$;3S`hZLJmdPDuJRu%hY#XG$C#ceDT#F$c&D;%=- z^>v0_Q_C!Z^*XVHR+D{Adtr5Ic7-(i`}Nf#r}#}|3Dqg)wE~lpg>pxo=F~W3UZ1Xn zUfaaVF4JY+E+=g{K-AV77mhd)T!h%euih%T_vxrBm>$r%QY$Pod^52-?)c@gAnUWxO zeKQ5Z0%-M%yW|_zfuAPAr*19!G)EZ(vlleI>sr-0vh)?Q&De}ap4Qo-=#PIAEpE5v zn18V~u`c@r=B4LJPFoOx64T1KXdh+$<|n@l;PYyeTc^*jI{tQ|@qW@uHxk1fllgit zAt?Oh=HdmPyM(J59>LEi0GDIgYI}T!tDeRjVJB;2@MYWUOE2HTb!+{f6)Ghygwy5$ zMTC?XK~&2eHal8ZZCySk%Rc`BnC!x?o(6WeQsX>C9lSfCEmY#}y1e>@zX5HO*5HTX zT4wj35+R7PkZpQ;Dx+^&av5Tl@p|8h+vN2{{NQVa-6=;4nZB zvH$n-`JWqTbh#zsO|Bw{xc0Z6@t^CWqUlMKKQS}V1BalFe>(wz$os}2;y_1)QHaIu zVm43+N&NdN**_12Bpg{IMpk`KstsPv{c{ocl^B?V;4=>b29?9D#?OTMzYUn1ffeXvzfj~%9sf_W zo-3QA7|9uBYmpNHomQ3e1y zy%8g(XWtC^BX;|rm-EGZy(mjO;3L|{rB?! z#eW#EH2VG%3-EvOH2yyu`f_`nzqeP6w#VJFg%Rjj6hceA%pdWh@b-VH@^jx3pP%Ro zF-UBAFLSLq?;@GQ+eNau84D<#b{z`X_{qEQukZqW9~y#=l|rMn>k=MY(A>Rwn>NJ9 zheuOKw{F(TRrbHr{4f|~B(^*QHTD^a2T62(&LRct9kTy>f7z;zPHSf(FCXNPS(F(N zmPt5({LB*u^z{F<&&^9b7HfPK2KmAipBX55H0dI@r2n}I>R0}tweu-23gm#i2OV?H z6aMc2Kl@#iy|p4`BHS-Rqfs}T^pY!XA$O9c{8q=Gha-R02mPy;{<|XM63Iu822Z0i z>+@HgK&u1sLdl<=-*=@)DRd}7XA>3(P)f-H(SN@g(zZ4!y;4`QDgbhlyd@cqihKSP zaeDLQzkqysK2+`VH`-j>ZxOS!b*1sDze=P2-NEOhRhp0(_UWWEv+SSdtCS4{ul(DV zFOkjt`ws}jdH=7{tpB<4`2kHXw)vYHpUA{#y(~}#3O*Z*UssK?i?%5BIXuy>nyqnO zF4_D&^7!1NLcVKU61JV>G2T2wqy7i3VU(`$A@3>0(?Nk%G6yQs@z_v|;&#i7vr;|$ z+lQ)TasQWNNdit}-zN)9EOcjmFa?esjqLb_%KU)x+f`N)zV2_UngDf6J3t{uD}Be> zcxU|Lr=Y3+FCvY$ajwj67OEDYjk)FktZwrDf}*o>J$$#PI!)f`@k2vBrn@6{-B(Xq z6!Aj-61A@RpQ?*?(W7R%ruO}xY21QrK|Rv0lb;n%N{(Qmq4|O)gBELHKEbv-^X2ty zCiHjB0(yGaEX5WF!oA@}c-Lw#j8uc51-lW@FZ~j)Wx7S?6?exLsWEl{X~M%ggKZ*r_0w%lvb--Ukvdg5;QrN0Y{{{8&_3$dL4cS!~w ze|aAKce&8NUj6?+`ZomsF9&bL4MUc@K?y=82-$LbBa4UhKi|guieR{DeDuQLnxAN* z4$-2heyMCappVmU;Wt4XPHcE7VuJX6^P$}aOT#S@6L_2psmx+$Rq>$rnB8Ua^=hb& zS2M}{V_b|}?W&l+%yt@6`F^z7SYsO1rr-4dw+ifqARO_qe)k9#)U;_!e%d!(ySuwL zbTLo(Tln^Tdv<<)zAirKPb6zC@z~6BNZV%t2S?rXnel>u3iPnE>rP5f7Pq%wA0J>< z4mRi2;mGKb##{$@wrav_Y@@tK>VP5iN>7TUpk{(lZr%GUG^}C}o3{5WyQkRhj%|oEeSfES0z2yN`S&!#!?^)wMNKM{Kb*po%nsTdOFKxdD zTpxjFke`l?p>|eI4ypLgAeBhm_+3ytdNH+Zohyih^88Us8u&&U${_jE9lQ4hThGZn z&v@Xm0uw0&hVh*gPM zT~C@zo<7+9%2GJ<(N^(v@0EGbzIN?;*_sDo1HZ6Y&-H6KcSy{>ce?x2>Enkn*Ww4h zso4SWm?3lXyt5S~|3e{uM2cOL(CC;;|+1-Izq)%gM#DSl$jy_OZ&w6!P(3;SRiUw|aVt!Slg6u|Y_qN7ujO{*18dG0_fQd-1~;>4yD?Ri@m8PaUuyy z$Ho^2+Ggvdn|iSdj@u?$c+C1?6|q5^4ZFQ3zvGDs)blMNWW>&F{GWd>!>rS9%D z6Uqn-Kn=CaU!xF^n`+VBp8__MZ$`^-1N7oIZwa~^Ub82H>XD9CE?Whb-pN_^*{$Yj z|Fs#z#L`!;)iXlUGka?(T$q`ebWPzSGacpA#G{d7;ob(nU1NVtvUpb}6LhB!KATwH zM|7Rtj&3YpN?~#i2FjR+*fD}~^rKjAcS`FX-VfdhV=`tt2^JnB?hiKLI0K%es+;(% zln#d9UzN?HHYBSEw<0bl8YY7JC2}%|U4i&|`^7ePSaE=f^sH}y(qXg6Vha;IErYmM zvtBVIMf?5IXRqMXH7o4ikZzykn7IMIY^f(Takp1qgvH$b9-Yiw2#3$~i+qV)nY(=T z`w45i9S<;;Lod`oAi1el7OQxXz~7nX0UNgs69MI@|1x0Lg@igczslJi2*Y=+U!WQQ?i+?mkGQ?T^mZ@skO^)?l^N6O^~A4{RNO zVHLN-D&me@EJ?>h!Lza+1~OI@D2#1EuFbab~P#3 zyUk}e90MF~;d=97bm!FU3-^QR0Fq19qNce2-Z-QKz(HTS&olyM9vIxKv^(6LcBir3 z23E7#8MuZ*A$2+Z0u9!vCWmzDama7F@^wq?RwwyUo~>L(%LAkYJc?&(v%$5e%K|pP ze;kO}+}zZH2l{U|9QB&RTlZ_X3NG%VXY3p(D63eS+0t zWy;B|JCo+=#pkaR0uDo+QJc||e$%{rb8nQA z2ZQEk>o;Pt#5!yY;-&S0e{W;u(9LSR40F0etFTltF1L-DsPMxH3do=J=?TJ5A~S|F zM)(n=&b0k^apDVMT**6ar(s!tzdzj1hkYQ9mT$__zcgIcbOPYu%w}D11%1vt8`OQibetPcUecHL9*SgMg|Jor@5;kiOCASuS8J$!y6#b2bMCg z@{gM%7K&?W9bh|cNa$=OieNkgeFK_S&`g;o)Q~TP!RB6P!=5ibL6&i)E zzbDShwl#gcpH3sn?=DO8*9>nHQ=GK>R$%ncJf1&jAQp{2PTWhuG%09QJnxP@A`K$? zCoZ$@LFq130%nkmLt5=EAPy=s2~+5Psp(OUyNDY1g$_yT#GIhgP8fX9l8s-f>FeMr zXg>;i9m1{f`sH}wjt8rCMlbt_-+PwMmY@Eia!}@rIvq~o z`GBQ&7_vc7MsJ;aAb-J3>fEx$>iT-m+Y=~$d*@GrnQ8ITsI}|Kl1|#lTEuP~z8^uw zbY@B%Qk~zhoaw>Ajj2D?g73`wuB4N&bSjpQ+K6xVmzwzzZw+Pf?z?o|z2DWxHL{1Z zI?7e2|M=YcYQEc^c>4%-WYZipoXjQf8W1ymlfKrXu#L?4%nwrih?$dCpF=)xI=9=A z;lZp=jNwUysM~Pv3DTyUPH%zUbw3pK2%Ka0-?I#FYNsV312>)O7h^Rm@XeIcS0K5u z@&~*;n6%G?yEQJSI61;alp9G4cto-r58`usE{2T^VQ;Q?TRj!6W+U#%+WIVs3_y zN~hHjZK-FZESHwF(yEN+=-;pV?TeaL+(0W41*<>(4k;gZMG>S)KSItH$R47a2;=_G z&dP6mgS%0vc+nz%64dYAEs(g#%zvo-{WeC_m<_6SbtMOmoO6DN#W z>AF6bDxjHA{DV$L&81vd^0!bm1V%Y$PPhz6>LRK_52#q7HuV~)@#3y-Y^fYW9u z(tJ42M|JZXNv&u-D{r8C9{Q2mk*4uhso{k{qFLY`4PWA$OhFM8NdwZ+k9~ZIC#h(9 z|DeZVK3ae86_c4QG0=O^kGq7JM)Y0$TYb0vP4h%{IArEFQ8r~?yV-A!C6fcFxP0O& znod(625_u&u2kdHkDKq$aF7330!Yo9>;4Pfn7u}7h>!;t1+&tdrVcst!z{w z{va&3gxl6rp?$aN{@zzd(m^Q?-t_%_4En(@Y*r|vD2lXs3mMru%6Lb5dR>&(m9cttWM=vRa9+5xh_w_eo39@XSY zF<$JzAS6)?8twpvYhGuA0}st2q<9su6Y7rV}*=A=MP za?zMsx5RgEnQ)oLC-3cSWZoZqDN6#(-n|h13dB~^LIMZ5GmfB(0;Xstb|^VF37qD{j3N3UAz|S{S-;% zc55)4?VWo*QsTdf-W=z~!KEN5-TqgLYBG$z26s!n_sk-qh^b&)OPWCQ4**N=%(@Og# z2qS51fk?tfQ8+=wR0FYlA z8ygu>=ApPblvnDPQ_w_44oYQ|*6m}E!OD6Oa!V3wUWk@oKI8WK;c*V8 z(G@ndyfhS#hV7KN1qzMiY2k(t z6VF0y31h}c#@dkfpY;71cZ8dpWB$o*WRTO{_z{i&sNzfnKsShUn9G1%vaD>2sdf~tKFKO>et z5b<%Oz2(v$=rJkL-W}|r1Iw9L<(hx}MfrwP`T)=|Y$b3U?z8D!Hpw#SnW|MuQEIdg zG2Z;}{S9kv!Jok$b>#I_5bkDk5Fxxq3j7LQ>+JR0E#39=;W&>mL+Ry@>U_OVb^6VJ zDHWASNr64&UNdPo(nRV<_B&ZMR&HLqcZC)FQCAykhW%D zhGHd#e||ymiSvZV6O%xFBvry*X|ikug0iUT0lTKjvL4u%8v^|AbaH z5CM%eIQfa{8exbLo{ENQXw)vtGPl`nr~uUL%tC0BYZ#Y->t2)T8A&Cf`$#$)s3lIsh;?mqTwC4RSvV;vplXlOKbS{`#O#p*NCGvF6#Jn4Z~9pX?`qqbA8s2UU?eLxuKbla_ay1wRR#_?3p?6A z4Pak)Jk$O0Y}HeHJ8Wo4z@GG;qymnr_baU7-hT$gbbPmi&T$3rs0Vm@&E)s4>&xoazBp0ECZQ&tA?iUDUKWjZ5u zzG0*31Io=PW_sMh!x{`-kprj#>6oTvN!jgh%zJM112-;3KhLoxXmnACPAazuY|k`W z9AX-{BNC#eMYU z10GN{TKbL^&BgQ6wv(E0mJ})HdT4W*QC|WwBcG3I?p&@4YIF3z`Sl$be0hawo$JE^rNvOylFnDf#wl`g2)L1_D;d?S%GJGrS3Df*7o^U3Fo%5yGiIPd&>j8X~`bq zAl@hmFJNFKF9u<{fba{5D>_~NN~e6T+e2296-F18SfMQX;VfRH7t|m9a5w*6b9kapvq$Dd> z*RN!xju~4if+-By1BAvso6hKxhWo)QUPEq(k8YWVU-+mY0UM`$DSz{qg1mNcF9^H` zX_stS(LJ8}9F&rMH_hE*Ig2U(JTddvM-uUXFv($4Nb$$lNh7FxRuUu-QNTT}#tlb% zgEBDDz;?PlzBwmXWRSLF)hnWjztVr~Vw*`>g!Q?o_&>gm~p z6_|ux>kzqfg(?1;$vG9(-yB+wHENnq%wqXTOC%+khweV!cIt4X$L^pPLJ31%<{5l$ zznn6N@<@CAE6k9f0~LHC?QxcRC<+P+Hh4}-Mk^ltoUqTdw9Zeji88CcfL4cB%q-=lmV<*sn#VxY(ATG(6W-GYw<*$)0V}eZ>=?-{E%LdUIOpF9 zGV+JNRiJN3TPUsS(ZPG!d6?U`r?xJrp79DG7^2VEbOxOlOnYfNjFy%6o)OOo*gZI% zd#u3BvcWTKsW(wwr7fI8$eOgfB<8auJ>#*dDCR^i&LtiZ$movmojg2R=J&M>or6E!zVn#2jg<3p?5tnm;|6fs zuF47HjS9Rh>3A-Le@^%;tjXNMqhHp2e<-ot2TM(QY3aUG0g^7dZQ6~F8lGe-jEIem zUBw`+hO1LuA0LTHLEu%Mkf8AT=-1S$WxdK00!q@zw-?#?zFsLx4MyWLh$6)ghR}#&mfHF!5Li*Sy|a3YTee*QkIDO z&PUG9x{qNxfp^U;{t!L=`l<+Rubu1B?`7UgOH1XBW9zw2?1E>*&hkzf7T}}hy+aXn ze_asX>%|;~KfNXR%yG#rsy+TMF91hoz^?B`HAb6bolSQZP<>Cu0?GSt{bKkOtz#4q zx|9I|xE5fhZ8i$WL9chES2@ZH+kl+*t>gLn=-Lp9Qm?05cH>!z>+ICdloOlrp(cN@ zvth04?CMmt)6A=0VKLX4x>Z1$wMYsG2)F}k1x$Qk;@@u}+(C;3v-Pike4R$6u+~Md z7r#o6lew-#X!x6sGuGeGEGk9)W&)P{axY(`urn1~X>=Ff5*5{HsA<3Ga%Zg3w%2ZF zSd*x>IaM873ZotVd`w_15DAZnSZJnfX%?(3FLwa?DiLgHWmU!sj!V7WJOKivL0grB z#C$OGK&0>9#hb-rU!Tgu5!8w)%@^Vg~_ZmHD>; zgx1dK&|3J2XgaTzTHWROM=&;xdd zHa7nDv`u^Xk_OJp(O>)=^v$h11~w4(=B%8&-C#y$Swg0j1PfcU=m8diJbi(TKK7Ot+Yi%Ux#>tkO|I29Qu zs`aPD^CM(-+FHTU?!2&GY1bc>EV0sI=Oio3bcGvKV}g8v`$KR2O3bRWbut%Wr+J%U-hFI_3~i6NkV&g6MKM8LNgviK`-z%boYTC>dBajjNVEuC zYhIXoWJW6QRcdVOs#UvL+r<}=*Hga>G2rJnS3?wwzK+teTChl2aayS)xW)i{Tphq2cSoW^=$IIWtb{Rncmn7g4u^ww;n zU`Y(Gyi~si1QocNRXKdDYOZ?WkP-(KTlFUN$BswnAEs2-T*Z_2;^?o>UEvPc>z5V- z_264SlpkS!w^wwKaULs92ggaJ)=tZPHfr$m>dE*Sw*jtdxGWvjp%shx9fFh(E-4+2 zfF1qR`e1`}!YPVdI`mm)ASHOXgCve|{X;c@FI{dCo z7-{g@oR&61!qaup8x_6T0Mv3l`VBHLg6A=p z?M!4-rFOB{YCYi^Yn%AYJrTfF6*doJ5?fcH7H@+wuBjFsq z2^R%NoiL^Bq-sY&l%U`%{S>AwIrFBM?!$hS)e5$pSK?}BUR7R_eP!{dV!RH(hsfkA zc&+O$nwP1t5k#R*KpI?F2OA*blt|qb<}fJO;2xws4kRIYvn z@>rX#@oemHMh?tRbU>Ey^DX&{@$7{aipji!yT4y8mX4V32BGGzJfLzyPy)Cj)0`9W(wR==-&a| zxoyf}pWzz_bi!5*Od|j+YLTyRn$@~~Tn6inix7>?OdBgSEV?hq1ZByQJP-5B!EyLA z5bSQ15MKG`SI&QH@YLTzcMCb03(4AQ{ILLY0)T^H}5)--2UDrayl)Z1? zz8w}sB@0+K(#SZ)OUIy!G^Ursd4@QxoY{mh{)<5*Qr)3@hY!b=xrN0g#^QX2BjIl* z%18J(woXCHWMMOdOCdb3Tu<}J++QOD&G-TyMO3-(Fnq5c9GPi#&Ctjy2wyAyQyE95QNd)kGQfdI(NOwerx>XJMBv4~J^-kI9t*do#7k!l*Ov1tbOz&pD*_q6m#>L6w{oqOR{V&7Rj?>)i z2qpTU2IgR+#@KEqO5SuUFFbP7nYJY3H)% zG5pmGCBFojrXBDe7uNl^>g{;~w!bq%SZ>PNiDAc77oX4pz`pBR)x8YbZzRQ_8?eD> zs!o8k%d0<8vkAQO#M!eYx@r(K?6m!}c7Y8cBeXndl~gvKtI_(JI4d~ca!RKUB&_{A zckf0DW(J5KfP$nBNDkIOEsS5UbsQ_KTQ4lK9xZ4SMP9$g;K5!1R^ZD4Kw>DhW=V0s z&0!&Jytm&Gt{&0e!x1K!TdLXJ6MO09bg&GP;_HMW?oNy7s2T*{i38hSde+l@xO&{auBJ{0%4hDwzLu9bb7q|=Uo(At(cfaZ4%n@obuF6iYRmj8G-(b{ZJ7dP z9iL4{(>V$rZOjtO^n9Sgws#)zrjfkf6IVq5<9|ufZ=VHiOhbyIkHr1(!ZT~q; z$kR&gFf_J|53hruTvK0P-$-6DDRSDBU_;H?*s#)Q4P}kKEl|&IsaR&H0 z>C4FO_Jaen^FLZ+Vrt8o)z0#Cy=^Vst)P({suNrZ z6UGb$-!Z5wxcB}H*TvTNrzu#oH)?0HO?&M=S_#1t{=yB03FY+H7JJr2vH;a{9(Gs4$%A zrFgd9Lf%eWCB9=#&@&=)Wl+OU%iaCileBwwZ~VuR*n51`PVS++&5K{dPXM>Y*f@xn z)>|`e3ture0Tob+I+&{4*H<@YhMuRgL~*NtQDhh2C29Q45pOIZDzfIUk>)e&dm_K$ z*z-3G6bKL4LAoy|W7I+Un~N#7FukzQiKzarmM zT@*I?q>Hqy^^V`b)L2f}?JsLC45x}l)q^@}^;wS1OqaXZX0OA}=AxTTdj$us3GF>Q zRo=QK-xd_I$r+OV+N5eSTPuF?x30IFwOBbNdccdO?Uq#cUSYO&B6je|kXY-6b^vmg zuls;(=b_$d-P^#J0^SZsJvc!qhMRr19M^^!iD7q_Dwj;a!AxDDum$6f$L!%5a+ew0# z`S6U~a+-~JjSrv}RFRc_|9+{cn3|d%?YHWbzxbYQVpezmBqygDNK>P3Ca{$IZWpvt zq{9+i%+*{oKC5LpHqpq}^~@TU*^>5#k5b}5DGt1DT{6GG#!dH8Yxl=TMH8`ffKSsi zwini$nr2of+j6V!Z7O-H|)i<(u>-A|Ep zOa7G$NV>ofo(ea!gYH2j*NXA4+rLBc@u{iY`I$j}9S3fJ*x&(`IUv92Za*usvaSFM z_rkk(@5*2A%y;$nM%>g&QCaAS`ZqWh8I?pX9fz(+0D<*Q9V(i{c$B{ z>H@!sG~#O;(O3VD8qXDrOSw^m*zInsPnV+(;I5bHrN|K|0_V#+%@S%eB%Q|d!B=tm zz!PXq+{q}S=Db&JpXb@&C*5JUgph}u{3>mK-#+z!4`Z3Du}T{%z7Doh5SsS+>tp5* zu9D)s|FsU_|G{T${%2#(74YJ@|Ir-Tb%Eu7_Hb0Fz-?V!Cu>If=6vQzj|*EM10O1F z0w1gj12?{NE+tE2Y1@@vIO)RFkGc?-lzU4O*PD!>GA9)tLT|O4*E)|6sOPs*|2Bcf zT7sFFFF#4SzqVmD4pcV@7Em1>2!Ja&KRAr!^(TR*8@93VP?(^p2#Qc{j{j91EpB{V*b`{%+t0ML&5Y2{+PLBp za>Ehs`1v8Z{$!}|U0PRtxs7(G*?IR7QOp+ab^v87Bwa?4xg2~iKeG;r<*kMLQblnL zP&85JzK|~Q@x+ypSFc{thCn%wR%w&gNDvhfr8iiq+<)wGH@FIv{Wo_yVXpdNXJyq@ z7f)-MUJ1Tm^l|Nf>;lO7(*MTnf9FH_e^c9k?u-9F()cye5vIRfj7m+oA})fr1`D(g z6*%O)7;e&79NW*lTjp+79$eWzDdcgt~cJX8*R8$~8$ zKUiR4eA@`r=6VKoGAB=QcJA70()YORb2{{p8JLF!XT!t8v#YA^kBE(b0O0V<<=kaS z>$xUhhHNY8$Sdz1X;$s{C6_KLY}s%haD#>dD8yIb+jW>^mAcrQhz#WrdMwU+{Xvcz zAxAB$2e#rt+T{@Q-Sq)F-fWd&m2)x)ZybADNGL);Gn{?h3pXAO3S@?iQph$^W$J3! zU3f|Ql?7v3P`C~-q;@|%2 zn1_vO0JVR)CAMv@TeiKDBthwX()s8|P_IjlD~b&2bwJ-oKEpR(X77xO9=sVDmfg~> zft&`)METQv#hj7S^c??~g>2Kkgs-8ek5~Xv=(0mZ(-lX=E<8yV7Z7+j#UHT!AT97< z(rJ`T#AoXEzD3aXGTnif8L3C;#--jnu;6LujkcV_(` z2Edjmm*_)>hvZ76&8~f%&HBnyMy;rUboo*Dz_}7UwM)LsLh$vop#!X*2hiz9mAB&r zJF@>do*Z5Nex|8uqSB-G(|!t#I(mt+6DsLwNrc^H)Di+z%$I_f?g8S5m3*4pKPr%NqZ~#i=Vl_A;4M$uVV1!U_I{z zlFMFTN?pEC7&8WZe#f0gLF3YT-ExWtI4gJdw`O5mjc$MaN!{tB3j!8332-RE>#g~M zrmh;_V`V5=eQfnd!(7H0=NW|7nFeq2=-SS930r5XXcHGW6}Tqv?=#1D4giO{`Q1$& zsGFX+Nnw%3rHTpfe3z%^xw~HBo5W;XQERbaINKXPKbB8tps`s_ScK0D1!^1WgjHX0 zf8^STb;rKL4$?R?Lf#d1hxT&&qx)Ptru{&E%P6@E8k<|mL}aY}?qrx=`MqQPEqiIC ztVhs*XQZSjuEsv#@Ye_q{gQbGLI3u8AxaYX0#?#&hNU2-=Uru>N6p`+=Mx^|zuA}U zVYA#p_>#r&dko4hJfc zw&Pa)A7CXNrDqTi*^#%JlYB7CPS66z+LUy(T<+6I%Jb(Z~ahdp)er7-*ijluD0Hv!TZU(gj|{3EZ&9LTDZ0bXh$hpNY3XAt<+Y!7k-j6KUYxM zOV7yYqOpa$>d}!0!7tWLMMXnHBMm_#m4meQM4d_MS`3Ufct~3LrwVTlG<8r!f6nLE(L47wy+os4!D{Bo zg$NCsg}5R9Tw5e*&%Tp_KU=a-R7BqgUKp8$HtNC>XXYaZtG^cX0R@z3p-7Bb@?Z^VfOM&+;(35LsTzg+k zWjl;I>55(ywcwG+>koYg>{Nt|7{J(wD6S8`-YDt3hBgW^RAGHok3^I24k#^UnKa!Z z;mj-TQrnnV`MKmbo9wF`8ddMVn2<>jwYtn$$8Ia_(3tmV-lsQpp7`Mbqa9tTBYTUs z)5044_;?U|o=zqo;CrHDl*qS6^e#NfP>^LfeUoIwNKWEFH6YF+)bVrFk!CkQMDh4< zaO`voW+DkGfa89F4H|hdSz)>ew8ek^5%`x@2I4ueR-KAi_yLxAP>K6Os>^s`VKy`R z*}I673)vZ*?Ym#lQTz+>2?-tP##k<4v)a&B9VLYk_u#t{d!6`&-BW(5fZxi?F)#!F z;694>Pl0)D5YN=!+b5k&6@8%hdA>&o8Oi7fmOH7e)}JIMFVe7@@ETXLj%euFnA}^~ zZWRsBzLsyv{Ed7G8hj-y`6~Na+Hqqy&QoP^`Ka@FZE$@|G?rMS&ieCk8e2|_DsjW)Xe)z> z?Te!9F``Gid+zRoyqNY(H~(8pq`%iUV>Ly>*tH7|Idgz~_B4`9;^t@C&o^vpz=b0; zQw!8_94fD%;MPfCTLS@Mc`%bd6G8I@c2_yjWXuba2gjT|2Lr7|Toexf=bwL)Nb*?N>CQh!46m=kMk@Tn!{lUeNa&#Dh5cJhab=#~GKH@#4|2n`Cf!-?P#0|C)OT z(A?L2ID2adTO`;Vce>9W9egUj8%Bitif(Or`1GYqN{_gMH#(patCOR}&_D@#!`r2dQ~Nz;O*6 zHa4rh%nQx(^gr6$-z7(b7g&}|IbZbOn3VLMwZTpVbW{TO}=uP8e-k`W_u9WEa64lR*O$=&KZa*7Eictdlix;c?707B-QVQ-P0RDkRyL z?aWuNZUI3+kMdajqR{vADf57Z6&U6BU0j|BB=X*wsntr=8u! z{*?868`5U6%YBDN;kQ4c#GlavN+#9&0(39z3d@{UdicP(*XT#jd%D=89VE= zszHqt1coNWcGkB{d?>bIWy*iPXvYdz4t~BrHD6&a5;4;>lZyjvX8Ekhbh`@zEv(&m zR8?1uvE5myh269u&gY1BFagfgk`0$KyrE3+=?hy?iMh^hH6k_ohB(JFs6bHu6NTSo zo-cc>U}@)~gKe&*pAnYu#@N zoSA_)qBp$EJg2_wAy1usUR~odtu|fbA{0QMVyUj3v`bwb{rdDBrF4)X>4RAGBA$SZ zWb{G*XXd-}6NkhWY@>vXiX-K`ytNBJ=Ql1%DbU2$x&))n9~CoMxuX8y`@BirOZTJg zRvjQcTD2Kl1*VpZI@|T9aM#YI9Cf}^^xxtiRPwjK@0=8HuNjDe|HXZG%=*B%z$)vs zJiVa_29PTgta;F;F-=y|=0tn)+gLYylnMFOT zWqQ+~7!mS90NL(>V|{(SA=%VgMFp5B=W$4M>9C?c@HcDU=7(7Ii(IA?hH6}TPh#o4 zA=i$KL(Xnm*Ur`;Ut$UMI~|mTgK7S+6*R*Vpi^rrR_g>Dm>x9cF)QZ*2c%0gZ3A~{ z|3_A?Q{dJXJ3w|$Z~VO`${(JldA>|5r*nzfGW?-56h%GpO=GcF63?Ma&mfWmVE#Kn zh>}H}*n+3|uJ@g*4n$prtaq~C?F?rD{~xeKg@t6kc6k$mrVB}nin=!L?IcO#^Djxx zr%R6a^z>M7XQ8WG*ZAo<@vIc7ZC%@m4c(hS)ba&6&OC|=x8w?b7TdM z4-gtx+A3^?fTGWi2%rJOw=l@c<~wbCCpmIoU%!tmE#PtyD>Fo!!KZtUaOBg`rHO)a9z-o+CA^PHd^475$)Lq9*n zTID2w(pfNb=6Z&2-h93WuxOgj55D{y&e&57%e5|SdzBe6woODxIuGCDyG+)-|Kii( z)p_F6<{0S=$+q(J=X%7ig__e#?uCZCbTTN&5w8A8e2S@Y@-F zZib+9=gVKa>m4odKLisFgqLrB`#1wYO7~ib;_N7Gq=|f{QHc@@1WbtW{hP{D&Qn1n ztFSUe)Bc(!2f)C{izVi5nfzpr;p+L8`6Myn9fvw-Otn9S?^r^)m4Ht~ zR8Qo3&Fs~##3^ai6&Dwqoo!}@bY+1PSRb^3NSq*mZe|f+?MR?0Lkv+N?&7Hx;YcE4 zM-vrF=Q%!3iJs%wnzoCOa@WrEh%Hrw{Un_v9xrgr3{p^V2&6L$`HWJRH*2CdeP)C| z!vR6D+?Qecbq<1@XW+g|v$;BSrOm4A*?|--gcm~)u3O8Ch$}tABeQQzWPVgzgm03I zme~x=g|(H2x+*pTud8ruX+KDN0{)P}yONqY5i(Z(o>?`GfMCB_*{a>x8N|B(s6ona zwCvLc=u#nUkDFg#h}Cq}Dgdc{$9>W^-wsIH&tv}e-)_@>5OX}e=10(tJTn4QUN4Nl z&Iww2>MM-n%T0`$oTJEXV(c~@Rb1umQsxGQFlECen49;oA5JROuz{Fh?iDEt<4@Gh zl(si=t|2AFZ?WmdgVqgLJLpM34LHq#$*Vh@Uu1q`xJIMkW59JvPU)D_phb+KWap`T zbDPzcci}FVy8HpOx-DW~Z=!I_aSzVi+j{FuzzA(L?ZUw@9zHAiE9e2R!;Tq( z9X(EwwbC1kWdyX83t!;1FdjbsvlQb$1Hmo4;vZNF2IfF%nwzgnw_;ou!?3A4JpSzi z7lJ%;e5jFVifdX1rin0{=z0aMuyK6lU~}|B3|icXZk@5Z-P+jR$|eXCI0YRd7@K54 z?dI8QYAPFnKj-4NX3I2MWp?+kFOWjmGY=K#`_H?RIr5GD*n$m&Ozy!P0t5N=T|27ScFT_lxAG3QS}3XIGsjEjr@hiTeRKHByn1~ZG1)^5X*8pVWpKYW!x1j#UChQ?$ zumLpf$O|rUMEK>dHyAPeslaix@Trgk3gB7??PCV^wFElF59zyG-ndXYjnsIUQdq7^ zafu!0yqlD`d_&m_ll5R1uR=otNjv}Q31vHmv3z~hl!&wR@|$R3fab32qS5nK3LEaA zr95IK6D#4DRy}fuev|zOOy49@=KLUZTs<=&A8}+7gR9t zA17N7W>=OhSUZT{-%7VKOBWcH+lMM6#gMHlPdXmfA? zm6!i0UAoG7hFenO-=Td4{3Pi8PDzq+@Au6h6L8>$7lq5IF3X?opt8@5!5xQj-YCgm zUma%HU3#_5Z;q}U$q0s@ig;SVs(fd&X?jircRd8nfo~?fdPfntV{#7rgrxAf*$wmX znkdrl9pxC9z0{h7I27>Vq&_BY0hPYMR6_JKtzQ~u&;Tq%zDwQ4)`Y^b6NETXC0S+% zNZjdQgFkLORT6uHVc>rBMF`n+9qzyRMv{@UcV;|%+6Ux)`gHF=UD`nOe#L0Vctz^T zb?R>ZQBd$)hg}qu1odbcah5E()uFvM;3(5-@Fv&_b^>~$^3TAKW`%pe`OLm9nC`9j zjtrue3g}gU-6(OZU$TqevMe$Rs&a^v=>oR^6`RDj44#1sE8Ut8Z}K%QeSb^N+mw!a zDxxR=Jk8=x^M_&@xM_TyIk1)kpDuA$`X0DyqK&;A--sv6%!e{Fd~X%0OfL&9w6(Pv z8+~mG5C>0dbWraJU{Cj1eyC7{^uHLU_RrVF4QMvhfToxI=KZ!hLY`)J!OK=F!Nj{F zp`HBo5})UMGnuV3vHS+Viov~~HTmw+ZgV#TsBr{SRKtBx`o_o7ps~qL{s5kQA9+Qi zyXNI;DDU*Coo~HtDw_?}-~?Qe0FP}m3iPPb%?XFW`}s_dN;rg!+JL6Sfc&6uB{vE5 z!ahlp5zBj$d;w79p}+uPD|byf{`Fq}M_?cg!`fPbHVgN!{7THq?`~uuPZ?&Z7G2y~ z@CoZAFw#TKToCTl#!#7iYc2tp-hf;G%9x)O7S<8N%Q2D{lw4*6Sdu}u0GYYKy(Jl9 zi<0|>#)=x1+-gYk(?dfX%Xc&Iyn_9K3R#p`c6QHn^XlYyx!dXRDnVJYcTC*k=av zGCHwZG{zM{JpxEpt@rv&$_EmVwwZG?VOfLqTPLu}Qur#|9v?88I)=&NOG2^ZOyVVA z@H-PDZteB?yce)qscHKu?@leN(&=lwY_mR^`*OcFWY$I_vVq@qye=>IxvhoI7#D-{ z8!x~VC-eI#Zd_POHaKtK-w{U>}#(f^uKgO=yj3k`FTkl znF)qNEJAdS8yrZk$1Kp~ASB~3^wlH(5@Dd=ExF7%q}`BO8a~tX$I*ktxTdC8?L9q2 zmV#>~W^R|?!1*{ZL?sEO*ZAscxG`{vGyJeDO72!0pcPBzs4H&aM}}Y8mQZil-X%v&#?>YzoX5ftB4{G<};Wu_Vs#SU-$9j#=v5)yxb3_0DuE- z9fcj0eLNP%XvTe_er)23s;cHfS*u8>Y2|XMp4*6B+$FjF&!2*tf2Z?p2=89Oo_tU^ZiTWwUl{Sc<4`;`a|*z3!%< z`A;Jr^x6={3$=6P%&HI{rQj06s!%;BVyu8Put)3V6*GVfO>s=p5YR3Wt znyS4w6AMks)82qvoL}PqI{tD(mCA}MQro=T@N)g1_K7|=`#V+ef+?jrDePYAlRRfw z^7`_CeHkPZQaXq#HmhD=f48+6pWsbY1Xzv6{yp844!rT23l^! z;w;&{yJKq_OH`O;g6B6D-2^3nW-^cFJ>~XV8&TDomWu!Wp?~Ep(@(zm*tA?}3akk9 zH%65I6u){|!8wgtpDB1V{`OO~FOTD6V`5@%0R2o8Fs|Xz(MJ0E!Id{lOoZ_qAhu?yj#n ztX)1_R7Ob?6ut0ROM%CWLC?sM`=?z@DjrxxQ}j8t&7=}FWBsKvKe7a8-%t`!i|aTu z68;6-ofJ>-nQd=Zy&0!rS4k@Mcy4RE-b!R$-TkuXM|<~Rcl&3YDOkZf?n zaeO;B_j!>QREJTS4IQp;oelTSGrQ5nR%`2 z7ywybOFi+c22GdQfPdgn3xIBYxc#(wtS=d6Hkz;Huahoc>jN65pe?QY!L6=x zUbx&PtO#b1JE-Q8gdLZp_YV`{!!qlp3drRFvml$Jq2b+kNNKa`xr~pWFN;aN3(7Gg6L7 zntbwth2BT$`@S>xgvq}&qmEuAnANQ5CJiwzB~9(x3hZoZx^Wg#9m>&x6*@i}yFvA0 zyDuwdx+AvJ5J0OCNw3eX8oeJ8sLd<)g_ce!!UC0y2mvPMpwt^eA+y)(r{xOb6N#=`t*+$=cfbZcTqr&oFSW zR(au!O4FJCxa~B)@uTcnobWonX)hL7l-Gh)AZVuX1r#!S=`@ShQBbyD&BoW>6%q5< z<T*c)#AZpTA@>z(d2x2t4~H@umnr0NgAMaZ7G(_45B3NQ64`akTwby$?^ zyFdCOg3ADw0wQfwBGMho0t7|6OQfV5BnJx=BqT(-a~P2BP((_)yJLt!y5ZcjzWaBs zefD4H-*cVKb+KG9z|6ew^E`Kbg34lVQmp0o?=sBEEH}qu{klO*+iIR)Ro>~cSM^EW zuJggHAx2Y30sX}*Z}4lT)k3wy{+ojxZ05kZ>b!@xsHQe?xK6V%rKQ^(t;WX#k(L)& zZ{6ZnXe36=y3!OPts1*~y0=F_&OGmWmE-u83=N48$2i#x7-!D)S3D!}?#tUwY#l$Ssx z!d~JL@@;FxmZ=Xj@|-&G*T_<^__#VbQ_W1GD*o~;62H|WI(u$$gnc4gI*!J5j1O*H zWV?R%$G1#Q8>L|t?pTZXnA$rm->jZ{C!di>8Y%S%@U7`ocaaQX z*|rg3U3J}9y&gM*c~TUc*-}8CK~qo56ONcK*4-u9-?Beg?%A_yOn;fZ9=mQ+KpTQk5aXij za4l-A8B(?Px_dZ8+24LwoZNpS`G(hF{xMp94#$9F)yUF)9ZZ0fT%~lAe0$C%Y&}Sg zT(W)%TYuhQZ2P-!OiU%iTDPS5{Sl0LVPvNA+|rOurIXS-Q+ZmWuu=Sx;SB)poPO&O zB;K&N{lX;TAK;=;)U(hkR_b2s)c#ZOU~@Ww^f3|gejz4LypO7vF9mL1Ni?5)!pq@8g^x-~hL_nBA-HdK z+a{XFDb#yx-!gt7lR;gtqw3&OMeVpAgFeH7@gmdJ5mgdQi_Sa5KUG1DCb?|zWxzpG zuxWGsEnBKOdLd`EO2358l@9TK_zWGgDj780`4qfu=XXC_uhg)H``@frK$tr>;Vz8>Ws3QoaCx6Fc^6uFRZ7`MwkTg@_(IYFYG ziBUBt-qj-2RjaWV5dRVoX?O;i?zc=CDJd3KR=I}{AL1{EAVdYV7{2O@JTl74{(T1@ zF01g^j7DB{*3h7e6D-V?XgrJ5X>}r`e(s4wga_V@yA__eg8qA&DYp)T7LS@YD_r)Y z8%iF|y-}@vXgxNumsCnpMA7pPN|fTfnuS^ygg+bfonK6>cUYwK$MrYXTlY;Tvg$K(`e{py({vE2 zj*W(iCSxwGUdFZVlsZRO?66GjafMER_fg9WtC`_6xwx;tmjvM*H5D%Pv0(@E3$Jbu z4xWu*)A-}}`}601+B(bLOx4M9g1RUk>k(C0M^^*%{?QLso!x#6XQVJQHA3-e$f`g5 z<1L@T8Z}YF5n_XN8si2k(M?elAI4G#F`KVtV;n3<0J_xtbkNn~;C4(i2<7V732EJ_vS*&-ATI;y;@U z9B7-dXrgFgK|!^FJQ?j?pm*Qa(1<+KMuN0Aadax6^pARy85~<3ie(VyrEX=Ft$v?{ zBBNy*^vtPecBEK5-3^U_P?u-KNPFY((nP3giItWxa7dTmyg5>l7g>q=vy`}rPxel(o z--hh7RnaEJ1R`QVehu)pn<}-7v$Zjx8u(1Ff?|cJex|Xb8NYBOB{7WT2+mpd{Fhyl z+gbmd7h61ESAP3vWA8$|s6qozY z$17adE^)=QmG%W{Y01ex3ypMTiJ@!k>1nkXtFP~YBpe?$+$LWuqPJ6IIft}WtI1O%ZA)L5G8b;%h@s`nt%>1Fg>eE7b<@WhS=p=<6dPCYup zOnj*HUiEJaBB!<7r@kl4s*?MrEeIBu&vc4my^y+iR)zgcM@v)Fz0T3)fwcl{+ksrI z*YiY(nbZ1jsfNa%I`k<7bUuXw?yqVqoZUJtHcJE0XzAb>`AvRgwhJ0Un0^>-wMJ6F ztMPf^&qg4CS&ZqT8M007%lE!@FeFHV%<4xK%whUn*G69!8tIlhjayWE?ziv>6vwww)MFW}u49l#kh&^%xHi=YbTUCmDyuCVgS2o%7H~?9_GCt@5=wH1cDQ&K$46 zp4qV3^qq50^6-$78vk}}bK`y*wE_Epqo|uNA>#J=>(|T=AO1pv4Cg^+To3+AF|)!A zRN*qE-gen7bzUB356I^WE>;SV(H6K)iOfDLJU60+$%9hm7$bFKU=P$eaw3>sO_uC7L{xe?S+!!frMqfnbK z)Sqp{CY(XwQx!wSDQ{bI@(DK2y?6}42#K-xA@QZoxz;ZM+q3WCyiJu2D|-I@40;B@ z&(TN6#~1&lnIP=}#C8G^j*T5zX07qVMOI;b>$@4Xc`dxGBZ6=%W^~PT( z9*OO-LeXpGsPX)VkfhowaVRCfgV~T>%>q8cd3r*0YW+g;K{`c=qw2wFEx((32Ok<0+e`_e zXI6zvHR|o6?-EeR%gUa2Uu|eCdOm&+JrnHWseSRws(N{dKmMc(GUAFVdbR!n3Z$oF zm97KPyq3^lipUTIeU&6&5-kIbD_@A=@4pjIjt@s}-iOzTFwOm&0+Hf`GNH<#_?s>S zy~+_=kvPQI)<1ljQ(WQx?soOwPC(8(!aA0+va**yGqaX36WUhPrpG38LI z|25?n?b?wm?>@7gtKJdTv9pN&HoUzVM~$r9xqDaoW)Yo=lSUGw20H}%HGPi~TT@hMk!Rlbs>pnj zaQ^~^DjMz8W?HyoGmdVqXIh3rMZMIX9h;pL<~z*Ag$(xEp7ZX<#nEDdw!N_=)xsOx z-XjFessp)tDyF9G95Z)r-`2z!RJ*I?<_eZRefRENQyV+VK!Z2x>2QHbK#A2*GUOh` zRzu2DQ&Shn$TT8Y)nMCsjqCu~q7$gC*>FQ%0*xIGvnCf@a~Koa3EREjLNqx}K~A1m zCa}CvdFnVLty*$;0$>9{-135kHUYuDM-2qj3+G^)eXtcjR3A~dRcV#c$u{x(lC4#m ze)RT8t)(=4+Gv`RmJ-mHKDDt-EU2DPyUU&@^~qidoC^~Kv`SPF-%I2qI{YkaH4hfIeE z5+BG%aY=!WfJx0xoPd2YUcPmP4|sN+08)<2+n4!tEeSfYvz8M{l568d+|Em?qNhij z`_YVb)lgfi$;ryL+Q)1T>2h?$lq#pmxy^z1sZHGM@^VZpw^R*|+tueVLZY+&njF7ZImGgPxRp{-v-xDKRYX;=l4A_d^S8UU;O`lsf2q03d za#|bL%Xp@Rio)4cxU9MlSodReGJr=nYk6{dm7F{Uu!ol0OMR#T5fKrJYkLDvdh_%1 z;i5J7=>i#92_#r9#-6XM2H{29?e)gO&EmCp=M5}>yvuVOHU0U)n}$D#1Ni!i;rM)> z)0Dc{aqQWuZYlSKBNXT)*90X9Wk|xmKmTSZgfM%~h##xxcYPi%HA6ROnwt97>>b@| z3;3GOw511-5%;j!kdxnG%9t0heSg7(7j<$wca1=^*d8k_^)#qypl11MZcoMgWrtDI z$;{V87RaeBB&5ZL&BV};N|M;D;@YBgMpakJa}ku49tqf{m)P#J7#y|-e03SH7CZKQ z_?os3HvE-oBdCF%g@!qvxL-pA-onI4uiBk=V1yPf4K){_@$(=2>m)`~H}&%kekp1g z_0~9g$jA`*c-p(}c776MmH0{RVAkq;5al&I!4mCsHlCJ?xQZzKSj8K@r-y zkB^J_?-_ z>{JBgjU2EUx)}j{2R+5by4Qq4UI#_(@uKL|)Kt3NJk9)MV6A2c(F$jOZ z67;8qts_&f()8-~A&zbD$qhkl_uLJ&T-{dzZ+Tz-t^U$+0g{mlP=z96U&3hfI!M5Z z^uPMnm}|jx;T)q}7r)NQHxq_IEqCn-8@);srQMAk<>xoNUEJ2@tA|f|T5$0WZ{^aHE-vL?mps%?HfZUelk`9#s-^ z+b9?syWVH_n0fH`T)=|U>XJ!-ds}CPi=M3T4Ka1v{`+0u3B{K?zl&BlU_DDlh$GJ{ zg_&ad%CszxXY$P`D0JIx1Yg%i@#eayy^Tq|;Yy0ptL!fYirhNB5h3;HpMQRS0%c;d zib4kZYF7mbAA_=6TsLfgn-<>3*KfF`CGAWy)!W#OIZG~@!1sKpG`SnBTHP*|gt21B zmFk$`bb8^P?cXO~p!8zX{%HTPl-Ku=c#rkEfP^zmpHj+~z}`%?Tkrc^f4_C25GAHQp*Q`@ zF>>pBoKb>Texi0`V}*f}#69DgqakuR1%<*)zrI`!s(~LmZ?P?Dn{rR@RgJJyvZ;mT z8A#-o$Uptmv3_D=xW2WazD*M=91ycM|BPPT@b~0p*Zz(;Vb{Tqj=a~mxCr*`SBH5U z8X7>fNEXs3DCI8v^_SxF=ZR+s387qPk&$^v&Ux+91Thg&V3<>X%O9k0zxS1FjY|*_ z;=*YiT|4fMzP{^tNkPsxg74y4#O2q8$%fcUze-lMJmcM&l2@tkwM87v$k-79^$3e% z)iiB(nMOr(1C;1UN?!bGmqutf%pf4&yYsV=_5OWn{rK^X?TaBOi4eKN17QJnIH0QA zogAJL{o|&0J zLp&80B1QxvHs)HBT6{A;em~xJw1}~@eDyw zPLeLH&a5s1%lzLDACJf9W&Rt3^uNA6OG+~NU;q1m|1){}B_PuN#|P6x!vAIy_MZm@ z&eQyN7V5v>tdqsRwEyw(>O*i6`uc2PXG5&pRh!N|L&mr?>A%5{_jit_d@*d zRs63d^#9Mbm`gM?Wc5WWv{_mUNo?YdX;WV&W_c3YRb!4MzI+hgbaE6K6=i;PK?Z5~ z+V!&NfUw&*R5q58fWkm9{`3-;ag@nC-T6dKuGZL9ZkW~nS!?H#^;= zh$x=j3ffFV}ZB#Z#!dVg!$&LrUSu(@LQ4u5|=yG`a6Qz>8YW2@1qSr zv9gB$#l7FQS95l|MjN_Ngb4G8GZ^GPeHNSfYxz*b$MIF2941+S>Wsu&t0nQpyqHgj zqOMw7y4W-29C}AYLP_O*OhrK1FJd3}q2Agq12%y(6835=F$XVYm0W%kAX0$}eA|(C ziu29>M!x0ACUyTUOL9EXI3Yo08`Vwa-*UGGn_RJy@X-NdT6Ps%bTqD zbSg86eLUj7Ki6cWqZ?K44iRolf2yTg-NW7S%t7KF!hA)V6t#LVO=RHZWac$h^WFfT zO4-PrVg7Q7>*%WKUzM!p)e%!q3-@Pro1bIy&msPA`-ml1zl4gFIZlEa7y7hc$5yKs zrcl>JUj5l;1WCU_;boY29edT^og&iRyM)AseNU}6R3kaO6IaZ2gp=KDwjidiT8X=e ztQd~Qm@K2j^)PgCga}=l1l13dRvI=rnwKf}5XIRD4#uk8(efw#zV5V_d}&;ubuRVh z`|}SSHaSl<=R&zQJuXYEt7X_6Q}-`LSgP5uv5dCcBZ-e6v{q?$kFJzHsJh4UQ{N5t z45w~~O)Avo@x*UmTUsFv>YAE^uPnELqf#27MY0kHZ|h9q!|~7^Gk%+pq=Xz)(%(p| ze#4UISz?KG^&kJvtN)+Nqg?WTgCzcn{BIopuXXXi+0cJoi2qOIl)Civh#em^Yb)Hh z(_w&0K^t@Z?Zb^tHg<7wMzu^ubsWwnDCjT5#gHos`j;udhLe(!X?^~H`TBJUXy0DA zbV>E&l`1o0B$R@R7PCB%%goCwg*DF#y`9kQy#a;K94oIXxGgch{^7E^!Al(|Ez?*Q z2&G9&IEPVK`Th9vOj^`v8K%F;TBZC;(U^5YCasd3ylnB1XZajJrrcs>VR?u; zu~&lb2ULY&!NGY)M}(BhHC!E<$e?O(Aag_GFE-BmN?FZW4x4r==C$1$>zhhi=k)mr z5uZ0n1f$JRJy|TY8_?6&KbmW~ae)M55mv6AJDMEBpK^LqSX!D9kE$t@pKr%V`aLuM z{)TtBa3RF|c)P5-hdakcqaYQ%G(e_OXu7?%)kDA4DcQE4bZM{)7@J$rb`cQreGiR_ z;n^v<7cY`QiOgLG17-WtV7}4og?7yBtT9yb>N+J>z$6-hyKLlKiSKcn_efihl=Oi% zVLE(SX>#^YWVN_$|3{;9_*a=nb$W+PA@5Ab=HdIE1DkfU(!Th`ZWVb(E1k*mi$9FH zu#+cx!<8NZJ8NUww1)k^h^0*{S@@PNI>REhQOYAIJK{a`1jPa`~* z15YQc58LlL%2RVn#YEcHU`m)Af}#6u%~g9l(A_$`BzM@NaNhyFI%Caym@x!P!;WL5 zbnOGoC1)0|U3K3+zzYH5D#qGkx`w|^nb8Z_J@q3?=gnRNnE?PE=y)$!jIe3szJwX1ki+Z;xY+5S56H&O&OWl*`h^|+ zE07i~6>!xZT+b-4X})R;Zfl4+YV93^=rxiQnbx-EcCYh?=Gd;)R)%T7}#U2B9<3vtk+G9nMHy56n3zHhk9I|_eGXa_K-;sC{v+#RsZR<}M$ zVoGp(IQQtn8vi}yiOeozAGSUN?(>fsQHIFU;N8!+bFTj%EP!5V0HD0aXkC{FPmF}T zW{cYC1XF(Q{j@6GUEl5^Y-3cc|KqzfiY{aw$h2x5baR-RCBl3yoh}(R8e>pd^%W5( zKf&^tKCJ?AcoUG}e(>tg#b~ZMy_ny;c9WXWx!qh7*T~Uqw;`FtmL7U+NPZdw#LhC{D+ySQ=EgnJbe@`OryaVa6vq1ph@ z1Eln$DVa^QQ0_NT!H}Q)oPq$fG?>5^k=W}1%O4bEIQ5Zf*klAbX=LQ5xSX$w*0Ak? z2}}5pRr_{Te*SswTJK2E`Ama#3oN^SNYE0a`7mZ-qh=lY-TV{xK;6}PV0~s`1EwT8 zT_C`{`tRrDTXXk~W*Hv$t?R%yslPjfjE=<$Iu@Dt+{GWe!NCeaB$F8m3H_jYTx35Z z9VdjI4qoa;B;qse6S5D!UQg^9FBCO zz^<3Qz&>`G`a#65Q}R?_Umq`cNlZd>+rYpeW|lCdFiJ(dcfU|-`G70O<(Q7PE|}p! zsx{IR9XHaC9qwy&i#~+^0^OmYAETcs%ShHIUb)j>S1Qf&pmV2#6PkwoIogRGcWWZi zu~@9RP#G$c6y_7uDl+KSp6c!X&R|O2yFcfL5Y6F&7XdXir+s7mMTKAJwM|D5@69E7 z_5jUvYji30=XY|hsHf%e{G4J+mHfDVTwo=y|5&M0<#ho^~ng5=TXox?TMX#bHl2PfzH(wIjXwEMSp`B6HKCr6ZEAqSLr?Z>mhcvObbOUuwO*c?Vho1;fw8NYwuW7n_J52SVN3ul>_ z#~O@;&2 zNWrs~+`V&03cB2Cpifi;A>m9LOfwy!e=ORUl~f_RpLoKJasiCvT6k=1CefxTHX(RC zPkuRah zkxuDKcQiGj-tLkySX^&3P;nPyG^GucwjQr4ts@C@1>VYl@Y>VfiyWU4&(qaeD=RA( z*-nVXbi~BQ=74DaB2hZ6^Iv9rC>_$&8}oj8zxGs|d1tK?5401>8oz$PNxH5B2NxE1c9;hqt@tS_g81 z{N9~K>y$pT7%KSuND>V_Tp7SIbamMa*-uviq9X6k6Fz1@n7o*H_wKgy%Af|g!lul( zF*2{zUVs*>s%kh$QAOnSm0o-SrhGJ@z8*C4&et~^AlT5w-kaDoEFxtP`D(2Wc#ele5+AW19TQdMF3N2QXXkKrC2ROc zW@#hMvBGU8yKgm6I>ooPPbUK1s~C4kJ10!*GmS@8pFBK~`|w2Z(f!<*U4S%v?;z>l zGU=I{o>qQYjvr$mxZ>9Sm;uB_fR?6CX_ijdMIDTpk{SXAMz+gfBUQVT6b>J)E-$Cp z&k!$zyIbKwN{RcnoW*caJg7di0M;p9I_OB3+w|!9`V0>Xixh~o=aMq&-zOv6eRNof zG(-UXAX_yHyys@7rzse1heD_*C~n)@u6cGWRLy@O6<`n1knkKS-c)C}sQF;wFR*`;97CNRTlAy{$~zM7 zq2^jNl*ilyH>*!0TB*Xn{%xj|r+@2dy#Bs8Q$@x6+Lc+Dyl7W2KN9y8mW+zpIi8)2 z>(9|moO=d^S{rISjw%x_g&F zCwi;?wuy-;tD1gy^Ex zDMhzB-{Lpek9yk7NAC+t>BaBdkv~Tk-scu@d}V>;|h3q0oH_q<8GR^io5$Auk8>5JP6 z2+H)LxJ)iMiLV1NuBGW)l{7{*OS#72UUP?66Kqx%5fNR`Axng;B6V`|dBnZ_(}lQq z@6OVTyi$ZLwik5#!=o+S7$Q@lO30G*BZb9cUQ?h$e&tFs02n^roiaP>CM_p8 z9h4G)T!gn%AM5-lq#ftE%p=sl&#oc@sc5t9-y^Y zbSCCs-3|$PZapfXu{&YFrmzXOKvvX)H2;8lh)nz_QaZ?ZPRFb_S1+Mj*oE$;z0AI` zv2ki;Dos$+*%7ej_#}3EcN6xfRcVmbyIC)ikq9b~Js`eadMPUuU`x-+nQfnt;{AfHiBMtr9j4;3*#^y!) z$=mZ3I_5e_7?`X_gZqpMsSPBjjOUi=Sj74&=u|x(+uv_LFs`u{s}8(rVs9{h%PZLzd+LKS&+UwboR+o@V~}~x zUDHR;02BnOVOo<1*EYiQK$jcH_Tjgift?IU2&kH?d!bDr!dt&KQELDWPT9F2R_N>r zE}DQEc^O|YH4ZYBE9)Sh`2B4(CKaZp$neShUv{3 z^OBP*(AC?WLWyL_sw^y6d=3m;{$kNo>#ki*wZHRceMxw7OvJ2S6gx7kc4_7|^xOF+ z!~ZifZ&%GB!3zFkc{L|L6IHpb!wab2`9@3nZfzz06YZzJ(Y>eNTob00B1R?}QDORj z$ucMTjt5+ql2H9SB$-)CBAY^rfF(Kc@ns64?}U#zuKxYE;={lHW>F?e`|FI1zt7gq zJMYgvTKc{Dqj8gJm-Kd6^V7Tg-uhT=kAD62iuTwck36pl0*mpQ^5Go|baZg4*XP8+ zn0)uVQxEOx!9Cr_p^rA-Thup`T)1$)0Nps@y)WNL#-Py~SbMdy%zLgPh(REmyEdVG zEqj9es(dH6UPAtIRny7UXC!@l8ueU?-@CO7JeR-uB6ZDWmX{(we5%S~ieH>t;=^${ zXWP&51vDfRUHp~dv8NL{T;lZzoB_eX?AQ0-;1-grlyZ=MNX+W9Vh;6y`%ECe?%1zW zI2nF9?Nx#%`~kQLbr=7525w;#3=Fv-#!u^82igfa;GVHwM_i}Jm!p&WKEZo-iSMb@ zXj%4v0rurVT?4erjDEE#jgX4==<#!x%AZACIk9cBzJ8(%3=B*A?gzCR1jgbuHDWXZ z-(tWIO6&V~ENYOBCR*o7(`Ij$|+gH4J-%Rl`37{ZmpKaknDrYvSsU+F^m3{&rSoxA)-X*&Vf-@8dY#QPqvz=Gc!*!$uOmE|zCQ zyj~r?LT|Fg_1UV5&ylvp;X2L{oiqQDe7=P;_Q?~|`<$~WHveD`^J+BwB83L~CJKgH zi>3=HUA!RUPi?O`UhuIp-Ni`?xoyPW(699-;kDMDfGqjYRSDbOaA|#WA@Aix&FQcn z6~fhu?aA0)E&WBMD=I1q@GFtZ5)F(>M$oSyUfj3qvS57(alf=%j~vl8{MkuGaoJG! zBfqO%rkGaM_uMI4#HYx0ME|(#L`L!`>zP8<^jk{3&dWYIsZSy^oVOOWgy!|{@weLe3{q5*r3w4_H=%3E(_Ku8_Ijr61TNO zeBA@6KkDEVfN($aPVyJ z{rr|OrI!Lko`gP&7s>kh&!%2EGD}zPa1K3@SX%5oa$a;KDN?U~0@X@Sm;I5Eolh_I zyG60Z$b2z2+m#7dQlo#6e*=e|OS3TMn&$jY@zpWV2|o z^O2>uPKsfe-w^N7v4X9<+mkf5Xj{*k_m(OMQa}f~<+9?(TWE98FZhJXnVFhO;b2!@nziZp9(W(IRZ z^0(`q(Hbv<3JW(65A&UsF5t!0-qKci{5S+MMC0fuwzfz?Mo7rtU=!4yOGNYg-TU`h zu>8}@6TA;t#Ni83l!49?`OLyD5KgV&$$*XpIbH6O>b) z`a!Le_DDG!eF6MtdFzV_jLD!MrT&(f1n2ftS2uQNwe=_fFE$+Y%VTTtb5h0C04cA- zoj&k8z645+C)$9S?@;tYhGgFR_w^oS?d*!oL;G%P`D9D{Q;CM0od4ZGR1XjTUZA~u z>O<~~?K9WShP<&SWKn)D)Y-*Px=U%a)C*jiwdsdYKmT6)qkN8%dr0Xb!UgBYCK2P! zTehq>ZYb5%?Br#}D7D3iXSRh@Z02+J1)>nYvfg&>`N&shFqXv zP6WpiYKPCCKeOtOa!Ni!{*=nl@(j$Apf9a24|MN#H~Tub%FieibD@Sf*cmcULi{7| zp&iYhjZ=zmE!!Ns%_U#B%4*?ijqH`mD3{v=RZ?b*N))Q;R9b_V8P;tD1%l6>dDt%c?PH4 zZM;@|F*`?9eSderA>ha8^<%vM_Hpr>y%p>lb$hADfN8N!<4s|Njw#3PtEZ<|_}7q^ zO;Wmn-z<@;g=Nvc&Fy$tIV0~UEHrlwvAHCO#IyOSC1RhP>&y|1nYAbG_v(vPXz#oJ zT$)BEA45Matj(1BC!1>Kb#d{{NUiRAILGkxpd0bfAp+R~<1#VC_zOf)V;V*Q+)h?yWzI%jyjG?8j zzg(iT_Cwb9{co?1IG&Exg9+Wyn!VQrIKW8p2Uwb1RGtH9y%IP49BoltO_6CU&CF6+ zczvml2$8Au9`k&HJ=)(CUZDed%LjpsqVBzh3jofjcs2Ej^r)cqZ`9;>A@>|ZXc?bH zh9s?=a^{0#EI%xewqY3Zw(Yzn5r^t@_SkBb{U z4<{LLiPVakgS5P)x0G<5qyOF_`-3f_o>$KkQQ2&E!cQ!!Deo^${MN@y z1H?Y43a6b=?59t`dBJbqyw&Zz3>riv_%}6NjLue0>rOA13Qz|sGK5P7=7Hv;R%!GebFF4of-JI;90o3ff=JzG7n_OaG^ncPo@cnT zNI@_KlipIBqaF4EV53t4vLJr*zOCqGkcVdB~F7@yeCYRVT zE*vVd858Q!1qZa)(Kcv`hw?biKMiCQ9}i(u%MJ%sB;1=^xG3xEu0@U`?mfEO(c9g+ z3s$UX`*VJ?`RF_pw+?~sf#uwKm789z2cgf(l%Hy@JbK{YNSWhHU^jW{ae!^)wR_Gl zA5+rAgZeXR-x4XTZ*NF26zJSH|H|yYx<*Ye@OfnN) zpm-2yQ1zf(PdjV`pEm;0^x z+wfFN*y5|5Ni)Nh17$7Ietv%OUL{%hpBh^ouhz+U7RU9|%hR(rM~gdS=L$7-7M?l- zt^`7E-DU1J;3^L;p$2%`Y?c>6lOUhxZt)8vTbk+p`U_d6n4&ciJM6Sp&#T9e^*wYd zpS;Z6NA?;nnyIF!d-=t}%e!jN{zymNma~o5_20wb0hmbd`LU?@vOv&wT<|uJF4e|> z*db}O7#fj1!nXM8t=tan|D?1eG`;P;K$ciht8g;! z*@JnR^YqX2Kn=fN|L+wQ8!tO^8z~#csx->a+<6kAaTF)Oeq@ymvZ21YdeyP>(Qp=P zS3BgZ=jrBbP%?IY;OtSYv>}u!zJzFvqsI4wbJWo{#9oa)F9{(E!H&C`rH6*8Tv`YE z95mWn?k_H$exl)R;~59p27Ewt;71(J6sncn$%5kS0trc5xMO=X?=q^AL>gi-Gy)of z83zC!5FYyC$ooqw6hM|od+V1_giSoMvLB;)xAl5PdoYzvJ#4GDC`|)oAEVeWO#PLG zx$S+Zo+G(LSO*NO2ndBABJUZ5QsM_@Z@{hR*SaXj6cQ>8EDBJpCq7aU^YyDeHE)Pa$d+l8u5f1iWyni#9i2a96)j+#Y>q2l&s)EF-RCJKJX4%78K>Sc z-_E@6(S>QrxD!7i2ZwFt;UPbx zEo0AKoB$*m#=ql6T(`6v2f|~+t(w#_)gQ7~7CAlC0G5-tCIQ`JsWiDXURRv3MOSj^ zvpAuI^o}DB+U4~bgPw1O)!ZqfND~DV1YK~?Y(6mEzMUx(%mDj1>PLP3YHq^t1#vMk zF;FS0=0UWc82>EhVWbTg{wD(6ubMxdMhSw@aLV7g{gaLFt~OPBLjUJe+(6r6ld3rC zPhAI1XJsJNyGrr#@j)*ck%I8zC;dxJC%1g}ZnZHejs4n1?bH05W%N}aKIl30fQ|+z zG`Z^ST#gJZXwbmXleƟo+;pa62iS|g2gkM4Q%WraV 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%0DG^3U1>fA4n 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 GT>lR!h~HHJ literal 0 HcmV?d00001 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 35994ba6d..436990fd6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,3 +21,4 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. add_subdirectory(unit) + diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 52368a346..d57570ce6 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -49,19 +49,14 @@ target_link_libraries( cutlass_test_unit_infra ) -set(CUTLASS_INSTALL_TESTS ON CACHE BOOL "Install test executables") -set(CUTLASS_TEST_EXECUTION_ENVIRONMENT "" CACHE BOOL "Environment in which to invoke unit test executables") - -function(cutlass_test_unit_add_executable) +function(cutlass_test_unit_add_executable NAME) set(options) set(oneValueArgs) set(multiValueArgs) cmake_parse_arguments(_ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - cutlass_add_executable(${__UNPARSED_ARGUMENTS}) - - list(GET __UNPARSED_ARGUMENTS 0 NAME) + cutlass_add_executable(${NAME} ${__UNPARSED_ARGUMENTS}) target_link_libraries( ${NAME} @@ -72,25 +67,13 @@ function(cutlass_test_unit_add_executable) string(REGEX REPLACE cutlass_ "" NAME_STEM ${NAME}) - add_test(c${NAME_STEM} ${NAME}) + set(CUTLASS_TEST_UNIT_TEST_COMMAND_OPTIONS --gtest_output=xml:${NAME_STEM}.gtest.xml) - add_custom_target( - ${NAME_STEM} - COMMAND - ${CUTLASS_TEST_EXECUTION_ENVIRONMENT} $ - DEPENDS - ${NAME} + cutlass_add_executable_tests( + ${NAME_STEM} ${NAME} + TEST_COMMAND_OPTIONS CUTLASS_TEST_UNIT_TEST_COMMAND_OPTIONS ) - if (CUTLASS_INSTALL_TESTS) - - install( - TARGETS ${NAME} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - ) - - endif() - endfunction() add_custom_target(cutlass_test_unit) @@ -99,6 +82,7 @@ add_custom_target(test_unit) set(SUBDIRS core gemm + conv layout transform epilogue diff --git a/test/unit/conv/CMakeLists.txt b/test/unit/conv/CMakeLists.txt new file mode 100644 index 000000000..a50a58f59 --- /dev/null +++ b/test/unit/conv/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +add_custom_target(cutlass_test_unit_conv) +add_custom_target(test_unit_conv) + +set(CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED ON CACHE BOOL + "Enable/Disable convolution device reference for conv unit tests.") + +if(CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED) + message(STATUS "Enable device reference verification in conv unit tests") + list(APPEND CUTLASS_CUDA_NVCC_FLAGS -DCUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED=1) +endif() + +foreach(SUBDIR + device + ) + + add_subdirectory(${SUBDIR}) + add_dependencies(cutlass_test_unit_conv cutlass_test_unit_conv_${SUBDIR}) + add_dependencies(test_unit_conv test_unit_conv_${SUBDIR}) + +endforeach() diff --git a/test/unit/conv/device/CMakeLists.txt b/test/unit/conv/device/CMakeLists.txt new file mode 100644 index 000000000..ce907e0d5 --- /dev/null +++ b/test/unit/conv/device/CMakeLists.txt @@ -0,0 +1,148 @@ +# Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + add_custom_target( + cutlass_test_unit_conv_device + DEPENDS + cutlass_test_unit_conv_device_simt + cutlass_test_unit_conv_device_tensorop_f32_sm70 + cutlass_test_unit_conv_device_tensorop_f32_sm75 + cutlass_test_unit_conv_device_tensorop_f16_sm80 + cutlass_test_unit_conv_device_tensorop_f32_sm80 + cutlass_test_unit_conv_device_tensorop_f32_tf32_sm80 + cutlass_test_unit_conv_device_tensorop_s32 + cutlass_test_unit_conv_device_tensorop_s32_interleaved +) + + add_custom_target( + test_unit_conv_device + DEPENDS + test_unit_conv_device_simt + test_unit_conv_device_tensorop_f32_sm70 + test_unit_conv_device_tensorop_f32_sm75 + test_unit_conv_device_tensorop_f16_sm80 + test_unit_conv_device_tensorop_f32_sm80 + test_unit_conv_device_tensorop_f32_tf32_sm80 + test_unit_conv_device_tensorop_s32 + test_unit_conv_device_tensorop_s32_interleaved +) + +# +# OpClassSimt (CUDA cores) +# + +cutlass_test_unit_add_executable( + cutlass_test_unit_conv_device_simt + + # F32 + conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm50.cu + + conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu + conv2d_dgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu + conv2d_wgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu + + # CF32 + conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu + conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu + conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu + + conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu + conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu + conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu +) + +# +# OpClassTensorOp (Tensor cores) +# + +# Conv - F16 input, F32 output, F32 accumulation +cutlass_test_unit_add_executable( + cutlass_test_unit_conv_device_tensorop_f32_sm70 + + conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu + conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu + conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu +) + +# Conv2d - F16 input, F32 output, F32 accumulation - SM75 +cutlass_test_unit_add_executable( + cutlass_test_unit_conv_device_tensorop_f32_sm75 + + conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu + conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu + conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu +) + +# Conv2d - F16 input, F16 output, F16 accumulation +cutlass_test_unit_add_executable( + cutlass_test_unit_conv_device_tensorop_f16_sm80 + + conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu + conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu + conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu +) + +# Conv2d - F16 input, F32 output, F32 accumulation +cutlass_test_unit_add_executable( + cutlass_test_unit_conv_device_tensorop_f32_sm80 + + + conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu + conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu + conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu + + conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm75.cu + conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm80.cu +) + +# Conv2d - TF32 input, F32 output, F32 accumulation +cutlass_test_unit_add_executable( + cutlass_test_unit_conv_device_tensorop_f32_tf32_sm80 + + conv2d_fprop_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu + conv2d_dgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu + conv2d_wgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu + + conv3d_fprop_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu + conv3d_dgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu + conv3d_wgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu +) + +# Conv2d - S8 input, S32 output, S32 accumulation +cutlass_test_unit_add_executable( + cutlass_test_unit_conv_device_tensorop_s32 + + conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm75.cu + conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm75.cu + conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm80.cu + conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm80.cu +) + +# Conv2d - S8 interleaved input, S8 interleaved output, S32 accumulation +cutlass_test_unit_add_executable( + cutlass_test_unit_conv_device_tensorop_s32_interleaved + + conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm75.cu + conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm75.cu + conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm80.cu + conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm80.cu +) diff --git a/test/unit/conv/device/conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu new file mode 100644 index 000000000..4d500d978 --- /dev/null +++ b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu @@ -0,0 +1,130 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM50_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 64x64_8x2_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM50_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x2_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/unit/conv/device/conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu new file mode 100644 index 000000000..cc36edc75 --- /dev/null +++ b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu @@ -0,0 +1,314 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 64x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu new file mode 100644 index 000000000..aab0d34e4 --- /dev/null +++ b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu @@ -0,0 +1,123 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementAccumulator = cutlass::half_t; + using ElementCompute = cutlass::half_t; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementAccumulator = cutlass::half_t; + using ElementCompute = cutlass::half_t; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu new file mode 100644 index 000000000..bc9ee6e9d --- /dev/null +++ b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu @@ -0,0 +1,118 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM70_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM70_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm70, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<8, 8, 4>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM70_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_unity_stride, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm70, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<8, 8, 4>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM70_SUPPORTED diff --git a/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu new file mode 100644 index 000000000..7417f9219 --- /dev/null +++ b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu @@ -0,0 +1,159 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + + +#if defined(CUTLASS_ARCH_MMA_SM75_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM75_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM75_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_unity_stride, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM75_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_unity_stride, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED diff --git a/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..01f51a2cc --- /dev/null +++ b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,286 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic, + cutlass::conv::StrideSupport::kStrided + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_unity_stride, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_unity_stride, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_unity_stride, + 128x128_32x4_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_unity_stride, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_unity_stride, + 128x128_64x4_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu new file mode 100644 index 000000000..7682a319f --- /dev/null +++ b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu @@ -0,0 +1,323 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 64x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + test::conv::device::Conv2dProblemVector user_size; + + user_size.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, 4}, // input size (NHWC) + {8, 1, 1, 4}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d(user_size)); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_dgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..48c6ddb04 --- /dev/null +++ b/test/unit/conv/device/conv2d_dgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,124 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Analytic_ImplicitGemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::tfloat32_t; + using ElementB = cutlass::tfloat32_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Dgrad_Optimized_ImplicitGemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::tfloat32_t; + using ElementB = cutlass::tfloat32_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kUnity + >::Kernel; + + using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu new file mode 100644 index 000000000..b3b66a9de --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu @@ -0,0 +1,222 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM50_Device_Conv2d_Fprop_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x2_32x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<4>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM50_Device_Conv2d_Fprop_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x128_8x2_16x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<32, 128, 8>, + cutlass::gemm::GemmShape<16, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<4>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM50_Device_Conv2d_Fprop_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 64x64_8x2_32x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<4>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM50_Device_Conv2d_Fprop_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x2_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<4>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + + diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu new file mode 100644 index 000000000..25e3ee0d5 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu @@ -0,0 +1,397 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 64x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x5_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 5, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 64x64_8x3_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu new file mode 100644 index 000000000..e151f5a78 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu @@ -0,0 +1,121 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementAccumulator = cutlass::half_t; + using ElementCompute = cutlass::half_t; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementAccumulator = cutlass::half_t; + using ElementCompute = cutlass::half_t; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..4c8102a50 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,124 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED + diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu new file mode 100644 index 000000000..15f558583 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu @@ -0,0 +1,81 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM70_SUPPORTED) + +TEST(SM70_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm70, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<8, 8, 4>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM70_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu new file mode 100644 index 000000000..b54359f17 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu @@ -0,0 +1,121 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM75_SUPPORTED) + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..51d2b942f --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,124 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#if 0 +TEST(SM80_Device_Conv2d_Fprop_Precomputed_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm50.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm50.cu new file mode 100644 index 000000000..820f0fb89 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm50.cu @@ -0,0 +1,82 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM50_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x2_64x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu new file mode 100644 index 000000000..746e7d7b0 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu @@ -0,0 +1,321 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 64x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + test::conv::device::Conv2dProblemVector user_size; + + user_size.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, 4}, // input size (NHWC) + {8, 1, 1, 4}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d(user_size)); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm75.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm75.cu new file mode 100644 index 000000000..7255eac64 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm75.cu @@ -0,0 +1,520 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed_interleaved.h" + +#if defined(CUTLASS_ARCH_MMA_SM75_SUPPORTED) + + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 128x128_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 256x128_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<256, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 128x256_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 256, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 256x64_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<256, 64, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 64x256_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 256, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 64x128_128x2_32x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 128, 128>, + cutlass::gemm::GemmShape<32, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 128x128_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 256x128_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<256, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 128x256_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 256, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 256x64_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<256, 64, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 64x256_128x2_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 256, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 64x128_128x2_32x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 128, 128>, + cutlass::gemm::GemmShape<32, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm80.cu new file mode 100644 index 000000000..7e9bb9060 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32_sm80.cu @@ -0,0 +1,521 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed_interleaved.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 128x128_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 256x128_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<256, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 128x256_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 256, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 256x64_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<256, 64, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 64x256_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 256, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 64x128_128x4_32x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 128, 128>, + cutlass::gemm::GemmShape<32, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 4, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 128x128_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 256x128_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<256, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 128x256_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 256, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 256x64_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<256, 64, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 64x256_128x3_64x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 256, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4ncxhwx_s4cxrskx_s4ncxhwx_tensor_op_s32, + 64x128_128x4_32x64x128) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = cutlass::int4b_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<64>, + ElementB, cutlass::layout::TensorCxRSKx<64>, + ElementC, cutlass::layout::TensorNCxHWx<64>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 128, 128>, + cutlass::gemm::GemmShape<32, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 4, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm75.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm75.cu new file mode 100644 index 000000000..542600377 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm75.cu @@ -0,0 +1,119 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM75_SUPPORTED) + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = int32_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = int32_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<8, 8, 32>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm80.cu new file mode 100644 index 000000000..d0ba7a504 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32_sm80.cu @@ -0,0 +1,121 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = int32_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s4nhwc_s4nhwc_s32nhwc_tensor_op_s32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::int4b_t; + using ElementB = cutlass::int4b_t; + using ElementC = int32_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 128>, + cutlass::gemm::GemmShape<64, 64, 128>, + cutlass::gemm::GemmShape<16, 8, 64>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm75.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm75.cu new file mode 100644 index 000000000..fbab37316 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm75.cu @@ -0,0 +1,679 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed_interleaved.h" + +#if defined(CUTLASS_ARCH_MMA_SM75_SUPPORTED) + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x128_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 256x128_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<256, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x256_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 256, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 256x64_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<256, 64, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x256_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 256, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x64_64x2_64x32x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 64, 64>, + cutlass::gemm::GemmShape<64, 32, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x128_64x2_32x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 128, 64>, + cutlass::gemm::GemmShape<32, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x64_64x2_32x32x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<32, 32, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x128_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 256x128_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<256, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x256_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 256, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 256x64_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<256, 64, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x256_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 256, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x64_64x2_64x32x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 64, 64>, + cutlass::gemm::GemmShape<64, 32, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x128_64x2_32x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 128, 64>, + cutlass::gemm::GemmShape<32, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x64_64x2_32x32x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<32, 32, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm80.cu new file mode 100644 index 000000000..e8b7c44fe --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm80.cu @@ -0,0 +1,680 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed_interleaved.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 256x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<256, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x256_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 256, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 256x64_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<256, 64, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x256_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 256, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x64_64x4_64x32x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 64, 64>, + cutlass::gemm::GemmShape<64, 32, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 4, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x128_64x4_32x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 128, 64>, + cutlass::gemm::GemmShape<32, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 4, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x64_64x6_32x32x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<32, 32, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 6, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 256x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<256, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x256_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 256, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 256x64_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<256, 64, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x256_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 256, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 128x64_64x4_64x32x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 64, 64>, + cutlass::gemm::GemmShape<64, 32, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 4, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x128_64x4_32x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 128, 64>, + cutlass::gemm::GemmShape<32, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 4, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32, + 64x64_64x6_32x32x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int8_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNCxHWx<32>, + ElementB, cutlass::layout::TensorCxRSKx<32>, + ElementC, cutlass::layout::TensorNCxHWx<32>, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<32, 32, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombinationClamp< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>, + 6, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE((test::conv::device::TestAllInterleavedConv2d())); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm75.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm75.cu new file mode 100644 index 000000000..e5146be32 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm75.cu @@ -0,0 +1,119 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM75_SUPPORTED) + +TEST(SM75_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32, + 128x128_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int32_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM75_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32, + 128x128_64x2_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int32_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<8, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm80.cu new file mode 100644 index 000000000..4cfdd3722 --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm80.cu @@ -0,0 +1,120 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int32_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = int8_t; + using ElementB = int8_t; + using ElementC = int32_t; + using ElementAccumulator = int32_t; + using ElementCompute = float; + + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 32>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 64 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAddSaturate, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_fprop_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv2d_fprop_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..c1a1f647a --- /dev/null +++ b/test/unit/conv/device/conv2d_fprop_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,81 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::tfloat32_t; + using ElementB = cutlass::tfloat32_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dFpropKernel = typename cutlass::conv::kernel::DefaultConv2dFprop< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_problems.h b/test/unit/conv/device/conv2d_problems.h new file mode 100644 index 000000000..74b43e11c --- /dev/null +++ b/test/unit/conv/device/conv2d_problems.h @@ -0,0 +1,520 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Implicit GEMM testbed sizes for Conv2d problem +*/ +#pragma once + +#include + +#include "../../common/cutlass_unit_test.h" + +#include "cutlass/cutlass.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" + +#define CUTLASS_CONV_UNIT_TEST_RIGOROUS_SIZE_ENABLED 1 + +namespace test { +namespace conv { +namespace device { + +using Conv2dProblemVector = std::vector; + +// +// Structures to prune items from Conv2dProblemVector +// +// Specification template for pruning items for convolution problem lists +template struct Specification +{ + virtual ~Specification() = default; + virtual bool is_satisfied(T item) const = 0; +}; + +// input size (NHWC) specification +struct InputSizeSpecification : Specification +{ + cutlass::Tensor4DCoord input_size; + + InputSizeSpecification(cutlass::Tensor4DCoord input_size_) : input_size(input_size_) {} + + bool is_satisfied(cutlass::conv::Conv2dProblemSize item) const override { + return ((input_size.n() == item.N) && (input_size.h() == item.H) && (input_size.w() == item.W) && (input_size.c() == item.C)); + } +}; + +// stride (stride_h, stride_w) specification +struct StrideSpecification : Specification +{ + cutlass::MatrixCoord stride; + + StrideSpecification(cutlass::MatrixCoord stride_) : stride(stride_) {} + + bool is_satisfied(cutlass::conv::Conv2dProblemSize item) const override { + return ((stride.row() == item.stride_h) && (stride.column() == item.stride_h)); + } +}; + +// channel (C,K) specification, must be multiple of minimum channel +struct ChannelDivisibilitySpecification : Specification +{ + int channel_multiple; + + ChannelDivisibilitySpecification(int channel_multiple_) : channel_multiple(channel_multiple_) {} + + bool is_satisfied(cutlass::conv::Conv2dProblemSize item) const override { + return ((item.K % channel_multiple == 0) && (item.C % channel_multiple == 0)); + } +}; + +// +// Pruning function for items from Conv2dProblemVector based on a Specification +// +inline Conv2dProblemVector prune(Conv2dProblemVector const &items, + Specification const &spec) +{ + Conv2dProblemVector pruned_list; + + for (auto& p : items) + if (spec.is_satisfied(p)) + pruned_list.push_back(p); + return pruned_list; +} + + +//////////////////////////////////////////////////////////////////////////// +/// Structure TestbedConv2dProblemSizes initializes and holds conv default and +/// important network sizes +//////////////////////////////////////////////////////////////////////////// +struct TestbedConv2dProblemSizes { + + // + // Data members + // + int minimum_channel_size; + + Conv2dProblemVector conv2d_default_sizes; + Conv2dProblemVector conv2d_rigorous_sizes; + Conv2dProblemVector conv2d_resnet50_sizes; + Conv2dProblemVector conv2d_resnet50_sizes_perf; + + // + // Methods + // + /// Default ctor + TestbedConv2dProblemSizes(int minimum_channel_size_ = 64): minimum_channel_size (minimum_channel_size_) { + initialize_conv2d_default_sizes(); + initialize_conv2d_rigorous_sizes(); + initialize_conv2d_resnet50_sizes(conv2d_resnet50_sizes, 1 /*batch-size*/); + + initialize_conv2d_resnet50_sizes(conv2d_resnet50_sizes_perf, 34 /*batch-size*/); + filter_all(); + } + + /// Eliminates some illegal cases + void filter_all() { + + Conv2dProblemVector *problems_vectors[] = { + &conv2d_default_sizes, + &conv2d_rigorous_sizes, + &conv2d_resnet50_sizes, + &conv2d_resnet50_sizes_perf + }; + + for (Conv2dProblemVector *problems : problems_vectors) { + Conv2dProblemVector filtered; + + for (cutlass::conv::Conv2dProblemSize const & problem : *problems) { + if (!(problem.C % minimum_channel_size)) { + filtered.push_back(problem); + } + } + + *problems = filtered; + } + } + + // Add a few standard convolution problem sizes + void initialize_conv2d_default_sizes() { + + //////////////////////////////////////////////////////////////////////////////////////////// + // Very Small input size (1x8x8xminimum_channel_size), filter size (3x3 - 7x7), stride (1,1) + // C < CTA::K and non-multiples of CTA::K. Typical CTA::K = {32, 64} + //////////////////////////////////////////////////////////////////////////////////////////// + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, minimum_channel_size}, // input size (NHWC) + {8, 3, 3, minimum_channel_size}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, minimum_channel_size}, // input size (NHWC) + {8, 4, 4, minimum_channel_size}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, minimum_channel_size}, // input size (NHWC) + {8, 5, 5, minimum_channel_size}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, minimum_channel_size}, // input size (NHWC) + {8, 6, 5, minimum_channel_size}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, minimum_channel_size}, // input size (NHWC) + {8, 6, 6, minimum_channel_size}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, minimum_channel_size}, // input size (NHWC) + {8, 7, 7, minimum_channel_size}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + //////////////////////////////////////////////////////////////////////////////////// + // Medium input size (1x16x16x128), filter size (1x1, 2x2, 3x3, 5x5), stride (1, 1) + //////////////////////////////////////////////////////////////////////////////////// + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 15, 19, 160}, // input size (NHWC) + {224, 1, 1, 160}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 16, 16, 160}, // input size (NHWC) + {224, 2, 3, 160}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 23, 21, 128}, // input size (NHWC) + {224, 3, 3, 128}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 29, 37, 160}, // input size (NHWC) + {224, 5, 5, 160}, // filter size (KRSC) + {2, 2, 2, 2}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + //////////////////////////////////////////////////////////////////////////////////// + // C > CTA::K and non-multiples of CTA::K. Typical CTA::K = {32, 64} + //////////////////////////////////////////////////////////////////////////////////// + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 15, 19, 32 + minimum_channel_size}, // input size (NHWC) + {96, 3, 3, 32 + minimum_channel_size}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 16, 16, 64 + minimum_channel_size}, // input size (NHWC) + {96, 3, 3, 64 + minimum_channel_size}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + //////////////////////////////////////////////////////////////////////////////////// + // Medium input size (1x16x16x128), filter size (1x1, 3,x3, 5x5), stride (2, 2) + //////////////////////////////////////////////////////////////////////////////////// + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 19, 37, 160}, // input size (NHWC) + {224, 3, 3, 160}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 16, 16, 288}, // input size (NHWC) + {160, 5, 5, 288}, // filter size (KRSC) + {2, 2, 2, 2}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + ///////////////////////////////////////////////////////////////////////////// + // Additional input size + ///////////////////////////////////////////////////////////////////////////// + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {3, 28, 28, 256}, // input size (NHWC) + {256, 2, 2, 256}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {32, 32, 32, 32}, // input size (NHWC) + {32, 1, 1, 32}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {4, 3, 3, 128}, // input size (NHWC) + {256, 3, 3, 128}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1}, // dilation (dilation_h, dilation_w) + {4, 3, 3, 256} // output size (NPQK) + )); + + conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {4, 1, 1, 256}, // input size (NHWC) + {328, 3, 3, 256}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1}, // dilation (dilation_h, dilation_w) + {4, 1, 1, 328} // output size (NPQK) + )); + + } + + + // Add a few large and rigorous convolution problem sizes + void initialize_conv2d_rigorous_sizes() { + +#if CUTLASS_CONV_UNIT_TEST_RIGOROUS_SIZE_ENABLED + conv2d_rigorous_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 124, 224, 96}, // input size (NHWC) + {24, 7, 7, 96}, // filter size (KRSC) + {1, 229, 129, 32} // output size (NPQK) + )); + + conv2d_rigorous_sizes.push_back(cutlass::conv::Conv2dProblemSize( + {1, 233, 35, 48}, // input size (NHWC) + {24, 7, 5, 48}, // filter size (KRSC) + {1, 233, 35, 24} // output size (NPQK) + )); + +#endif + + } + + + // Add resent50 layers to unit testing sizes + void initialize_conv2d_resnet50_sizes(Conv2dProblemVector &conv2d_problem_vector, int batch_size = 1){ + +#if 0 // Resnet50 first layer (layer_id = 0) with channel = 3 is not supported in cutlass + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + [1, 224, 224, 3], // input size (NHWC) + [64, 7, 7, 3], // filter size (KRSC) + [3, 3, 3, 3], // padding (pad_h, _, pad_w, _) + [2, 2], // stride (stride_h, stride_w) + [1, 1], // dilation (dilation_h, dilation_w) + )); +#endif + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 56, 56, 64}, // input size (NHWC) + {256, 1, 1, 64}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 56, 56, 64}, // input size (NHWC) + {64, 1, 1, 64}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 56, 56, 64}, // input size (NHWC) + {64, 3, 3, 64}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 56, 56, 256}, // input size (NHWC) + {64, 1, 1, 256}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 56, 56, 256}, // input size (NHWC) + {512, 1, 1, 256}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 56, 56, 256}, // input size (NHWC) + {128, 1, 1, 256}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 28, 28, 128}, // input size (NHWC) + {128, 3, 3, 128}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 28, 28, 128}, // input size (NHWC) + {512, 1, 1, 128}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 28, 28, 512}, // input size (NHWC) + {128, 1, 1, 512}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 28, 28, 512}, // input size (NHWC) + {1024, 1, 1, 512}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 28, 28, 512}, // input size (NHWC) + {256, 1, 1, 512}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 14, 14, 256}, // input size (NHWC) + {256, 3, 3, 256}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 14, 14, 256}, // input size (NHWC) + {1024, 1, 1, 256}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 14, 14, 1024}, // input size (NHWC) + {256, 1, 1, 1024}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 14, 14, 1024}, // input size (NHWC) + {2048, 1, 1, 1024}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 14, 14, 1024}, // input size (NHWC) + {512, 1, 1, 1024}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {2, 2}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 7, 7, 512}, // input size (NHWC) + {512, 3, 3, 512}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 7, 7, 512}, // input size (NHWC) + {2048, 1, 1, 512}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + conv2d_problem_vector.push_back(cutlass::conv::Conv2dProblemSize( + {batch_size, 7, 7, 2048}, // input size (NHWC) + {512, 1, 1, 2048}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + } + +}; + +} // namespace device +} // namespace conv +} // namespace test diff --git a/test/unit/conv/device/conv2d_testbed.h b/test/unit/conv/device/conv2d_testbed.h new file mode 100644 index 000000000..14bdd9bf1 --- /dev/null +++ b/test/unit/conv/device/conv2d_testbed.h @@ -0,0 +1,558 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Implicit GEMM testbed +*/ +#pragma once + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/device/implicit_gemm_convolution.h" +#include "cutlass/reduction/device/reduce_split_k.h" +#include "cutlass/reduction/thread/reduction_operators.h" + +#include "conv2d_problems.h" + +#include "cutlass/util/host_tensor.h" +#include "cutlass/util/reference/host/tensor_fill.h" +#include "cutlass/util/reference/device/tensor_compare.h" +#include "cutlass/util/reference/host/tensor_compare.h" + +#include "cutlass/util/reference/host/convolution.h" +#include "cutlass/util/reference/device/convolution.h" + +#include "cutlass/core_io.h" +#include "cutlass/util/tensor_view_io.h" + +namespace test { +namespace conv { +namespace device { + +template +class TestbedConv2d { +public: + + using ElementA = typename Conv2d::ElementA; + using LayoutA = typename Conv2d::LayoutA; + using ElementB = typename Conv2d::ElementB; + using LayoutB = typename Conv2d::LayoutB; + using ElementC = typename Conv2d::ElementC; + using LayoutC = typename Conv2d::LayoutC; + using ElementAccumulator = typename Conv2d::ElementAccumulator; + using ElementCompute = typename Conv2d::ElementCompute; + using EpilogueOutputOp = typename Conv2d::EpilogueOutputOp; + + static cutlass::conv::Operator const kConvolutionalOperator = Conv2d::kConvolutionalOperator; + + /// Reduction kernel + using ReductionOp = cutlass::reduction::thread::ReduceAdd< + ElementAccumulator, + typename EpilogueOutputOp::ElementAccumulator, + EpilogueOutputOp::kCount + >; + + using ReductionKernel = cutlass::reduction::kernel::ReduceSplitK< + cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>, + EpilogueOutputOp, + ReductionOp + >; + + using ReductionDevice = cutlass::reduction::device::ReduceSplitK; + + +public: + + /// Initialization + cutlass::Distribution::Kind init_A; + cutlass::Distribution::Kind init_B; + cutlass::Distribution::Kind init_C; + uint64_t seed; + + cutlass::HostTensor tensor_A; + cutlass::HostTensor tensor_B; + cutlass::HostTensor tensor_C; + cutlass::HostTensor tensor_D_computed; + cutlass::HostTensor tensor_D_reference; + +public: + + TestbedConv2d( + cutlass::Distribution::Kind init_A_ = cutlass::Distribution::Uniform, + cutlass::Distribution::Kind init_B_ = cutlass::Distribution::Uniform, + cutlass::Distribution::Kind init_C_ = cutlass::Distribution::Uniform, + uint64_t seed_ = 2080 + ): + init_A(init_A_), init_B(init_B_), init_C(init_C_), seed(seed_) { + + } + + /// Helper to initialize a tensor view + template + void initialize_tensor( + cutlass::TensorView view, + cutlass::Distribution::Kind dist_kind, + uint64_t seed) { + + if (dist_kind == cutlass::Distribution::Uniform) { + + int scope; + int bits = cutlass::sizeof_bits::value; + + if (bits <= 8) { + scope = 2; + } + else if (bits == 16) { + scope = 3; + } + else { + scope = 8; + } + cutlass::reference::host::TensorFillRandomUniform( + view, seed, scope, -scope, 0); + } + else if (dist_kind == cutlass::Distribution::Identity) { + + cutlass::reference::host::TensorFillIdentity(view); + } + else if (dist_kind == cutlass::Distribution::Gaussian) { + + cutlass::reference::host::TensorFillRandomGaussian(view, seed, 0, 0.5); + } + else if (dist_kind == cutlass::Distribution::Sequential) { + + cutlass::reference::host::BlockFillSequential(view.data(), view.capacity()); + } + else { + } + } + + void initialize( + cutlass::conv::Conv2dProblemSize const &problem_size, uint64_t seed = 2019) { + + tensor_A.resize(implicit_gemm_tensor_a_extent(kConvolutionalOperator, problem_size)); + tensor_B.resize(implicit_gemm_tensor_b_extent(kConvolutionalOperator, problem_size)); + tensor_C.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + tensor_D_computed.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + tensor_D_reference.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + + initialize_tensor(tensor_A.host_view(), init_A, seed); + initialize_tensor(tensor_B.host_view(), init_B, seed * 17); + initialize_tensor(tensor_C.host_view(), init_C, seed * 39); + + tensor_A.sync_device(); + tensor_B.sync_device(); + tensor_C.sync_device(); + tensor_D_computed.sync_device(); + tensor_D_reference.sync_device(); + } + + bool sufficient() const { + // + // Determine SMEM requirements and waive if not satisfied + // + + int smem_size = int(sizeof(typename Conv2d::ImplicitGemmKernel::SharedStorage)); + + cudaDeviceProp properties; + int device_idx; + cudaError_t result = cudaGetDevice(&device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDevice() API call failed."); + } + + result = cudaGetDeviceProperties(&properties, device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDeviceProperties() failed"); + } + + if (properties.sharedMemPerMultiprocessor < smem_size) { + return false; + } + + return true; + } + + /// Executes one test + bool run( + cutlass::conv::Conv2dProblemSize const &problem_size, + cutlass::conv::SplitKMode const &split_k_mode = cutlass::conv::SplitKMode::kSerial, + ElementCompute alpha = ElementCompute(1), + ElementCompute beta = ElementCompute(0)) { + + // Waive test if CUDA device is insufficient + if (!sufficient()) { + return true; + } + +#if 0 //display conv2d problem size for debugging + std::cout << problem_size << std::endl + << "alpha, beta: (" << float(alpha) << ", " << float(beta) << ")" << std::endl + << "split_k_mode: " << ((split_k_mode == cutlass::conv::SplitKMode::kSerial) ? "(serial)" : "(parallel)") << std::endl + << std::endl; +#endif + + initialize(problem_size); + + // configure the operator + Conv2d conv2d_op; + + typename Conv2d::Arguments conv2d_args( + problem_size, + tensor_A.device_ref(), + tensor_B.device_ref(), + tensor_C.device_ref(), + tensor_D_computed.device_ref(), + {alpha, beta}, + split_k_mode + ); + + // find workspace requirement for parallel split-k reduction + size_t workspace_size = Conv2d::get_workspace_size(conv2d_args); + + cutlass::device_memory::allocation workspace(workspace_size); + + cutlass::Status status = conv2d_op.initialize(conv2d_args, workspace.get()); + + if (status != cutlass::Status::kSuccess) { + cudaError_t error = cudaGetLastError(); + std::cerr << "This test is not supported: " << cudaGetErrorString(error) << "\n"; + return true; + } + + // conv2d operation with parallel split-k-mode + if (split_k_mode == cutlass::conv::SplitKMode::kParallel) { + + // conv2d output is written to workspace in global memory + conv2d_args.ref_D.reset(reinterpret_cast(workspace.get())); + // accumulate mma for each cta in k-dimension (1.0 * A * B) + conv2d_args.output_op = {ElementCompute(1), ElementCompute(0)}; + // update conv2d operator arguments + status = conv2d_op.update(conv2d_args, workspace.get()); + } + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + // run conv2d operator + status = conv2d_op(); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + if (split_k_mode == cutlass::conv::SplitKMode::kParallel) { + + // configure parallel reduction operator + ReductionDevice reduction_op; + + typename ReductionDevice::Arguments reduction_args( + cutlass::conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn(), + problem_size.split_k_slices, + cutlass::conv::implicit_gemm_tensor_c_size(kConvolutionalOperator, problem_size), + {reinterpret_cast (workspace.get()), tensor_C.stride(Conv2d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {tensor_D_computed.device_data(), tensor_C.stride(Conv2d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {tensor_C.device_data(), tensor_C.stride(Conv2d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {alpha, beta} // apply alpha, beta to obtain the following equation alpha * ReduceAdd(A * B) + beta * C + ); + + status = reduction_op.initialize(reduction_args, nullptr); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + // run prallel reduction kernel + status = reduction_op(); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + } + bool passed = false; + + tensor_D_computed.sync_host(); + +#if CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED + + cutlass::reference::device::Conv2d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator + >( + kConvolutionalOperator, + problem_size, + tensor_A.device_ref(), + tensor_B.device_ref(), + tensor_C.device_ref(), + tensor_D_reference.device_ref(), + alpha, + beta); + + cudaError_t result = cudaDeviceSynchronize(); + EXPECT_EQ(result, cudaSuccess) << " device reference error: " + << cudaGetErrorString(result); + + // sync host (copy device data to host) for dumping error output in case of mismatches + tensor_D_reference.sync_host(); + +#else + + cutlass::reference::host::Conv2d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator + >( + kConvolutionalOperator, + problem_size, + tensor_A.host_ref(), + tensor_B.host_ref(), + tensor_C.host_ref(), + tensor_D_reference.host_ref(), + alpha, + beta); + +#endif + passed = cutlass::reference::host::TensorEquals( + tensor_D_computed.host_view(), + tensor_D_reference.host_view()); + + EXPECT_TRUE(passed); + + if (!passed) { + std::stringstream fname; + + fname << "error_Conv2d_ImplicitGemm_device_" + << (split_k_mode == cutlass::conv::SplitKMode::kSerial ? "serial_reduction_" : "parallel_reduction_") + << (Conv2d::kConvolutionalOperator == cutlass::conv::Operator::kFprop ? "fprop_" : + (Conv2d::kConvolutionalOperator == cutlass::conv::Operator::kDgrad ? "dgrad_" : "wgrad_")) + << "nhwc_" + << problem_size.N << "x" + << problem_size.H << "x" + << problem_size.W << "x" + << problem_size.C + << "_krsc_" + << problem_size.K << "x" + << problem_size.R << "x" + << problem_size.S << "x" + << problem_size.C + << "_padding_" + << problem_size.pad_h << "x" + << problem_size.pad_w + << "_stride_" + << problem_size.stride_h << "x" + << problem_size.stride_w + << "_dilation_" + << problem_size.dilation_h << "x" + << problem_size.dilation_w << "_" + << (problem_size.mode == cutlass::conv::Mode::kCrossCorrelation ? "xcorr_" : "conv_") + << Conv2d::ThreadblockShape::kM << "x" + << Conv2d::ThreadblockShape::kN << "x" + << Conv2d::ThreadblockShape::kK << "_" + << Conv2d::WarpShape::kM << "x" + << Conv2d::WarpShape::kN << "x" + << Conv2d::WarpShape::kK << ".txt"; + + std::cout << fname.str() << std::endl; + + std::ofstream results(fname.str()); + + results << problem_size << std::endl; + + results + << "\nA:\n" << tensor_A.host_view() << "\n" + << "\nB:\n" << tensor_B.host_view() << "\n" + << "\nC:\n" << tensor_C.host_view() << "\n" + << "\nD reference:\n" << tensor_D_reference.host_view() << "\n" + << "\nD computed:\n" << tensor_D_computed.host_view() << "\n"; + + } + + return passed; + } + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// TestAllConv: Runs cutlass::conv::device::ImplicitGemmConvolution operator and compares it with reference +// TestAllConv runs conv operator on default conv problem sizes from test::conv::device::TestbedConv2dProblemSizes +// Additionaly, each conv2d test can provide conv problem sizes (conv_test_sizes) and blacklist of sizes +// (conv_blacklist_sizes) +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +bool TestAllConv2d( + const Conv2dProblemVector & conv_test_sizes = Conv2dProblemVector(), + const Conv2dProblemVector & conv_blacklist_sizes = Conv2dProblemVector()) { + + bool passed = true; + + // + // Testbed object + // + + TestbedConv2d testbed; + + // + // Get conv problem sizes to run conv operator + // + TestbedConv2dProblemSizes conv_problems(128/cutlass::sizeof_bits::value); + + // Vector of conv2d problem sizes to avoid duplicate runs + Conv2dProblemVector conv_tested_sizes; + + Conv2dProblemVector const *problem_vectors[] = { + &conv_test_sizes, // run user specified sizes + &conv_problems.conv2d_default_sizes, // run default and cudnn bug sizes + &conv_problems.conv2d_resnet50_sizes, // run resnet50 sizes +#if CUTLASS_CONV_UNIT_TEST_RIGOROUS_SIZE_ENABLED + &conv_problems.conv2d_rigorous_sizes, // run large and rigorous sizes if enabled +#endif + }; + + // Sweep conv2d problem sizes (split-k-mode=kSerial, split-k-slice=1, alpha=1.0, beta=0.0) + for (Conv2dProblemVector const * problem_vector : problem_vectors) { + + // Run conv testbed on default convolution sizes + for(auto conv_problem : *problem_vector) { + + // Skip blacklist and avoid duplicate problem sizes + if (std::find(conv_blacklist_sizes.begin(), conv_blacklist_sizes.end(), conv_problem) != conv_blacklist_sizes.end() || + std::find(conv_tested_sizes.begin(), conv_tested_sizes.end(), conv_problem) != conv_tested_sizes.end()) { + continue; + } + + // + // Procedurally disable certain cases + // + + // CUTLASS DGRAD's unity stride specialization only support stride {1, 1} + if ((ImplicitGemm::kConvolutionalOperator == + cutlass::conv::Operator::kDgrad) && + (ImplicitGemm::ImplicitGemmKernel::Mma::IteratorA::kStrideSupport == + cutlass::conv::StrideSupport::kUnity)) { + if (!((conv_problem.stride_h == 1) && (conv_problem.stride_w == 1))) { + continue; + } + } + + // + // Test + // + // push back tested problem size to avoid re-running duplicates + conv_tested_sizes.push_back(conv_problem); + + // test mode = xcross + passed = testbed.run( + conv_problem, + cutlass::conv::SplitKMode::kSerial); + + if (!passed) { + return false; + } + + // test mode = convolution + passed = testbed.run( + conv_problem.reset_mode(cutlass::conv::Mode::kConvolution), + cutlass::conv::SplitKMode::kSerial); + + if (!passed) { + return false; + } + } + } + + // Sweep split-k-slice using serial and prallel reduction with non-unity alpha and non-zero beta for + // a single conv2d problem size. Convolution unit tests take a long time to run so only sweep parameters + // which are abolutely neccessary to catch functional bugs. The below code does provide option to sweep + // alpha and beta for local testing, but only runs one value for alpha and beta. + cutlass::conv::Conv2dProblemSize conv2d_split_k_test_size ( + {1, 17, 11, 288}, // input size (NHWC) + {160, 3, 3, 288}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + ); + + cutlass::conv::SplitKMode split_k_modes [] = { + cutlass::conv::SplitKMode::kSerial, + cutlass::conv::SplitKMode::kParallel, + }; + + int split_k_slices[] = { + 1, 2, 3, 4, 201 + }; + + double problem_alpha[] = { + 2.0 + }; + + double problem_beta[] = { + 2.0 + }; + + for (auto split_k_mode : split_k_modes) { + for (auto split_k_slice : split_k_slices) { + for (auto alpha : problem_alpha) { + for (auto beta : problem_beta) { + + passed = testbed.run( + conv2d_split_k_test_size.reset_split_k_slices(split_k_slice), + split_k_mode, + cutlass::from_real(alpha), + cutlass::from_real(beta)); + + if (!passed) { + return false; + } + } + } + } + } + + return passed; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace device +} // namespace conv +} // namespace test diff --git a/test/unit/conv/device/conv2d_testbed_interleaved.h b/test/unit/conv/device/conv2d_testbed_interleaved.h new file mode 100644 index 000000000..cb4ecc705 --- /dev/null +++ b/test/unit/conv/device/conv2d_testbed_interleaved.h @@ -0,0 +1,534 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Implicit GEMM testbed +*/ +#pragma once + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/device/implicit_gemm_convolution.h" +#include "cutlass/reduction/device/reduce_split_k.h" +#include "cutlass/reduction/thread/reduction_operators.h" + +#include "conv2d_problems.h" + +#include "cutlass/util/host_tensor.h" +#include "cutlass/util/reference/host/tensor_fill.h" +#include "cutlass/util/reference/device/tensor_compare.h" +#include "cutlass/util/reference/host/tensor_compare.h" +#include "cutlass/util/host_reorder.h" + +#include "cutlass/util/reference/host/convolution.h" +#include "cutlass/util/reference/device/convolution.h" + +#include "cutlass/core_io.h" +#include "cutlass/util/tensor_view_io.h" + +namespace test { +namespace conv { +namespace device { + +template +class InterleavedTestbedConv2d { +public: + + using ElementA = typename Conv2d::ElementA; + using LayoutA = typename Conv2d::LayoutA; + using ElementB = typename Conv2d::ElementB; + using LayoutB = typename Conv2d::LayoutB; + using ElementC = typename Conv2d::ElementC; + using LayoutC = typename Conv2d::LayoutC; + using ElementAccumulator = typename Conv2d::ElementAccumulator; + using ElementCompute = typename Conv2d::ElementCompute; + using EpilogueOutputOp = typename Conv2d::EpilogueOutputOp; + + static cutlass::conv::Operator const kConvolutionalOperator = Conv2d::kConvolutionalOperator; + + /// Reduction kernel + using ReductionOp = cutlass::reduction::thread::ReduceAdd< + ElementAccumulator, + typename EpilogueOutputOp::ElementAccumulator, + EpilogueOutputOp::kCount + >; + + using ReductionKernel = cutlass::reduction::kernel::ReduceSplitK< + cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>, + EpilogueOutputOp, + ReductionOp + >; + + using ReductionDevice = cutlass::reduction::device::ReduceSplitK; + + +public: + + /// Initialization + cutlass::Distribution::Kind init_A; + cutlass::Distribution::Kind init_B; + cutlass::Distribution::Kind init_C; + uint64_t seed; + + cutlass::HostTensor tensor_A; + cutlass::HostTensor tensor_B; + cutlass::HostTensor tensor_B_reordered; + cutlass::HostTensor tensor_C; + cutlass::HostTensor tensor_D_computed; + cutlass::HostTensor tensor_D_reference; + +public: + + InterleavedTestbedConv2d( + cutlass::Distribution::Kind init_A_ = cutlass::Distribution::Uniform, + cutlass::Distribution::Kind init_B_ = cutlass::Distribution::Uniform, + cutlass::Distribution::Kind init_C_ = cutlass::Distribution::Uniform, + uint64_t seed_ = 2080 + ): + init_A(init_A_), init_B(init_B_), init_C(init_C_), seed(seed_) { + + } + + /// Helper to initialize a tensor view + template + void initialize_tensor( + cutlass::TensorView view, + cutlass::Distribution::Kind dist_kind, + uint64_t seed) { + + if (dist_kind == cutlass::Distribution::Uniform) { + + int scope; + int bits = cutlass::sizeof_bits::value; + + if (bits <= 8) { + scope = 2; + } + else if (bits == 16) { + scope = 3; + } + else { + scope = 8; + } + cutlass::reference::host::TensorFillRandomUniform( + view, seed, scope, -scope, 0); + } + else if (dist_kind == cutlass::Distribution::Identity) { + + cutlass::reference::host::TensorFillIdentity(view); + } + else if (dist_kind == cutlass::Distribution::Gaussian) { + + cutlass::reference::host::TensorFillRandomGaussian(view, seed, 0, 0.5); + } + else if (dist_kind == cutlass::Distribution::Sequential) { + + cutlass::reference::host::BlockFillSequential(view.data(), view.capacity()); + } + else { + } + } + + void initialize( + cutlass::conv::Conv2dProblemSize const &problem_size, uint64_t seed = 2019) { + + tensor_A.resize(implicit_gemm_tensor_a_extent(kConvolutionalOperator, problem_size)); + tensor_B.resize(implicit_gemm_tensor_b_extent(kConvolutionalOperator, problem_size)); + tensor_B_reordered.resize(implicit_gemm_tensor_b_extent(kConvolutionalOperator, problem_size)); + tensor_C.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + tensor_D_computed.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + tensor_D_reference.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + + initialize_tensor(tensor_A.host_view(), init_A, seed); + initialize_tensor(tensor_B.host_view(), init_B, seed * 17); + initialize_tensor(tensor_C.host_view(), init_C, seed * 39); + + cutlass::reorder_convK( + tensor_B_reordered.host_ref(), tensor_B.host_ref(), implicit_gemm_problem_size(kConvolutionalOperator, problem_size)); + + tensor_A.sync_device(); + tensor_B.sync_device(); + tensor_B_reordered.sync_device(); + tensor_C.sync_device(); + tensor_D_computed.sync_device(); + tensor_D_reference.sync_device(); + } + + /// Executes one test + bool run( + cutlass::conv::Conv2dProblemSize const &problem_size, + cutlass::conv::SplitKMode const &split_k_mode = cutlass::conv::SplitKMode::kSerial, + ElementCompute alpha = ElementCompute(1), + ElementCompute beta = ElementCompute(0)) { + +#if 0 //display conv2d problem size for debugging + std::cout << problem_size << std::endl + << "alpha, beta: (" << float(alpha) << ", " << float(beta) << ")" << std::endl + << "split_k_mode: " << ((split_k_mode == cutlass::conv::SplitKMode::kSerial) ? "(serial)" : "(parallel)") << std::endl + << std::endl; +#endif + + initialize(problem_size); + + // configure the operator + Conv2d conv2d_op; + + typename Conv2d::Arguments conv2d_args( + problem_size, + tensor_A.device_ref(), + tensor_B_reordered.device_ref(), + tensor_C.device_ref(), + tensor_D_computed.device_ref(), + {alpha, beta}, + split_k_mode + ); + + // find workspace requirement for parallel split-k reduction + size_t workspace_size = Conv2d::get_workspace_size(conv2d_args); + + cutlass::device_memory::allocation workspace(workspace_size); + + cutlass::Status status = conv2d_op.initialize(conv2d_args, workspace.get()); + + // conv2d operation with parallel split-k-mode + if (split_k_mode == cutlass::conv::SplitKMode::kParallel) { + + // conv2d output is written to workspace in global memory + conv2d_args.ref_D.reset(reinterpret_cast(workspace.get())); + // accumulate mma for each cta in k-dimension (1.0 * A * B) + conv2d_args.output_op = {ElementCompute(1), ElementCompute(0)}; + // update conv2d operator arguments + status = conv2d_op.update(conv2d_args, workspace.get()); + } + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + // run conv2d operator + status = conv2d_op(); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + if (split_k_mode == cutlass::conv::SplitKMode::kParallel) { + + // configure parallel reduction operator + ReductionDevice reduction_op; + + typename ReductionDevice::Arguments reduction_args( + cutlass::conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn(), + problem_size.split_k_slices, + cutlass::conv::implicit_gemm_tensor_c_size(kConvolutionalOperator, problem_size), + {reinterpret_cast (workspace.get()), tensor_C.stride(Conv2d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {tensor_D_computed.device_data(), tensor_C.stride(Conv2d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {tensor_C.device_data(), tensor_C.stride(Conv2d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {alpha, beta} // apply alpha, beta to obtain the following equation alpha * ReduceAdd(A * B) + beta * C + ); + + status = reduction_op.initialize(reduction_args, nullptr); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + // run prallel reduction kernel + status = reduction_op(); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + } + bool passed = false; + + tensor_D_computed.sync_host(); + +#if CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED + + cutlass::reference::device::Conv2d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + cutlass::NumericConverterClamp + >( + kConvolutionalOperator, + problem_size, + tensor_A.device_ref(), + tensor_B.device_ref(), + tensor_C.device_ref(), + tensor_D_reference.device_ref(), + alpha, + beta); + + cudaError_t result = cudaDeviceSynchronize(); + EXPECT_EQ(result, cudaSuccess) << " device reference error: " + << cudaGetErrorString(result); + + // sync host (copy device data to host) for dumping error output in case of mismatches + tensor_D_reference.sync_host(); + +#else + + cutlass::reference::host::Conv2d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + cutlass::NumericConverterClamp + >( + kConvolutionalOperator, + problem_size, + tensor_A.host_ref(), + tensor_B.host_ref(), + tensor_C.host_ref(), + tensor_D_reference.host_ref(), + alpha, + beta); + +#endif + passed = cutlass::reference::host::TensorEquals( + tensor_D_computed.host_view(), + tensor_D_reference.host_view()); + + EXPECT_TRUE(passed); + + if (!passed) { + std::stringstream fname; + + fname << "error_Conv2d_ImplicitGemm_device_" + << (split_k_mode == cutlass::conv::SplitKMode::kSerial ? "serial_reduction_" : "parallel_reduction_") + << (Conv2d::kConvolutionalOperator == cutlass::conv::Operator::kFprop ? "fprop_" : + (Conv2d::kConvolutionalOperator == cutlass::conv::Operator::kDgrad ? "dgrad_" : "wgrad_")) + << "nhwc_" + << problem_size.N << "x" + << problem_size.H << "x" + << problem_size.W << "x" + << problem_size.C + << "_krsc_" + << problem_size.K << "x" + << problem_size.R << "x" + << problem_size.S << "x" + << problem_size.C + << "_padding_" + << problem_size.pad_h << "x" + << problem_size.pad_w + << "_stride_" + << problem_size.stride_h << "x" + << problem_size.stride_w + << "_dilation_" + << problem_size.dilation_h << "x" + << problem_size.dilation_w << "_" + << (problem_size.mode == cutlass::conv::Mode::kCrossCorrelation ? "xcorr_" : "conv_") + << Conv2d::ThreadblockShape::kM << "x" + << Conv2d::ThreadblockShape::kN << "x" + << Conv2d::ThreadblockShape::kK << "_" + << Conv2d::WarpShape::kM << "x" + << Conv2d::WarpShape::kN << "x" + << Conv2d::WarpShape::kK << ".txt"; + + std::cout << fname.str() << std::endl; + + std::ofstream results(fname.str()); + + results << problem_size << std::endl; + + results + << "\nA:\n" << tensor_A.host_view() << "\n" + << "\nB:\n" << tensor_B.host_view() << "\n" + << "\nB_reordered =\n" << tensor_B_reordered.host_view() << "\n" + << "\nC:\n" << tensor_C.host_view() << "\n" + << "\nD reference:\n" << tensor_D_reference.host_view() << "\n" + << "\nD computed:\n" << tensor_D_computed.host_view() << "\n"; + + } + + return passed; + } + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// TestAllConv: Runs cutlass::conv::device::ImplicitGemmConvolution operator and compares it with reference +// TestAllConv runs conv operator on default conv problem sizes from test::conv::device::TestbedConv2dProblemSizes +// Additionaly, each conv2d test can provide conv problem sizes (conv_test_sizes) and blacklist of sizes +// (conv_blacklist_sizes) +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +bool TestAllInterleavedConv2d( + const Conv2dProblemVector & conv_test_sizes = Conv2dProblemVector(), + const Conv2dProblemVector & conv_blacklist_sizes = Conv2dProblemVector()) { + + bool passed = true; + + // + // Testbed object + // + + InterleavedTestbedConv2d testbed; + + // + // Get conv problem sizes to run conv operator + // + TestbedConv2dProblemSizes conv_problems(InterleavedK); // minimum channel size must be multiple of InterleavedK for interleaved layout + + // Vector of conv2d problem sizes to avoid duplicate runs + Conv2dProblemVector conv_tested_sizes; + + Conv2dProblemVector const *problem_vectors[] = { + &conv_test_sizes, // run user specified sizes + &conv_problems.conv2d_default_sizes, // run default and cudnn bug sizes + &conv_problems.conv2d_resnet50_sizes, // run resnet50 sizes +#if CUTLASS_CONV_UNIT_TEST_RIGOROUS_SIZE_ENABLED + &conv_problems.conv2d_rigorous_sizes, // run large and rigorous sizes if enabled +#endif + }; + + // Sweep conv2d problem sizes (split-k-mode=kSerial, split-k-slice=1, alpha=1.0, beta=0.0) + for (Conv2dProblemVector const * problem_vector : problem_vectors) { + + ChannelDivisibilitySpecification channel_spec(InterleavedK); //input and output channels must be multiple of InterleavedK + auto pruned_problem_vector = prune(*problem_vector, channel_spec); + + // Run conv testbed on default convolution sizes + for(auto conv_problem : pruned_problem_vector) { + + // Skip blacklist and avoid duplicate problem sizes + if (std::find(conv_blacklist_sizes.begin(), conv_blacklist_sizes.end(), conv_problem) != conv_blacklist_sizes.end() || + std::find(conv_tested_sizes.begin(), conv_tested_sizes.end(), conv_problem) != conv_tested_sizes.end()) { + continue; + } + + // + // Procedurally disable certain cases + // + + // CUTLASS DGRAD's unity stride specialization only support stride {1, 1} + if ((ImplicitGemm::kConvolutionalOperator == + cutlass::conv::Operator::kDgrad) && + (ImplicitGemm::ImplicitGemmKernel::Mma::IteratorA::kStrideSupport == + cutlass::conv::StrideSupport::kUnity)) { + if (!((conv_problem.stride_h == 1) && (conv_problem.stride_w == 1))) { + continue; + } + } + + // + // Test + // + // push back tested problem size to avoid re-running duplicates + conv_tested_sizes.push_back(conv_problem); + + // test mode = xcross + passed = testbed.run( + conv_problem, + cutlass::conv::SplitKMode::kSerial); + + if (!passed) { + return false; + } + + // test mode = convolution + passed = testbed.run( + conv_problem.reset_mode(cutlass::conv::Mode::kConvolution), + cutlass::conv::SplitKMode::kSerial); + + if (!passed) { + return false; + } + } + } + +#if 0 + // Sweep split-k-slice using serial and prallel reduction with non-unity alpha and non-zero beta for + // a single conv2d problem size. Convolution unit tests take a long time to run so only sweep parameters + // which are abolutely neccessary to catch functional bugs. The below code does provide option to sweep + // alpha and beta for local testing, but only runs one value for alpha and beta. + cutlass::conv::Conv2dProblemSize conv2d_split_k_test_size ( + {1, 17, 11, 288}, // input size (NHWC) + {160, 3, 3, 288}, // filter size (KRSC) + {1, 1, 1, 1}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + ); + + cutlass::conv::SplitKMode split_k_modes [] = { + cutlass::conv::SplitKMode::kSerial, + cutlass::conv::SplitKMode::kParallel, + }; + + int split_k_slices[] = { + 1, 2, 3, 4, 201 + }; + + double problem_alpha[] = { + 2.0 + }; + + double problem_beta[] = { + 2.0 + }; + + for (auto split_k_mode : split_k_modes) { + for (auto split_k_slice : split_k_slices) { + for (auto alpha : problem_alpha) { + for (auto beta : problem_beta) { + + passed = testbed.run( + conv2d_split_k_test_size.reset_split_k_slices(split_k_slice), + split_k_mode, + cutlass::from_real(alpha), + cutlass::from_real(beta)); + + if (!passed) { + return false; + } + } + } + } + } +#endif + + return passed; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace device +} // namespace conv +} // namespace test diff --git a/test/unit/conv/device/conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu new file mode 100644 index 000000000..07961dd2b --- /dev/null +++ b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm50.cu @@ -0,0 +1,172 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM50_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x2_32x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM50_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 64x64_8x2_32x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM50_Device_Conv2d_Wgrad_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x2_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm50, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} diff --git a/test/unit/conv/device/conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu new file mode 100644 index 000000000..a68a30fe5 --- /dev/null +++ b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32_sm80.cu @@ -0,0 +1,311 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 64x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Optimized_ImplicitGemm_cf32nhwc_cf32nhwc_cf32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::complex; + using ElementB = cutlass::complex; + using ElementC = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementCompute = cutlass::complex; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAddComplex, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu new file mode 100644 index 000000000..3cbde0288 --- /dev/null +++ b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu @@ -0,0 +1,122 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementAccumulator = cutlass::half_t; + using ElementCompute = cutlass::half_t; + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + + +TEST(SM80_Device_Conv2d_Wgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16, + 128x128_64x3_64x64x64) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = cutlass::half_t; + using ElementAccumulator = cutlass::half_t; + using ElementCompute = cutlass::half_t; + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 64>, + cutlass::gemm::GemmShape<64, 64, 64>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu new file mode 100644 index 000000000..ffb79d77a --- /dev/null +++ b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu @@ -0,0 +1,78 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM70_SUPPORTED) + +TEST(SM70_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm70, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<8, 8, 4>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM70_SUPPORTED + diff --git a/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu new file mode 100644 index 000000000..1101090a1 --- /dev/null +++ b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm75.cu @@ -0,0 +1,78 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM75_SUPPORTED) + +TEST(SM75_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED + diff --git a/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..ade6f8df3 --- /dev/null +++ b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,161 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Wgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv2d_Wgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32, + 64x256_32x4_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 256, 32>, + cutlass::gemm::GemmShape<64, 64, 32 >, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized, + cutlass::conv::StrideSupport::kStrided + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED + diff --git a/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu new file mode 100644 index 000000000..a0aac8114 --- /dev/null +++ b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.cu @@ -0,0 +1,321 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 64x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + test::conv::device::Conv2dProblemVector user_size; + + user_size.push_back(cutlass::conv::Conv2dProblemSize( + {1, 8, 8, 4}, // input size (NHWC) + {8, 1, 1, 4}, // filter size (KRSC) + {0, 0, 0, 0}, // padding (pad_h, _, pad_w, _) + {1, 1}, // stride (stride_h, stride_w) + {1, 1} // dilation (dilation_h, dilation_w) + )); + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d(user_size)); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kAnalytic + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Optimized_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 32x64_8x4_32x64x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<32, 64, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Optimized_ImplicitGemm_f32nhwc_f32nhwc_f32nhwc_simt_f32, + 128x128_8x4_64x32x8) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = float; + using ElementB = float; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, + cutlass::layout::TensorNHWC, + ElementB, + cutlass::layout::TensorNHWC, + ElementC, + cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassSimt, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 8>, + cutlass::gemm::GemmShape<64, 32, 8>, + cutlass::gemm::GemmShape<1, 1, 1>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 1, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); + +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv2d_wgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..2185257f1 --- /dev/null +++ b/test/unit/conv/device/conv2d_wgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,81 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv2d_testbed.h" + + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv2d_Wgrad_Analytic_ImplicitGemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::tfloat32_t; + using ElementB = cutlass::tfloat32_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv2dWgradKernel = typename cutlass::conv::kernel::DefaultConv2dWgrad< + ElementA, cutlass::layout::TensorNHWC, + ElementB, cutlass::layout::TensorNHWC, + ElementC, cutlass::layout::TensorNHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv2dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv2d instance + EXPECT_TRUE(test::conv::device::TestAllConv2d()); +} + + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv3d_dgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv3d_dgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..211a331d8 --- /dev/null +++ b/test/unit/conv/device/conv3d_dgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,80 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv3d_dgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv3d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv3d_Dgrad_Analytic_ImplicitGemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::tfloat32_t; + using ElementB = cutlass::tfloat32_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv3dDgradKernel = typename cutlass::conv::kernel::DefaultConv3dDgrad< + ElementA, cutlass::layout::TensorNDHWC, + ElementB, cutlass::layout::TensorNDHWC, + ElementC, cutlass::layout::TensorNDHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv3dDgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv3d instance + EXPECT_TRUE(test::conv::device::TestAllConv3d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv3d_fprop_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv3d_fprop_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..0aabef5ba --- /dev/null +++ b/test/unit/conv/device/conv3d_fprop_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,80 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv3d_fprop.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv3d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv3d_Fprop_Analytic_ImplicitGemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::tfloat32_t; + using ElementB = cutlass::tfloat32_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv3dFpropKernel = typename cutlass::conv::kernel::DefaultConv3dFprop< + ElementA, cutlass::layout::TensorNDHWC, + ElementB, cutlass::layout::TensorNDHWC, + ElementC, cutlass::layout::TensorNDHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv3dFprop = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv3d instance + EXPECT_TRUE(test::conv::device::TestAllConv3d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/conv/device/conv3d_problems.h b/test/unit/conv/device/conv3d_problems.h new file mode 100644 index 000000000..9cc618467 --- /dev/null +++ b/test/unit/conv/device/conv3d_problems.h @@ -0,0 +1,248 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Implicit GEMM testbed sizes for Conv2d problem +*/ +#pragma once + +#include "../../common/cutlass_unit_test.h" + +#include "cutlass/cutlass.h" + +#include "cutlass/aligned_buffer.h" +#include "cutlass/numeric_types.h" +#include "cutlass/layout/matrix.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/layout/pitch_linear.h" +#include "cutlass/core_io.h" +#include "cutlass/util/host_tensor.h" +#include "cutlass/util/tensor_view_io.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/conv3d_problem_size.h" + +namespace test { +namespace conv { +namespace device { + +using Conv3dProblemVector = std::vector; + +//////////////////////////////////////////////////////////////////////////// +/// Structure TestbedConv3dProblemSizes initializes and holds conv default and +/// important network sizes +//////////////////////////////////////////////////////////////////////////// +struct TestbedConv3dProblemSizes { + + // + // Data members + // + int minimum_channel_size; + Conv3dProblemVector conv3d_default_sizes; + Conv3dProblemVector conv3d_vnet_medical_sizes; + + // + // Methods + // + /// Default ctor + TestbedConv3dProblemSizes(int minimum_channel_size_ = 64): minimum_channel_size (minimum_channel_size_) { + + initialize_conv3d_default_sizes(); + initialize_conv3d_vnet_medical_sizes(conv3d_vnet_medical_sizes, 1 /*batch-size*/); + + filter_all(); + } + + /// Eliminates some illegal cases + void filter_all() { + + Conv3dProblemVector *problems_vectors[] = { + &conv3d_default_sizes, + &conv3d_vnet_medical_sizes + }; + + for (Conv3dProblemVector *problems : problems_vectors) { + Conv3dProblemVector filtered; + + for (cutlass::conv::Conv3dProblemSize const & problem : *problems) { + if (!(problem.C % minimum_channel_size)) { + filtered.push_back(problem); + } + } + + *problems = filtered; + } + } + + // Add a few standard convolution problem sizes + void initialize_conv3d_default_sizes() { + + conv3d_default_sizes.push_back(cutlass::conv::Conv3dProblemSize( + {1, 1, 3, 3, minimum_channel_size}, // input size (NDHWC) + {8, 1, 1, 1, minimum_channel_size}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + conv3d_default_sizes.push_back(cutlass::conv::Conv3dProblemSize( + {1, 1, 16, 16, minimum_channel_size}, // input size (NDHWC) + {8, 1, 3, 3, minimum_channel_size}, // filter size (KTRSC) + cutlass::Coord<3>({0, 1, 1}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + conv3d_default_sizes.push_back(cutlass::conv::Conv3dProblemSize( + {1, 1, 15, 19, 160}, // input size (NDHWC) + {224, 1, 3, 6, 160}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + conv3d_default_sizes.push_back(cutlass::conv::Conv3dProblemSize( + {1, 2, 1, 1, minimum_channel_size}, // input size (NDHWC) + {8, 2, 1, 1, minimum_channel_size}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + conv3d_default_sizes.push_back(cutlass::conv::Conv3dProblemSize( + {1, 1, 7, 7, minimum_channel_size}, // input size (NDHWC) + {16, 1, 3, 3, minimum_channel_size}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + conv3d_default_sizes.push_back(cutlass::conv::Conv3dProblemSize( + {1, 11, 15, 19, 64}, // input size (NDHWC) + {32, 4, 3, 6, 64}, // filter size (KTRSC) + cutlass::Coord<3>({2, 1, 3}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + } + + // Add vnet layers to unit testing sizes + void initialize_conv3d_vnet_medical_sizes(Conv3dProblemVector &conv3d_problem_vector, int batch_size = 1) { + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 32, 32, 32, 16}, // input size (NDHWC) + {32, 2, 2, 2, 16}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({2, 2, 2}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 16, 16, 16, 32}, // input size (NDHWC) + {32, 3, 3, 3, 32}, // filter size (KTRSC) + cutlass::Coord<3>({1, 1, 1}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 16, 16, 16, 32}, // input size (NDHWC) + {64, 2, 2, 2, 32}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({2, 2, 2}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 8, 8, 8, 64}, // input size (NDHWC) + {64, 3, 3, 3, 64}, // filter size (KTRSC) + cutlass::Coord<3>({1, 1, 1}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 8, 8, 8, 64}, // input size (NDHWC) + {128, 2, 2, 2, 64}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({2, 2, 2}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 4, 4, 4, 128}, // input size (NDHWC) + {128, 3, 3, 3, 128}, // filter size (KTRSC) + cutlass::Coord<3>({1, 1, 1}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 8, 8, 8, 128}, // input size (NDHWC) + {128, 3, 3, 3, 128}, // filter size (KTRSC) + cutlass::Coord<3>({1, 1, 1}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 16, 16, 16, 64}, // input size (NDHWC) + {64, 3, 3, 3, 64}, // filter size (KTRSC) + cutlass::Coord<3>({1, 1, 1}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 32, 32, 32, 16}, // input size (NDHWC) + {64, 2, 2, 2, 16}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({2, 2, 2}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + + conv3d_problem_vector.push_back(cutlass::conv::Conv3dProblemSize( + {batch_size, 16, 16, 16, 32}, // input size (NDHWC) + {128, 2, 2, 2, 32}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({2, 2, 2}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + )); + + } + +}; + +} // namespace device +} // namespace conv +} // namespace test diff --git a/test/unit/conv/device/conv3d_testbed.h b/test/unit/conv/device/conv3d_testbed.h new file mode 100644 index 000000000..179520d15 --- /dev/null +++ b/test/unit/conv/device/conv3d_testbed.h @@ -0,0 +1,537 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Implicit GEMM testbed +*/ +#pragma once + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + + +#include "cutlass/conv/device/implicit_gemm_convolution.h" +#include "cutlass/reduction/device/reduce_split_k.h" +#include "cutlass/reduction/thread/reduction_operators.h" + +#include "cutlass/util/reference/host/tensor_fill.h" + +#include "cutlass/util/reference/host/convolution.h" + +#include "cutlass/util/reference/host/tensor_compare.h" + +#include "cutlass/util/reference/device/convolution.h" +#include "cutlass/util/reference/device/tensor_compare.h" + +#include "conv3d_problems.h" +#include "cutlass/core_io.h" + +namespace test { +namespace conv { +namespace device { + +template +class TestbedConv3d { +public: + + using ElementA = typename Conv3d::ElementA; + using LayoutA = typename Conv3d::LayoutA; + using ElementB = typename Conv3d::ElementB; + using LayoutB = typename Conv3d::LayoutB; + using ElementC = typename Conv3d::ElementC; + using LayoutC = typename Conv3d::LayoutC; + using ElementAccumulator = typename Conv3d::ElementAccumulator; + using ElementCompute = typename Conv3d::ElementCompute; + using EpilogueOutputOp = typename Conv3d::EpilogueOutputOp; + + static cutlass::conv::Operator const kConvolutionalOperator = Conv3d::kConvolutionalOperator; + + /// Reduction kernel + using ReductionOp = cutlass::reduction::thread::ReduceAdd< + ElementAccumulator, + typename EpilogueOutputOp::ElementAccumulator, + EpilogueOutputOp::kCount + >; + + using ReductionKernel = cutlass::reduction::kernel::ReduceSplitK< + cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>, + EpilogueOutputOp, + ReductionOp + >; + + using ReductionDevice = cutlass::reduction::device::ReduceSplitK; + +public: + + /// Initialization + cutlass::Distribution::Kind init_A; + cutlass::Distribution::Kind init_B; + cutlass::Distribution::Kind init_C; + uint64_t seed; + + cutlass::HostTensor tensor_A; + cutlass::HostTensor tensor_B; + cutlass::HostTensor tensor_C; + cutlass::HostTensor tensor_D_computed; + cutlass::HostTensor tensor_D_reference; + +public: + + TestbedConv3d( + cutlass::Distribution::Kind init_A_ = cutlass::Distribution::Uniform, + cutlass::Distribution::Kind init_B_ = cutlass::Distribution::Uniform, + cutlass::Distribution::Kind init_C_ = cutlass::Distribution::Uniform, + uint64_t seed_ = 2080 + ): + init_A(init_A_), init_B(init_B_), init_C(init_C_), seed(seed_) { + + } + + /// Helper to initialize a tensor view + template + void initialize_tensor( + cutlass::TensorView view, + cutlass::Distribution::Kind dist_kind, + uint64_t seed) { + + if (dist_kind == cutlass::Distribution::Uniform) { + + int scope; + int bits = cutlass::sizeof_bits::value; + + if (bits <= 8) { + scope = 2; + } + else if (bits == 16) { + scope = 4; + } + else { + scope = 8; + } + cutlass::reference::host::TensorFillRandomUniform( + view, seed, scope, -scope, 0); + } + else if (dist_kind == cutlass::Distribution::Identity) { + + cutlass::reference::host::TensorFillIdentity(view); + } + else if (dist_kind == cutlass::Distribution::Gaussian) { + + cutlass::reference::host::TensorFillRandomGaussian(view, seed, 0, 0.5); + } + else if (dist_kind == cutlass::Distribution::Sequential) { + + cutlass::reference::host::BlockFillSequential(view.data(), view.capacity()); + } + else { + } + } + + void initialize( + cutlass::conv::Conv3dProblemSize const &problem_size, uint64_t seed = 2019) { + + tensor_A.resize(implicit_gemm_tensor_a_extent(kConvolutionalOperator, problem_size)); + tensor_B.resize(implicit_gemm_tensor_b_extent(kConvolutionalOperator, problem_size)); + tensor_C.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + tensor_D_computed.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + tensor_D_reference.resize(implicit_gemm_tensor_c_extent(kConvolutionalOperator, problem_size)); + + initialize_tensor(tensor_A.host_view(), init_A, seed); + initialize_tensor(tensor_B.host_view(), init_B, seed * 17); + initialize_tensor(tensor_C.host_view(), init_C, seed * 39); + + tensor_A.sync_device(); + tensor_B.sync_device(); + tensor_C.sync_device(); + tensor_D_computed.sync_device(); + tensor_D_reference.sync_device(); + } + + bool sufficient() const { + // + // Determine SMEM requirements and waive if not satisfied + // + + int smem_size = int(sizeof(typename Conv3d::ImplicitGemmKernel::SharedStorage)); + + cudaDeviceProp properties; + int device_idx; + cudaError_t result = cudaGetDevice(&device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDevice() API call failed."); + } + + result = cudaGetDeviceProperties(&properties, device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDeviceProperties() failed"); + } + + if (properties.sharedMemPerMultiprocessor < smem_size) { + return false; + } + + return true; + } + + + /// Executes one test + bool run( + cutlass::conv::Conv3dProblemSize const &problem_size, + cutlass::conv::SplitKMode const &split_k_mode = cutlass::conv::SplitKMode::kSerial, + ElementCompute alpha = ElementCompute(1), + ElementCompute beta = ElementCompute()) { + + // Waive test if CUDA device is insufficient. + if (!sufficient()) { + return true; + } + +#if 0 //display conv2d problem size for debugging + std::cout << problem_size << std::endl + << "alpha, beta: (" << float(alpha) << ", " << float(beta) << ")" << std::endl + << "split_k_mode: " << ((split_k_mode == cutlass::conv::SplitKMode::kSerial) ? "(serial)" : "(parallel)") << std::endl + << std::endl; +#endif + + initialize(problem_size); + + // configure the operator + Conv3d conv3d_op; + + typename Conv3d::Arguments conv3d_args( + problem_size, + tensor_A.device_ref(), + tensor_B.device_ref(), + tensor_C.device_ref(), + tensor_D_computed.device_ref(), + {alpha, beta}, + split_k_mode + ); + + // find workspace requirement for parallel split-k reduction + size_t workspace_size = Conv3d::get_workspace_size(conv3d_args); + + cutlass::device_memory::allocation workspace(workspace_size); + + cutlass::Status status = conv3d_op.initialize(conv3d_args, workspace.get()); + + if (status != cutlass::Status::kSuccess) { + cudaError_t error = cudaGetLastError(); + std::cerr << "This test is not supported: " << cudaGetErrorString(error) << "\n"; + return true; + } + + // conv3d operation with parallel split-k-mode + if (split_k_mode == cutlass::conv::SplitKMode::kParallel) { + + // conv3d output is written to workspace in global memory + conv3d_args.ref_D.reset(reinterpret_cast(workspace.get())); + // accumulate mma for each cta in k-dimension (1.0 * A * B) + conv3d_args.output_op = {1.0, 0.0}; + // update conv3d operator arguments + status = conv3d_op.update(conv3d_args, workspace.get()); + } + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + // run conv3d operator + status = conv3d_op(); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + if (split_k_mode == cutlass::conv::SplitKMode::kParallel) { + + // configure parallel reduction operator + ReductionDevice reduction_op; + + typename ReductionDevice::Arguments reduction_args( + cutlass::conv::implicit_gemm_problem_size(kConvolutionalOperator, problem_size).mn(), + problem_size.split_k_slices, + cutlass::conv::implicit_gemm_tensor_c_size(kConvolutionalOperator, problem_size), + {reinterpret_cast (workspace.get()), tensor_C.stride(Conv3d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {tensor_D_computed.device_data(), tensor_C.stride(Conv3d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {tensor_C.device_data(), tensor_C.stride(Conv3d::ImplicitGemmKernel::kTensorCStrideIdx)}, + {alpha, beta} // apply alpha, beta to obtain the following equation alpha * ReduceAdd(A * B) + beta * C + ); + + status = reduction_op.initialize(reduction_args, nullptr); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + + // run prallel reduction kernel + status = reduction_op(); + + EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + return false; + } + } + bool passed = false; + + cutlass::reference::host::Conv3d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementAccumulator, + ElementCompute + >( + kConvolutionalOperator, + problem_size, + tensor_A.host_ref(), + tensor_B.host_ref(), + tensor_C.host_ref(), + tensor_D_reference.host_ref(), + alpha, + beta + ); + + tensor_D_computed.sync_host(); + + passed = cutlass::reference::host::TensorEquals( + tensor_D_computed.host_view(), + tensor_D_reference.host_view()); + + EXPECT_TRUE(passed); + + if (!passed) { + std::stringstream fname; + + fname << "error_Conv3d_ImplicitGemm_device_" + << (split_k_mode == cutlass::conv::SplitKMode::kSerial ? "serial_reduction_" : "parallel_reduction_") + << (Conv3d::kConvolutionalOperator == cutlass::conv::Operator::kFprop ? "fprop_" : + (Conv3d::kConvolutionalOperator == cutlass::conv::Operator::kDgrad ? "dgrad_" : "wgrad_")) + << "ndhwc_" + << problem_size.N << "x" + << problem_size.D << "x" + << problem_size.H << "x" + << problem_size.W << "x" + << problem_size.C + << "_ktrsc_" + << problem_size.K << "x" + << problem_size.T << "x" + << problem_size.R << "x" + << problem_size.S << "x" + << problem_size.C + << "_padding_" + << problem_size.pad_d << "x" + << problem_size.pad_h << "x" + << problem_size.pad_w + << "_stride_" + << problem_size.stride_d << "x" + << problem_size.stride_h << "x" + << problem_size.stride_w + << "_dilation_" + << problem_size.dilation_d << "x" + << problem_size.dilation_h << "x" + << problem_size.dilation_w << "_" + << (problem_size.mode == cutlass::conv::Mode::kCrossCorrelation ? "xcorr_" : "conv_") + << Conv3d::ThreadblockShape::kM << "x" + << Conv3d::ThreadblockShape::kN << "x" + << Conv3d::ThreadblockShape::kK << "_" + << Conv3d::WarpShape::kM << "x" + << Conv3d::WarpShape::kN << "x" + << Conv3d::WarpShape::kK << ".txt"; + + std::cout << fname.str() << std::endl; + + std::ofstream results(fname.str()); + + results << problem_size << std::endl; + + results + << "\nA:\n" << tensor_A.host_view() << "\n" + << "\nB:\n" << tensor_B.host_view() << "\n" + << "\nC:\n" << tensor_C.host_view() << "\n" + << "\nD reference:\n" << tensor_D_reference.host_view() << "\n" + << "\nD computed:\n" << tensor_D_computed.host_view() << "\n"; + + } + + return passed; + } + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// TestAllConv: Runs cutlass::conv::device::ImplicitGemmConvolution operator and compares it with reference +// TestAllConv runs conv operator on default conv problem sizes from test::conv::device::TestbedConv2dProblemSizes +// Additionaly, each conv3d test can provide conv problem sizes (conv_test_sizes) and blacklist of sizes +// (conv_blacklist_sizes) +///////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool TestAllConv3d( + const Conv3dProblemVector & conv_test_sizes = Conv3dProblemVector(), + const Conv3dProblemVector & conv_blacklist_sizes = Conv3dProblemVector()) { + + bool passed = true; + + // + // Testbed object + // + + //TestbedConv3d testbed(cutlass::Distribution::Sequential, cutlass::Distribution::Sequential, cutlass::Distribution::Sequential); + TestbedConv3d testbed; + + // + // Get conv problem sizes to run conv operator + // + TestbedConv3dProblemSizes conv3d_problems(128/cutlass::sizeof_bits::value); + + // + // Get conv problem sizes to run conv operator + // + //TestbedConv3dProblemSizes conv_problems(128/cutlass::sizeof_bits::value); + + // Vector of conv3d problem sizes to avoid duplicate runs + Conv3dProblemVector conv_tested_sizes; + + Conv3dProblemVector const *problem_vectors[] = { + &conv3d_problems.conv3d_default_sizes, + &conv3d_problems.conv3d_vnet_medical_sizes, + &conv_test_sizes + }; + + // Sweep conv3d problem sizes (split-k-mode=kSerial, split-k-slice=1, alpha=1.0, beta=0.0) + for (Conv3dProblemVector const * problem_vector : problem_vectors) { + + // Run conv testbed on default convolution sizes + for(auto conv_problem : *problem_vector) { + + // Skip blacklist and avoid duplicate problem sizes + if (std::find(conv_blacklist_sizes.begin(), conv_blacklist_sizes.end(), conv_problem) != conv_blacklist_sizes.end() || + std::find(conv_tested_sizes.begin(), conv_tested_sizes.end(), conv_problem) != conv_tested_sizes.end()) { + continue; + } + + // + // Procedurally disable certain cases + // + + // CUTLASS DGRAD's unity stride specialization only support stride {1, 1} + if ((ImplicitGemm::kConvolutionalOperator == + cutlass::conv::Operator::kDgrad) && + (ImplicitGemm::ImplicitGemmKernel::Mma::IteratorA::kStrideSupport == + cutlass::conv::StrideSupport::kUnity)) { + if (!((conv_problem.stride_h == 1) && (conv_problem.stride_w == 1))) { + continue; + } + } + + // + // Test + // + // push back tested problem size to avoid re-running duplicates + conv_tested_sizes.push_back(conv_problem); + + // test mode = xcross + passed = testbed.run( + conv_problem, + cutlass::conv::SplitKMode::kSerial); + + if (!passed) { + return false; + } + + // test mode = convolution + passed = testbed.run( + conv_problem.reset_mode(cutlass::conv::Mode::kConvolution), + cutlass::conv::SplitKMode::kSerial); + + if (!passed) { + return false; + } + } + } + + // Sweep split-k-slice using serial reduction with non-unity alpha and non-zero beta for + // a single conv2d problem size. Convolution unit tests take a long time to run so only sweep parameters + // which are abolutely neccessary to catch functional bugs. The below code does provide option to sweep + // alpha and beta for local testing, but only runs one value for alpha and beta. + cutlass::conv::Conv3dProblemSize conv3d_split_k_test_size ( + {1, 8, 8, 8, 32}, // input size (NDHWC) + {32, 3, 3, 3, 32}, // filter size (KTRSC) + cutlass::Coord<3>({0, 0, 0}), // padding (pad_d, pad_h, pad_w) + cutlass::Coord<3>({1, 1, 1}), // stride (stride_d, stride_h, stride_w) + cutlass::Coord<3>({1, 1, 1}) // dilation (dilation_d, dilation_h, dilation_w) + ); + + cutlass::conv::SplitKMode split_k_modes [] = { + cutlass::conv::SplitKMode::kSerial, + cutlass::conv::SplitKMode::kParallel + }; + + int split_k_slices[] = { + 1, 2, 3, 4, 201 + }; + + double problem_alpha[] = { + 2.0 + }; + + double problem_beta[] = { + 2.0 + }; + + for (auto split_k_mode : split_k_modes) { + for (auto split_k_slice : split_k_slices) { + for (auto alpha : problem_alpha) { + for (auto beta : problem_beta) { + + passed = testbed.run( + conv3d_split_k_test_size.reset_split_k_slices(split_k_slice), + split_k_mode, + cutlass::from_real(alpha), + cutlass::from_real(beta)); + + if (!passed) { + return false; + } + } + } + } + } + + return passed; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace device +} // namespace conv +} // namespace test diff --git a/test/unit/conv/device/conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm75.cu b/test/unit/conv/device/conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm75.cu new file mode 100644 index 000000000..a3f840944 --- /dev/null +++ b/test/unit/conv/device/conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm75.cu @@ -0,0 +1,78 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv3d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv3d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM75_SUPPORTED) + +TEST(SM75_Device_Conv3d_Wgrad_Analytic_ImplicitGemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32, + 128x128_32x2_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv3dWgradKernel = typename cutlass::conv::kernel::DefaultConv3dWgrad< + ElementA, cutlass::layout::TensorNDHWC, + ElementB, cutlass::layout::TensorNDHWC, + ElementC, cutlass::layout::TensorNDHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm75, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 2, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv3dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv3d instance + EXPECT_TRUE(test::conv::device::TestAllConv3d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED + diff --git a/test/unit/conv/device/conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..9847aede8 --- /dev/null +++ b/test/unit/conv/device/conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,159 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv3d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv3d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +TEST(SM80_Device_Conv3d_Wgrad_Analytic_ImplicitGemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32, + 128x128_32x4_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv3dWgradKernel = typename cutlass::conv::kernel::DefaultConv3dWgrad< + ElementA, cutlass::layout::TensorNDHWC, + ElementB, cutlass::layout::TensorNDHWC, + ElementC, cutlass::layout::TensorNDHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv3dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv3d instance + EXPECT_TRUE(test::conv::device::TestAllConv3d()); +} + +//////////////////////////////////////////////////////////////////////////////// + + +TEST(SM80_Device_Conv3d_Wgrad_Optimized_ImplicitGemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32, + 128x128_32x4_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv3dWgradKernel = typename cutlass::conv::kernel::DefaultConv3dWgrad< + ElementA, cutlass::layout::TensorNDHWC, + ElementB, cutlass::layout::TensorNDHWC, + ElementC, cutlass::layout::TensorNDHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv3dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv3d instance + EXPECT_TRUE(test::conv::device::TestAllConv3d()); +} + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv3d_Wgrad_Optimized_ImplicitGemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32, + 64x256_32x4_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + using Conv3dWgradKernel = typename cutlass::conv::kernel::DefaultConv3dWgrad< + ElementA, cutlass::layout::TensorNDHWC, + ElementB, cutlass::layout::TensorNDHWC, + ElementC, cutlass::layout::TensorNDHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<64, 256, 32>, + cutlass::gemm::GemmShape<64, 64, 32>, + cutlass::gemm::GemmShape<16, 8, 16>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 4, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv3dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv3d instance + EXPECT_TRUE(test::conv::device::TestAllConv3d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM75_SUPPORTED + diff --git a/test/unit/conv/device/conv3d_wgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu b/test/unit/conv/device/conv3d_wgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu new file mode 100644 index 000000000..6dcbf0e72 --- /dev/null +++ b/test/unit/conv/device/conv3d_wgrad_implicit_gemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32_sm80.cu @@ -0,0 +1,120 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/*! \file + \brief Tests for device-wide Implicit GEMM interface +*/ + +#include "../../common/cutlass_unit_test.h" +#include "cutlass/cutlass.h" + +#include "cutlass/conv/kernel/default_conv3d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "conv3d_testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM80_Device_Conv3d_Wgrad_Analytic_ImplicitGemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::tfloat32_t; + using ElementB = cutlass::tfloat32_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv3dWgradKernel = typename cutlass::conv::kernel::DefaultConv3dWgrad< + ElementA, cutlass::layout::TensorNDHWC, + ElementB, cutlass::layout::TensorNDHWC, + ElementC, cutlass::layout::TensorNDHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd + >::Kernel; + + using Conv3dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv3d instance + EXPECT_TRUE(test::conv::device::TestAllConv3d()); +} + +//////////////////////////////////////////////////////////////////////////////// +TEST(SM80_Device_Conv3d_Wgrad_Optimized_ImplicitGemm_tf32ndhwc_tf32ndhwc_f32ndhwc_tensor_op_f32, + 128x128_32x3_64x64x32) { + + /// Conv operation element types for the Gemm equivalent (ImplicitGemm) + using ElementA = cutlass::tfloat32_t; + using ElementB = cutlass::tfloat32_t; + using ElementC = float; + using ElementAccumulator = float; + using ElementCompute = float; + + /// Device-level Conv2d instance + using Conv3dWgradKernel = typename cutlass::conv::kernel::DefaultConv3dWgrad< + ElementA, cutlass::layout::TensorNDHWC, + ElementB, cutlass::layout::TensorNDHWC, + ElementC, cutlass::layout::TensorNDHWC, + ElementAccumulator, + cutlass::arch::OpClassTensorOp, + cutlass::arch::Sm80, + cutlass::gemm::GemmShape<128, 128, 16>, + cutlass::gemm::GemmShape<64, 64, 16>, + cutlass::gemm::GemmShape<16, 8, 8>, + cutlass::epilogue::thread::LinearCombination< + ElementC, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >, + cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, + 3, + cutlass::arch::OpMultiplyAdd, + cutlass::conv::IteratorAlgorithm::kOptimized + >::Kernel; + + using Conv3dWgrad = cutlass::conv::device::ImplicitGemmConvolution; + + /// Run all unit test sizes with device-level Conv3d instance + EXPECT_TRUE(test::conv::device::TestAllConv3d()); +} + +//////////////////////////////////////////////////////////////////////////////// +#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED diff --git a/test/unit/epilogue/threadblock/epilogue_simt_sm61.cu b/test/unit/epilogue/threadblock/epilogue_simt_sm61.cu index fcc8426ca..f3552a184 100644 --- a/test/unit/epilogue/threadblock/epilogue_simt_sm61.cu +++ b/test/unit/epilogue/threadblock/epilogue_simt_sm61.cu @@ -804,7 +804,7 @@ TEST(SM61_Epilogue_threadblock_epilogue, simt_i8_i32_32x64_32x64x8) { // Output operator // - using OutputOp = cutlass::epilogue::thread::LinearCombinationClamp< + using OutputOp = cutlass::epilogue::thread::LinearCombination< ElementOutput, kElementsPerAccess, ElementAccumulator, @@ -874,7 +874,7 @@ TEST(SM61_Epilogue_threadblock_epilogue, simt_i8_i32_32x128_32x64x8) { // Output operator // - using OutputOp = cutlass::epilogue::thread::LinearCombinationClamp< + using OutputOp = cutlass::epilogue::thread::LinearCombination< ElementOutput, kElementsPerAccess, ElementAccumulator, @@ -944,7 +944,7 @@ TEST(SM61_Epilogue_threadblock_epilogue, simt_i8_i32_64x128_32x64x8) { // Output operator // - using OutputOp = cutlass::epilogue::thread::LinearCombinationClamp< + using OutputOp = cutlass::epilogue::thread::LinearCombination< ElementOutput, kElementsPerAccess, ElementAccumulator, @@ -1014,7 +1014,7 @@ TEST(SM61_Epilogue_threadblock_epilogue, simt_i8_i32_128x128_32x64x8) { // Output operator // - using OutputOp = cutlass::epilogue::thread::LinearCombinationClamp< + using OutputOp = cutlass::epilogue::thread::LinearCombination< ElementOutput, kElementsPerAccess, ElementAccumulator, @@ -1084,7 +1084,7 @@ TEST(SM61_Epilogue_threadblock_epilogue, simt_i8_i32_128x64_32x64x8) { // Output operator // - using OutputOp = cutlass::epilogue::thread::LinearCombinationClamp< + using OutputOp = cutlass::epilogue::thread::LinearCombination< ElementOutput, kElementsPerAccess, ElementAccumulator, diff --git a/test/unit/gemm/device/CMakeLists.txt b/test/unit/gemm/device/CMakeLists.txt index 84247e0bd..7ead7eba5 100644 --- a/test/unit/gemm/device/CMakeLists.txt +++ b/test/unit/gemm/device/CMakeLists.txt @@ -20,120 +20,47 @@ # STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -cutlass_test_unit_add_executable( +add_custom_target( cutlass_test_unit_gemm_device + DEPENDS + cutlass_test_unit_gemm_device_simt + cutlass_test_unit_gemm_device_tensorop_sm70 + cutlass_test_unit_gemm_device_tensorop_sm75 + cutlass_test_unit_gemm_device_tensorop_f16_sm80 + cutlass_test_unit_gemm_device_tensorop_f32_sm80 + cutlass_test_unit_gemm_device_tensorop_f32_tf32_sm80 + cutlass_test_unit_gemm_device_tensorop_f64 + cutlass_test_unit_gemm_device_tensorop_s32_sm80 + cutlass_test_unit_gemm_device_wmma + cutlass_test_unit_gemm_device_tensorop_planar_complex + cutlass_test_unit_gemm_device_sparse_tensorop_sm80 +) + +add_custom_target( + test_unit_gemm_device + DEPENDS + test_unit_gemm_device_simt + test_unit_gemm_device_tensorop_sm70 + test_unit_gemm_device_tensorop_sm75 + test_unit_gemm_device_tensorop_f16_sm80 + test_unit_gemm_device_tensorop_f32_sm80 + test_unit_gemm_device_tensorop_f32_tf32_sm80 + test_unit_gemm_device_tensorop_f64 + test_unit_gemm_device_tensorop_s32_sm80 + test_unit_gemm_device_wmma + test_unit_gemm_device_tensorop_planar_complex + test_unit_gemm_device_sparse_tensorop_sm80 +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_simt BATCH_SOURCES ON BATCH_SIZE 4 - gemm_planar_complex_f16_f16_f32_tensor_op_sm70.cu - gemm_planar_complex_f16_f16_f32_tensor_op_sm75.cu - gemm_planar_complex_f16_f16_f32_tensor_op_sm80.cu - - gemm_universal_f16n_f16t_f32t_tensor_op_f32_sm80.cu - gemm_universal_cf64n_cf64t_cf64t_tensor_op_f64_sm80.cu - gemm_universal_cf64n_cf64t_cf64t_tensor_op_f64_gaussian_sm80.cu - gemm_universal_cf32n_cf32n_cf32n_tensor_op_f32_sm80.cu - - gemm_cf64n_cf64t_cf64t_tensor_op_f64_sm80.cu - gemm_cf64t_cf64n_cf64t_tensor_op_f64_sm80.cu - - gemm_cf64n_cf64t_cf64t_tensor_op_f64_gaussian_sm80.cu - gemm_cf64t_cf64n_cf64t_tensor_op_f64_gaussian_sm80.cu - - gemm_cf32n_cf32t_cf32t_tensor_op_tf32_f32_sm80.cu - gemm_cf32t_cf32n_cf32t_tensor_op_tf32_f32_sm80.cu - - gemm_f16n_f16n_f16t_tensor_op_f32_sm80.cu - gemm_f16n_f16n_f32n_tensor_op_f32_sm80.cu - gemm_f16n_f16n_f32t_tensor_op_f32_sm80.cu - gemm_f16n_f16t_f16t_tensor_op_f16_sm80.cu - gemm_f16n_f16t_f32t_tensor_op_f32_sm80.cu - gemm_f16t_f16n_f16t_tensor_op_f16_sm80.cu - gemm_f16t_f16n_f32t_tensor_op_f32_sm80.cu - gemm_f16t_f16t_f32n_tensor_op_f32_sm80.cu - gemm_f16t_f16t_f32t_tensor_op_f32_sm80.cu - gemm_bf16n_bf16n_f32t_tensor_op_f32_sm80.cu - gemm_bf16t_bf16t_bf16t_tensor_op_f32_sm80.cu - gemm_tf32t_tf32n_f32t_tensor_op_f32_sm80.cu - gemm_tf32n_tf32t_f32t_tensor_op_f32_sm80.cu - gemm_tf32n_tf32n_f32t_tensor_op_f32_sm80.cu - gemm_tf32t_tf32t_f32t_tensor_op_f32_sm80.cu - - gemm_f16n_f16n_f16t_tensor_op_f32_sparse_sm80.cu - gemm_f16n_f16n_f32t_tensor_op_f32_sparse_sm80.cu - gemm_f16n_f16t_f16t_tensor_op_f16_sparse_sm80.cu - gemm_f16n_f16t_f32t_tensor_op_f32_sparse_sm80.cu - gemm_f16t_f16n_f16t_tensor_op_f16_sparse_sm80.cu - gemm_f16t_f16n_f32t_tensor_op_f32_sparse_sm80.cu - gemm_f16t_f16t_f32t_tensor_op_f32_sparse_sm80.cu - gemm_f32t_f32n_f32t_tensor_op_f32_sparse_sm80.cu - gemm_f32n_f32t_f32t_tensor_op_f32_sparse_sm80.cu - gemm_f32t_f32t_f32t_tensor_op_f32_sparse_sm80.cu - gemm_f32n_f32n_f32t_tensor_op_f32_sparse_sm80.cu - gemm_s8t_s8n_s32t_tensor_op_s32_sparse_sm80.cu - gemm_s4t_s4n_s32t_tensor_op_s32_sparse_sm80.cu - - gemm_f16t_f16n_f16t_tensor_op_f16_slicedk_sm80.cu - gemm_f16n_f16t_f16t_tensor_op_f16_slicedk_sm80.cu - simt_sgemm_nt_sm80.cu simt_sgemm_tn_sm80.cu - - gemm_s8t_s8n_s32t_tensor_op_s32_sm80.cu - gemm_s8t_s8n_s32n_tensor_op_s32_sm80.cu - gemm_s8t_s8n_s8n_tensor_op_s32_sm80.cu - gemm_s8t_s8n_s8t_tensor_op_s32_sm80.cu - gemm_s4t_s4n_s32n_tensor_op_s32_sm80.cu - gemm_s4t_s4n_s32t_tensor_op_s32_sm80.cu - gemm_b1t_b1n_s32n_tensor_op_s32_sm80.cu - gemm_b1t_b1n_s32t_tensor_op_s32_sm80.cu - - gemm_s8n_s8t_s8n_tensor_op_s32_sm80.cu - gemm_s4n_s4t_s4n_tensor_op_s32_sm80.cu - - gemm_f64n_f64t_f64t_tensor_op_f64_sm80.cu - gemm_f64t_f64n_f64t_tensor_op_f64_sm80.cu - - gemm_b1t_b1n_s32t_tensor_op_s32_sm75.cu - gemm_b1t_b1n_s32n_tensor_op_s32_sm75.cu - - gemm_f32n_f32n_f32t_tensor_op_f32_sm80.cu - gemm_f16t_f16n_f16t_tensor_op_f16_sm75.cu - gemm_f16n_f16t_f16t_tensor_op_f16_sm75.cu - gemm_f16n_f16t_f16t_tensor_op_f16_slicedk_sm75.cu - gemm_f16t_f16n_f16t_tensor_op_f16_slicedk_sm75.cu - - gemm_f16n_f16n_f16t_tensor_op_f32_sm75.cu - - gemm_f16n_f16n_f32t_tensor_op_f32_sm75.cu - gemm_f16n_f16t_f32t_tensor_op_f32_sm75.cu - gemm_f16t_f16n_f32t_tensor_op_f32_sm75.cu - gemm_f16t_f16t_f32t_tensor_op_f32_sm75.cu - - gemm_f16n_f16n_f32n_tensor_op_f32_sm75.cu - gemm_f16t_f16t_f32n_tensor_op_f32_sm75.cu - - gemm_s8n_s8t_s8n_tensor_op_s32_sm75.cu - gemm_s8t_s8n_s32t_tensor_op_s32_sm75.cu - gemm_s8t_s8n_s32n_tensor_op_s32_sm75.cu - gemm_s8t_s8n_s8t_tensor_op_s32_sm75.cu - gemm_s8t_s8n_s8n_tensor_op_s32_sm75.cu - - gemm_s4n_s4t_s4n_tensor_op_s32_sm75.cu - gemm_s4t_s4n_s32t_tensor_op_s32_sm75.cu - gemm_s4t_s4n_s32n_tensor_op_s32_sm75.cu - - gemm_f16n_f16n_f32t_volta_tensor_op_f32_sm70.cu - gemm_f16n_f16t_f32t_volta_tensor_op_f32_sm70.cu - gemm_f16t_f16n_f32t_volta_tensor_op_f32_sm70.cu - gemm_f16t_f16t_f32t_volta_tensor_op_f32_sm70.cu - - gemm_f16n_f16n_f16t_volta_tensor_op_f32_sm70.cu - - gemm_f16n_f16t_f16t_volta_tensor_op_f16_sm70.cu - gemm_f16t_f16n_f16t_volta_tensor_op_f16_sm70.cu - + simt_cgemm_nn_sm50.cu simt_cgemm_nt_sm50.cu simt_cgemm_tn_sm50.cu @@ -167,10 +94,158 @@ cutlass_test_unit_add_executable( simt_zgemm_tn_sm50.cu simt_zgemm_tt_sm50.cu + gemm_splitk_simt_sm50.cu +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_tensorop_sm70 + + BATCH_SOURCES ON + BATCH_SIZE 4 + + + gemm_f16n_f16n_f32t_volta_tensor_op_f32_sm70.cu + gemm_f16n_f16t_f32t_volta_tensor_op_f32_sm70.cu + gemm_f16t_f16n_f32t_volta_tensor_op_f32_sm70.cu + gemm_f16t_f16t_f32t_volta_tensor_op_f32_sm70.cu + + gemm_f16n_f16n_f16t_volta_tensor_op_f32_sm70.cu + + gemm_f16n_f16t_f16t_volta_tensor_op_f16_sm70.cu + gemm_f16t_f16n_f16t_volta_tensor_op_f16_sm70.cu + + gemm_splitk_tensor_op_sm70.cu +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_tensorop_sm75 + + BATCH_SOURCES ON + BATCH_SIZE 4 + + gemm_f16t_f16n_f16t_tensor_op_f16_sm75.cu + gemm_f16n_f16t_f16t_tensor_op_f16_sm75.cu + gemm_f16n_f16t_f16t_tensor_op_f16_slicedk_sm75.cu + gemm_f16t_f16n_f16t_tensor_op_f16_slicedk_sm75.cu + + gemm_f16n_f16n_f16t_tensor_op_f32_sm75.cu + + gemm_f16n_f16n_f32t_tensor_op_f32_sm75.cu + gemm_f16n_f16t_f32t_tensor_op_f32_sm75.cu + gemm_f16t_f16n_f32t_tensor_op_f32_sm75.cu + gemm_f16t_f16t_f32t_tensor_op_f32_sm75.cu + + gemm_f16n_f16n_f32n_tensor_op_f32_sm75.cu + gemm_f16t_f16t_f32n_tensor_op_f32_sm75.cu + + gemm_s8n_s8t_s8n_tensor_op_s32_sm75.cu + gemm_s8t_s8n_s32t_tensor_op_s32_sm75.cu + gemm_s8t_s8n_s32n_tensor_op_s32_sm75.cu + gemm_s8t_s8n_s8t_tensor_op_s32_sm75.cu + gemm_s8t_s8n_s8n_tensor_op_s32_sm75.cu + + gemm_s4n_s4t_s4n_tensor_op_s32_sm75.cu + gemm_s4t_s4n_s32t_tensor_op_s32_sm75.cu + gemm_s4t_s4n_s32n_tensor_op_s32_sm75.cu + + gemm_b1t_b1n_s32t_tensor_op_s32_sm75.cu + gemm_b1t_b1n_s32n_tensor_op_s32_sm75.cu + gemm_splitk_serial_tensor_op_sm75.cu gemm_splitk_tensor_op_sm75.cu - gemm_splitk_tensor_op_sm70.cu - gemm_splitk_simt_sm50.cu + +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_tensorop_f16_sm80 + + BATCH_SOURCES ON + BATCH_SIZE 4 + + gemm_f16t_f16n_f16t_tensor_op_f16_slicedk_sm80.cu + gemm_f16n_f16t_f16t_tensor_op_f16_slicedk_sm80.cu +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_tensorop_f32_sm80 + + BATCH_SOURCES ON + BATCH_SIZE 4 + + gemm_universal_f16n_f16t_f32t_tensor_op_f32_sm80.cu + gemm_f16n_f16n_f16t_tensor_op_f32_sm80.cu + gemm_f16n_f16n_f32n_tensor_op_f32_sm80.cu + gemm_f16n_f16n_f32t_tensor_op_f32_sm80.cu + gemm_f16n_f16t_f16t_tensor_op_f16_sm80.cu + gemm_f16n_f16t_f32t_tensor_op_f32_sm80.cu + gemm_f16t_f16n_f16t_tensor_op_f16_sm80.cu + gemm_f16t_f16n_f32t_tensor_op_f32_sm80.cu + gemm_f16t_f16t_f32n_tensor_op_f32_sm80.cu + gemm_f16t_f16t_f32t_tensor_op_f32_sm80.cu + gemm_bf16n_bf16n_f32t_tensor_op_f32_sm80.cu + gemm_bf16t_bf16t_bf16t_tensor_op_f32_sm80.cu +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_tensorop_f32_tf32_sm80 + + BATCH_SOURCES ON + BATCH_SIZE 4 + + gemm_tf32t_tf32n_f32t_tensor_op_f32_sm80.cu + gemm_tf32n_tf32t_f32t_tensor_op_f32_sm80.cu + gemm_tf32n_tf32n_f32t_tensor_op_f32_sm80.cu + gemm_tf32t_tf32t_f32t_tensor_op_f32_sm80.cu + gemm_universal_cf32n_cf32n_cf32n_tensor_op_f32_sm80.cu + gemm_cf32n_cf32t_cf32t_tensor_op_tf32_f32_sm80.cu + gemm_cf32t_cf32n_cf32t_tensor_op_tf32_f32_sm80.cu + + gemm_f32n_f32n_f32t_tensor_op_f32_sm80.cu + gemm_f32n_f32n_f32t_tensor_op_bf16_f32_sm80.cu +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_tensorop_f64 + + BATCH_SOURCES ON + BATCH_SIZE 4 + + gemm_f64n_f64t_f64t_tensor_op_f64_sm80.cu + gemm_f64t_f64n_f64t_tensor_op_f64_sm80.cu + + gemm_universal_cf64n_cf64t_cf64t_tensor_op_f64_sm80.cu + gemm_universal_cf64n_cf64t_cf64t_tensor_op_f64_gaussian_sm80.cu + gemm_cf64n_cf64t_cf64t_tensor_op_f64_sm80.cu + gemm_cf64t_cf64n_cf64t_tensor_op_f64_sm80.cu + gemm_cf64n_cf64t_cf64t_tensor_op_f64_gaussian_sm80.cu + gemm_cf64t_cf64n_cf64t_tensor_op_f64_gaussian_sm80.cu + +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_tensorop_s32_sm80 + + BATCH_SOURCES ON + BATCH_SIZE 4 + + gemm_s8t_s8n_s32t_tensor_op_s32_sm80.cu + gemm_s8t_s8n_s32n_tensor_op_s32_sm80.cu + gemm_s8t_s8n_s8n_tensor_op_s32_sm80.cu + gemm_s8t_s8n_s8t_tensor_op_s32_sm80.cu + gemm_s4t_s4n_s32n_tensor_op_s32_sm80.cu + gemm_s4t_s4n_s32t_tensor_op_s32_sm80.cu + gemm_b1t_b1n_s32n_tensor_op_s32_sm80.cu + gemm_b1t_b1n_s32t_tensor_op_s32_sm80.cu + + gemm_s8n_s8t_s8n_tensor_op_s32_sm80.cu + gemm_s4n_s4t_s4n_tensor_op_s32_sm80.cu +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_wmma + + BATCH_SOURCES ON + BATCH_SIZE 4 # wmma floating point tests gemm_f16t_f16n_f16t_wmma_tensor_op_f16_sm70.cu @@ -222,5 +297,37 @@ cutlass_test_unit_add_executable( gemm_f16t_f16n_f16n_singlestage_wmma_tensor_op_f16_sm70.cu gemm_f16t_f16n_f32t_singlestage_wmma_tensor_op_f32_sm70.cu - ) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_tensorop_planar_complex + + BATCH_SOURCES ON + BATCH_SIZE 4 + + gemm_planar_complex_f16_f16_f32_tensor_op_sm70.cu + gemm_planar_complex_f16_f16_f32_tensor_op_sm75.cu + gemm_planar_complex_f16_f16_f32_tensor_op_sm80.cu +) + +cutlass_test_unit_add_executable( + cutlass_test_unit_gemm_device_sparse_tensorop_sm80 + + BATCH_SOURCES ON + BATCH_SIZE 4 + + gemm_f16n_f16n_f16t_tensor_op_f32_sparse_sm80.cu + gemm_f16n_f16n_f32t_tensor_op_f32_sparse_sm80.cu + gemm_f16n_f16t_f16t_tensor_op_f16_sparse_sm80.cu + gemm_f16n_f16t_f32t_tensor_op_f32_sparse_sm80.cu + gemm_f16t_f16n_f16t_tensor_op_f16_sparse_sm80.cu + gemm_f16t_f16n_f32t_tensor_op_f32_sparse_sm80.cu + gemm_f16t_f16t_f32t_tensor_op_f32_sparse_sm80.cu + gemm_f32t_f32n_f32t_tensor_op_f32_sparse_sm80.cu + gemm_f32n_f32t_f32t_tensor_op_f32_sparse_sm80.cu + gemm_f32t_f32t_f32t_tensor_op_f32_sparse_sm80.cu + gemm_f32n_f32n_f32t_tensor_op_f32_sparse_sm80.cu + gemm_s8t_s8n_s32t_tensor_op_s32_sparse_sm80.cu + gemm_s4t_s4n_s32t_tensor_op_s32_sparse_sm80.cu +) + diff --git a/test/unit/gemm/device/multistage_testbed.h b/test/unit/gemm/device/multistage_testbed.h index bdc4b7708..f7b6ac8f5 100644 --- a/test/unit/gemm/device/multistage_testbed.h +++ b/test/unit/gemm/device/multistage_testbed.h @@ -97,10 +97,45 @@ struct MultistageTestbed { return true; } + /// Waives test if CUDA device is insufficient + bool sufficient() const { + // + // Determine SMEM requirements and waive if not satisfied + // + + int smem_size = int(sizeof(typename Gemm::GemmKernel::SharedStorage)); + + cudaDeviceProp properties; + int device_idx; + cudaError_t result = cudaGetDevice(&device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDevice() API call failed."); + } + + result = cudaGetDeviceProperties(&properties, device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDeviceProperties() failed"); + } + + if (properties.sharedMemPerMultiprocessor < smem_size) { + return false; + } + + return true; + } + /// Executes one test bool run(cutlass::gemm::GemmCoord problem_size, ElementCompute alpha = ElementCompute(1), ElementCompute beta = ElementCompute(0)) { + + // Waives test if CUDA device is insufficient + if (!sufficient()) { + return true; + } + // // Allocate the GEMM workspace // @@ -144,7 +179,11 @@ struct MultistageTestbed { cutlass::Status status = gemm_op.initialize(arguments); - EXPECT_TRUE(status == cutlass::Status::kSuccess); + if (status != cutlass::Status::kSuccess) { + cudaError_t error = cudaGetLastError(); + std::cerr << "This test is not supported: " << cudaGetErrorString(error) << "\n"; + return true; + } // // Run the GEMM diff --git a/test/unit/gemm/device/simt_sgemm_nt_sm80.cu b/test/unit/gemm/device/simt_sgemm_nt_sm80.cu index 7d2ab45b6..f0fe1ebd9 100644 --- a/test/unit/gemm/device/simt_sgemm_nt_sm80.cu +++ b/test/unit/gemm/device/simt_sgemm_nt_sm80.cu @@ -39,7 +39,8 @@ #include "cutlass/util/tensor_view_io.h" #include "testbed.h" - + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) //////////////////////////////////////////////////////////////////////////////// TEST(SM80_Device_Gemm_f32n_f32t_f32t_simt_f32, 32x64x8_32x64x1) { @@ -246,4 +247,8 @@ TEST(SM80_Device_Gemm_f32n_f32t_f32t_simt_f32, 128x256x8_64x64x1) { EXPECT_TRUE(test::gemm::device::TestAllGemm()); } -//////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#endif // #if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/unit/gemm/device/simt_sgemm_tn_sm80.cu b/test/unit/gemm/device/simt_sgemm_tn_sm80.cu index 00461d2e0..c183fbff3 100644 --- a/test/unit/gemm/device/simt_sgemm_tn_sm80.cu +++ b/test/unit/gemm/device/simt_sgemm_tn_sm80.cu @@ -41,8 +41,10 @@ #include "testbed.h" + +#if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) //////////////////////////////////////////////////////////////////////////////// - + TEST(SM80_Device_Gemm_f32t_f32n_f32t_simt_f32, 32x64x8_32x64x1) { using Element = float; @@ -246,4 +248,8 @@ TEST(SM80_Device_Gemm_f32t_f32n_f32t_simt_f32, 128x256x8_64x64x1) { EXPECT_TRUE(test::gemm::device::TestAllGemm()); } -//////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#endif // #if defined(CUTLASS_ARCH_MMA_SM80_SUPPORTED) + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/unit/gemm/device/testbed.h b/test/unit/gemm/device/testbed.h index b8c739a7e..c2bf40ec2 100644 --- a/test/unit/gemm/device/testbed.h +++ b/test/unit/gemm/device/testbed.h @@ -247,6 +247,36 @@ struct Testbed { return compare_reference(problem_size, alpha, beta); } + /// Determine if the CUDA device is sufficient to run the kernel + bool sufficient() const { + // + // Determine SMEM requirements and waive if not satisfied + // + + int smem_size = int(sizeof(typename Gemm::GemmKernel::SharedStorage)); + + cudaDeviceProp properties; + int device_idx; + cudaError_t result = cudaGetDevice(&device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDevice() API call failed."); + } + + result = cudaGetDeviceProperties(&properties, device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDeviceProperties() failed"); + } + + if (properties.sharedMemPerMultiprocessor < smem_size) { + return false; + } + + return true; + } + + /// Executes one test bool run( cutlass::gemm::GemmCoord problem_size, @@ -254,6 +284,10 @@ struct Testbed { ElementCompute alpha = ElementCompute(1), ElementCompute beta = ElementCompute(0)) { + // Waive test if insufficient CUDA device + if (!sufficient()) { + return true; + } this->initialize(problem_size); @@ -279,7 +313,11 @@ struct Testbed { cutlass::Status status = gemm_op.initialize(arguments, workspace.get()); - EXPECT_TRUE(status == cutlass::Status::kSuccess) << to_string(status); + if (status != cutlass::Status::kSuccess) { + cudaError_t error = cudaGetLastError(); + std::cerr << "This test is not supported: " << cudaGetErrorString(error) << "\n"; + return true; + } // // Run the GEMM diff --git a/test/unit/gemm/device/testbed_complex.h b/test/unit/gemm/device/testbed_complex.h index 65c0fdfb4..a3e1353ee 100644 --- a/test/unit/gemm/device/testbed_complex.h +++ b/test/unit/gemm/device/testbed_complex.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "../../common/cutlass_unit_test.h" @@ -100,6 +101,34 @@ struct TestbedComplex : public Testbed { return this->compare_reference(problem_size, alpha, beta); } + bool sufficient() const { + // + // Determine SMEM requirements and waive if not satisfied + // + + int smem_size = int(sizeof(typename Gemm::GemmKernel::SharedStorage)); + + cudaDeviceProp properties; + int device_idx; + cudaError_t result = cudaGetDevice(&device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDevice() API call failed."); + } + + result = cudaGetDeviceProperties(&properties, device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDeviceProperties() failed"); + } + + if (properties.sharedMemPerMultiprocessor < smem_size) { + return false; + } + + return true; + } + /// Executes one test bool run( cutlass::gemm::GemmCoord problem_size, @@ -107,7 +136,17 @@ struct TestbedComplex : public Testbed { ElementCompute alpha = ElementCompute(1), ElementCompute beta = ElementCompute(0)) { + // Waive the test if device not sufficient + if (!sufficient()) { + return true; + } + + // + // Initialize workspace + // + this->initialize(problem_size); + // // Initialize the GEMM operator diff --git a/test/unit/gemm/device/testbed_interleaved.h b/test/unit/gemm/device/testbed_interleaved.h index 3cbd720bd..6e14f87f6 100644 --- a/test/unit/gemm/device/testbed_interleaved.h +++ b/test/unit/gemm/device/testbed_interleaved.h @@ -99,6 +99,35 @@ struct InterleavedTestbed { return false; } + return true; + } + + /// Waives test if CUDA device is insufficient + bool sufficient() const { + // + // Determine SMEM requirements and waive if not satisfied + // + + int smem_size = int(sizeof(typename Gemm::GemmKernel::SharedStorage)); + + cudaDeviceProp properties; + int device_idx; + cudaError_t result = cudaGetDevice(&device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDevice() API call failed."); + } + + result = cudaGetDeviceProperties(&properties, device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDeviceProperties() failed"); + } + + if (properties.sharedMemPerMultiprocessor < smem_size) { + return false; + } + return true; } @@ -107,6 +136,10 @@ struct InterleavedTestbed { cutlass::gemm::GemmCoord problem_size, ElementCompute alpha = ElementCompute(1), ElementCompute beta = ElementCompute(0)) { + + if (!sufficient()) { + return true; + } // // Allocate the GEMM workspace diff --git a/test/unit/gemm/device/testbed_sparse.h b/test/unit/gemm/device/testbed_sparse.h index d1d57b893..28901a986 100644 --- a/test/unit/gemm/device/testbed_sparse.h +++ b/test/unit/gemm/device/testbed_sparse.h @@ -295,6 +295,34 @@ struct SparseTestbed { return compare_reference(problem_size, alpha, beta); } + bool sufficient() const { + // + // Determine SMEM requirements and waive if not satisfied + // + + int smem_size = int(sizeof(typename Gemm::GemmKernel::SharedStorage)); + + cudaDeviceProp properties; + int device_idx; + cudaError_t result = cudaGetDevice(&device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDevice() API call failed."); + } + + result = cudaGetDeviceProperties(&properties, device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDeviceProperties() failed"); + } + + if (properties.sharedMemPerMultiprocessor < smem_size) { + return false; + } + + return true; + } + /// Executes one test bool run( cutlass::gemm::GemmCoord problem_size, @@ -302,6 +330,11 @@ struct SparseTestbed { ElementCompute alpha = ElementCompute(1), ElementCompute beta = ElementCompute(0)) { + // Waive test if insufficient CUDA device + if (!sufficient()) { + return true; + } + this->initialize(problem_size); // @@ -327,7 +360,10 @@ struct SparseTestbed { cutlass::Status status = gemm_op.initialize(arguments, workspace.get()); - EXPECT_TRUE(status == cutlass::Status::kSuccess) << to_string(status); + // This failure is likely due to insufficient device capabilities. Waive the test. + if (status != cutlass::Status::kSuccess) { + return true; + } // // Run the GEMM diff --git a/test/unit/gemm/device/testbed_universal.h b/test/unit/gemm/device/testbed_universal.h index a83c27cda..fb36f10e2 100644 --- a/test/unit/gemm/device/testbed_universal.h +++ b/test/unit/gemm/device/testbed_universal.h @@ -250,6 +250,34 @@ struct TestbedUniversal { return compare_reference(problem_size, alpha, beta); } + bool sufficient() const { + // + // Determine SMEM requirements and waive if not satisfied + // + + int smem_size = int(sizeof(typename Gemm::GemmKernel::SharedStorage)); + + cudaDeviceProp properties; + int device_idx; + cudaError_t result = cudaGetDevice(&device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDevice() API call failed."); + } + + result = cudaGetDeviceProperties(&properties, device_idx); + + if (result != cudaSuccess) { + throw std::runtime_error("cudaGetDeviceProperties() failed"); + } + + if (properties.sharedMemPerMultiprocessor < smem_size) { + return false; + } + + return true; + } + /// Executes one test bool run( cutlass::gemm::GemmUniversalMode mode, @@ -258,6 +286,11 @@ struct TestbedUniversal { ElementCompute alpha = ElementCompute(1), ElementCompute beta = ElementCompute(0)) { + // Waive test if insufficient CUDA device + if (!sufficient()) { + return true; + } + this->initialize(problem_size); // diff --git a/test/unit/gemm/threadblock/mma_multistage_sparse_testbed.h b/test/unit/gemm/threadblock/mma_multistage_sparse_testbed.h index 7036e26d9..d667d8f55 100644 --- a/test/unit/gemm/threadblock/mma_multistage_sparse_testbed.h +++ b/test/unit/gemm/threadblock/mma_multistage_sparse_testbed.h @@ -328,19 +328,17 @@ struct SparseTestbed { test::gemm::threadblock::kernel_multistage_mma_sparse, cudaFuncAttributeMaxDynamicSharedMemorySize, smem_size); - EXPECT_EQ(result, cudaSuccess) - << " cudaFuncSetAttribute " - "cudaFuncAttributeMaxDynamicSharedMemorySize error: " - << cudaGetErrorString(result); + if (result != cudaSuccess) { + return true; + } result = cudaFuncSetAttribute( test::gemm::threadblock::kernel_multistage_mma_sparse, cudaFuncAttributePreferredSharedMemoryCarveout, 100); - EXPECT_EQ(result, cudaSuccess) - << " cudaFuncSetAttribute " - "cudaFuncAttributePreferredSharedMemoryCarveout error: " - << cudaGetErrorString(result); + if (result != cudaSuccess) { + return true; + } } test::gemm::threadblock::kernel_multistage_mma_sparse diff --git a/test/unit/gemm/threadblock/mma_multistage_testbed.h b/test/unit/gemm/threadblock/mma_multistage_testbed.h index 3870dd22f..6b8dc94fb 100644 --- a/test/unit/gemm/threadblock/mma_multistage_testbed.h +++ b/test/unit/gemm/threadblock/mma_multistage_testbed.h @@ -266,19 +266,17 @@ struct Testbed { test::gemm::threadblock::kernel_multistage_mma, cudaFuncAttributeMaxDynamicSharedMemorySize, smem_size); - EXPECT_EQ(result, cudaSuccess) - << " cudaFuncSetAttribute " - "cudaFuncAttributeMaxDynamicSharedMemorySize error: " - << cudaGetErrorString(result); + if (result != cudaSuccess) { + return true; + } result = cudaFuncSetAttribute( test::gemm::threadblock::kernel_multistage_mma, cudaFuncAttributePreferredSharedMemoryCarveout, 100); - EXPECT_EQ(result, cudaSuccess) - << " cudaFuncSetAttribute " - "cudaFuncAttributePreferredSharedMemoryCarveout error: " - << cudaGetErrorString(result); + if (result != cudaSuccess) { + return true; + } } test::gemm::threadblock::kernel_multistage_mma diff --git a/test/unit/gemm/warp/gemm_sm70.cu b/test/unit/gemm/warp/gemm_sm70.cu index 16f1427e5..3785290e5 100644 --- a/test/unit/gemm/warp/gemm_sm70.cu +++ b/test/unit/gemm/warp/gemm_sm70.cu @@ -199,6 +199,91 @@ TEST(SM70_warp_gemm_tensor_op_crosswise, 64x64x32_64x64x32_16x16x4) { test::gemm::warp::Testbed >().run(); } + +//////////////////////////////////////////////////////////////////////////////// + +TEST(SM70_warp_gemm_volta_tensor_op_canonical_f32_row_col, 64x64x16_64x64x4_8x8x4) { + + using Shape = cutlass::gemm::GemmShape<64, 64, 4>; + using InstructionShape = cutlass::gemm::GemmShape<8, 8, 4>; + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using LayoutA = cutlass::layout::RowMajor; + using LayoutB = cutlass::layout::ColumnMajor; + + using Policy = cutlass::gemm::warp::MmaTensorOpPolicy< + cutlass::arch::Mma< + cutlass::gemm::GemmShape<16, 16, 4>, + 32, + ElementA, + cutlass::layout::RowMajor, + ElementB, + cutlass::layout::ColumnMajor, + ElementC, + cutlass::layout::RowMajor, + cutlass::arch::OpMultiplyAdd + >, + cutlass::MatrixShape<1, 1> + >; + + using MmaTensorOp = cutlass::gemm::warp::MmaVoltaTensorOp< + Shape, + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + cutlass::layout::RowMajor, + Policy + >; + + test::gemm::warp::Testbed >() + .run(); +} + +TEST(SM70_warp_gemm_volta_tensor_op_canonical_f32_col_row, 64x64x16_64x64x4_8x8x4) { + + using Shape = cutlass::gemm::GemmShape<64, 64, 4>; + using InstructionShape = cutlass::gemm::GemmShape<8, 8, 4>; + using ElementA = cutlass::half_t; + using ElementB = cutlass::half_t; + using ElementC = float; + using LayoutA = cutlass::layout::ColumnMajor; + using LayoutB = cutlass::layout::RowMajor; + + using Policy = cutlass::gemm::warp::MmaTensorOpPolicy< + cutlass::arch::Mma< + cutlass::gemm::GemmShape<16, 16, 4>, + 32, + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + cutlass::layout::RowMajor, + cutlass::arch::OpMultiplyAdd + >, + cutlass::MatrixShape<1, 1> + >; + + using MmaTensorOp = cutlass::gemm::warp::MmaVoltaTensorOp< + Shape, + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + cutlass::layout::RowMajor, + Policy + >; + + test::gemm::warp::Testbed >() + .run(); +} + ///////////////////////////////////////////////////////////////////////////////////////////////// #endif // CUTLASS_ARCH_MMA_SM70_SUPPORTED diff --git a/test/unit/gemm/warp/testbed.h b/test/unit/gemm/warp/testbed.h index c0c98d80d..3cc00fb44 100644 --- a/test/unit/gemm/warp/testbed.h +++ b/test/unit/gemm/warp/testbed.h @@ -30,6 +30,7 @@ #include "cutlass/cutlass.h" #include "cutlass/aligned_buffer.h" +#include "cutlass/numeric_types.h" #include "cutlass/subbyte_reference.h" #include "cutlass/platform/platform.h" @@ -1019,9 +1020,11 @@ __global__ void sparse_kernel( typename Mma::ElementB, ThreadblockShape::kN * ThreadblockShape::kK> smem_buffer_B; __shared__ cutlass::AlignedBuffer< - typename Mma::ElementE, ThreadblockShape::kM * ThreadblockShape::kK / + typename Mma::ElementE, Mma::Shape::kM * Mma::Shape::kK / Mma::kSparse / Mma::kElementsPerElementE> smem_buffer_E; + + __syncthreads(); if (threadIdx.x == 0) { typename Mma::ElementA *smem_ptr_A = smem_buffer_A.data(); @@ -1168,6 +1171,7 @@ struct SparseTestbed { /// Allocates workspace in device memory SparseTestbed() { + tensor_A.reset(cutlass::make_Coord(ThreadblockShape::kM, ThreadblockShape::kK / Sparse)); tensor_A_uncompressed.reset( diff --git a/test/unit/reduction/CMakeLists.txt b/test/unit/reduction/CMakeLists.txt index 7b4f26706..96c371614 100644 --- a/test/unit/reduction/CMakeLists.txt +++ b/test/unit/reduction/CMakeLists.txt @@ -22,7 +22,6 @@ add_subdirectory(thread) add_subdirectory(kernel) - add_custom_target( cutlass_test_unit_reduction DEPENDS diff --git a/test/unit/transform/threadblock/regular_tile_iterator_tensor_op.cu b/test/unit/transform/threadblock/regular_tile_iterator_tensor_op.cu index e52af8edf..8d2382e4c 100644 --- a/test/unit/transform/threadblock/regular_tile_iterator_tensor_op.cu +++ b/test/unit/transform/threadblock/regular_tile_iterator_tensor_op.cu @@ -81,7 +81,7 @@ __global__ void kernel_gemm_threadblock_tensor_op_multiplicand_store( } } - // Use iterator to scatter results + // Use iterator to store results Iterator iter(ref_output, threadIdx.x); iter.store(frag); } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 3ca637b2d..e43c821e6 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -26,6 +26,12 @@ if (CUTLASS_ENABLE_LIBRARY) add_subdirectory(library) endif() if (CUTLASS_ENABLE_PROFILER) - add_subdirectory(profiler) + if (NOT CUTLASS_ENABLE_LIBRARY) + message(SEND_ERROR "Build conflict: The CUTLASS profiler requires the CUTLASS library.") + message(SEND_ERROR " CUTLASS_ENABLE_PROFILER = ${CUTLASS_ENABLE_PROFILER}") + message(SEND_ERROR " CUTLASS_ENABLE_LIBRARY = ${CUTLASS_ENABLE_LIBRARY}") + else() + add_subdirectory(profiler) + endif() endif() diff --git a/tools/library/CMakeLists.txt b/tools/library/CMakeLists.txt index 294cd98f0..4bf7577fb 100644 --- a/tools/library/CMakeLists.txt +++ b/tools/library/CMakeLists.txt @@ -63,6 +63,15 @@ cutlass_add_library( src/reference/gemm.cu src/reference/initialize_reference_operations.cu + + # cutlass reduction instances in cutlass library + src/reduction/reduction_device.cu + src/reduction/init_reduction_operations.cu + + # cutlass conv reference instances in cutlass library + src/reference/conv2d.cu + src/reference/conv3d.cu + ) file(GLOB_RECURSE GENERATOR_PYTHON_SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.py) @@ -136,7 +145,7 @@ function(cutlass_add_cutlass_library) cutlass_library_includes ) - set_target_properties(${__NAME} PROPERTIES DEBUG_POSTFIX ${CUTLASS_LIBRARY_DEBUG_POSTFIX}) + set_target_properties(${__NAME} PROPERTIES DEBUG_POSTFIX "${CUTLASS_LIBRARY_DEBUG_POSTFIX}") set(OUTPUT_NAME cutlass) diff --git a/tools/library/include/cutlass/library/handle.h b/tools/library/include/cutlass/library/handle.h index 58c6b30c7..27d2bfe6a 100644 --- a/tools/library/include/cutlass/library/handle.h +++ b/tools/library/include/cutlass/library/handle.h @@ -335,6 +335,10 @@ public: using HandlePtr = std::unique_ptr; ///////////////////////////////////////////////////////////////////////////////////////////////// +/// Finds conv2d operation instances with Conv2d::ElementC = Reduction::ElementWorkspace +Operation const* find_conv_operation_for_parallel_reduction(Operation const *operation); +///////////////////////////////////////////////////////////////////////////////////////////////// + } // namespace library } // namespace cutlass diff --git a/tools/library/include/cutlass/library/library.h b/tools/library/include/cutlass/library/library.h index f69243719..6a018a704 100644 --- a/tools/library/include/cutlass/library/library.h +++ b/tools/library/include/cutlass/library/library.h @@ -53,6 +53,10 @@ #include "cutlass/layout/tensor.h" #include "cutlass/gemm/gemm.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/conv3d_problem_size.h" + ///////////////////////////////////////////////////////////////////////////////////////////////// namespace cutlass { @@ -79,6 +83,10 @@ enum class LayoutTypeID { kTensorNCDHW, kTensorNHWC, kTensorNDHWC, + kTensorNC32HW32, + kTensorC32RSK32, + kTensorNC64HW64, + kTensorC64RSK64, kInvalid }; @@ -138,6 +146,7 @@ enum class Provider { kReferenceHost, kReferenceDevice, kCUBLAS, + kCUDNN, kInvalid }; @@ -146,6 +155,8 @@ enum class Provider { /// Enumeration indicating the kind of operation enum class OperationKind { kGemm, + kConv2d, + kConv3d, kEqGemm, kSparseGemm, kReduction, @@ -204,6 +215,30 @@ enum class GemmKind { /// Mode of Universal GEMM using GemmUniversalMode = cutlass::gemm::GemmUniversalMode; +/// Enumeration indicating what kind of Conv2d operation to perform +enum class ConvKind { + kUnknown, + kFprop, + kDgrad, + kWgrad, + kInvalid +}; + +enum class ConvModeID { + kCrossCorrelation, + kConvolution, + kInvalid +}; + +// Iterator algorithm enum in order of general performance-efficiency +enum class IteratorAlgorithmID { + kNone, + kAnalytic, + kOptimized, + kInvalid +}; + + enum class EpilogueKind { kUnknown, kConversion, @@ -477,6 +512,66 @@ struct ReductionDescription : public OperationDescription { }; ///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Description of all Conv2d operations +struct ConvDescription : public OperationDescription { + /// Describes the convolution dimension support (2D or 3D) + int conv_dim; + + /// Describes the kind of convolution + ConvKind conv_kind; + + /// Describes the type of iterator algorithm (analytic or precomputed) + IteratorAlgorithmID iterator_algorithm; + + /// Describes the A operand + TensorDescription A; + + /// Describes the B operand + TensorDescription B; + + /// Describes the C operand + TensorDescription C; + + /// Describes the data type of the scalars passed to the epilogue + NumericTypeID element_epilogue; + + // + // Methods + // + // Returns Activation TensorDescription + TensorDescription activation() const { + switch(conv_kind) { + case library::ConvKind::kFprop : return A; + case library::ConvKind::kDgrad : return C; + case library::ConvKind::kWgrad : return B; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns Filter TensorDescription + TensorDescription filter() const { + switch(conv_kind) { + case library::ConvKind::kFprop : return B; + case library::ConvKind::kDgrad : return B; + case library::ConvKind::kWgrad : return C; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns Output TensorDescription + TensorDescription output() const { + switch(conv_kind) { + case library::ConvKind::kFprop : return C; + case library::ConvKind::kDgrad : return A; + case library::ConvKind::kWgrad : return A; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + +}; + + ///////////////////////////////////////////////////////////////////////////////////////////////// /// Base class for all operations @@ -825,6 +920,204 @@ struct SparseGemmArguments { ///////////////////////////////////////////////////////////////////////////////////////////////// +/// Two dimensional convolution +// +// OperationKind: Conv2d +// +struct Conv2dConfiguration { + + conv::SplitKMode split_k_mode; + + /// Conv2d problem size + // contains strictly conv2d size (N,H,W,C,K,R,S,P,Q,padding,stride,dilation,mode) + // also includes (split_k_slices, groups) + conv::Conv2dProblemSize problem_size; + + /// Layout object for activations tensor + layout::TensorNHWC layout_activations; + + /// Layout object for filters tensor + layout::TensorNHWC layout_filters; + + /// Layout object for source tensor + layout::TensorNHWC layout_source; + + /// Layout object for output tensor + layout::TensorNHWC layout_output; + + // + // Methods + // + + // Mapping functions (A,B,C -> activation,filter,output) + layout::TensorNHWC layout_a(library::ConvKind const &conv_kind) const { + switch (conv_kind) { + case library::ConvKind::kFprop: return layout_activations; + case library::ConvKind::kDgrad: return layout_output; + case library::ConvKind::kWgrad: return layout_output; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + layout::TensorNHWC layout_b(library::ConvKind const &conv_kind) const { + switch (conv_kind) { + case library::ConvKind::kFprop: return layout_filters; + case library::ConvKind::kDgrad: return layout_filters; + case library::ConvKind::kWgrad: return layout_activations; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + layout::TensorNHWC layout_c(library::ConvKind const &conv_kind) const { + switch (conv_kind) { + case library::ConvKind::kFprop: return layout_output; + case library::ConvKind::kDgrad: return layout_activations; + case library::ConvKind::kWgrad: return layout_filters; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } +}; + + +/// Three dimensional convolution +// +// OperationKind: Conv3d +// +struct Conv3dConfiguration { + + conv::SplitKMode split_k_mode; + + /// Conv2d problem size + // contains strictly conv2d size (N,D,H,W,C,K,T,R,S,Z,P,Q,padding,stride,dilation,mode) + // also includes (split_k_slices, groups) + conv::Conv3dProblemSize problem_size; + + /// Layout object for activations tensor + layout::TensorNDHWC layout_activations; + + /// Layout object for filters tensor + layout::TensorNDHWC layout_filters; + + /// Layout object for source tensor + layout::TensorNDHWC layout_source; + + /// Layout object for output tensor + layout::TensorNDHWC layout_output; + + // + // Methods + // + + // Mapping functions (A,B,C -> activation,filter,output) + layout::TensorNDHWC layout_a(library::ConvKind const &conv_kind) const { + switch (conv_kind) { + case library::ConvKind::kFprop: return layout_activations; + case library::ConvKind::kDgrad: return layout_output; + case library::ConvKind::kWgrad: return layout_output; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + layout::TensorNDHWC layout_b(library::ConvKind const &conv_kind) const { + switch (conv_kind) { + case library::ConvKind::kFprop: return layout_filters; + case library::ConvKind::kDgrad: return layout_filters; + case library::ConvKind::kWgrad: return layout_activations; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + layout::TensorNDHWC layout_c(library::ConvKind const &conv_kind) const { + switch (conv_kind) { + case library::ConvKind::kFprop: return layout_output; + case library::ConvKind::kDgrad: return layout_activations; + case library::ConvKind::kWgrad: return layout_filters; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } +}; + +/// Arguments for CONV +struct ConvArguments { + + ///////////////////////////////////////////////////////// + /// ImplicitGemm matrices A, B, C, D + ///////////////////////////////////////////////////////// + /// pointer to implicit gemm matrix A + void const *A; + + /// pointer to implicit gemm matrix B + void const *B; + + /// pointer to implicit gemm matrix C + void const *C; + + /// pointer to implicit gemm desitination matrix D + void *D; + + /// Host or device pointer to alpha scalar + void const *alpha; + + /// Host or device pointer to beta scalar + void const *beta; + + /// Enumerant indicating whether alpha/beta point to host or device memory + ScalarPointerMode pointer_mode; + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Configuration for Reduction operations +// +// OperationKind: Reduction +// +struct ReductionConfiguration { + + /// Redcution problem size + MatrixCoord problem_size; + + /// Number of partitions to reduce + int partitions; + + /// Number of lements between each partition + int64_t partition_stride; + + /// leading dimension of 'w'orksace operand + int64_t ldw; + + /// leading dimension of 's'ource operand + int64_t lds; + + /// leading dimension of 'd'estination operand + int64_t ldd; +}; + +/// Arguments for Reduction +struct ReductionArguments { + + /// Pointer to workspace matrix + void const *workspace; + + /// Pointer to source matrix + void const *source; + + /// Pointer to destination matrix + void *destination; + + /// pointer to reference matrix + void *reference; + + /// Host or device pointer to alpha scalar + void const *alpha; + + /// Host or device pointer to beta scalar + void const *beta; + + /// Enumerant indicating whether alpha/beta point to host or device memory + ScalarPointerMode pointer_mode; +}; + } // namespace library } // namespace cutlass diff --git a/tools/library/include/cutlass/library/manifest.h b/tools/library/include/cutlass/library/manifest.h index 7adf0fbbc..2bde2884b 100644 --- a/tools/library/include/cutlass/library/manifest.h +++ b/tools/library/include/cutlass/library/manifest.h @@ -51,6 +51,9 @@ class Manifest; // init and insert all cutlass gemm operations in manifest object (procedurally generated using generator.py) void initialize_all(Manifest &manifest); +// init and insert all reduction op in manifest object (manually instantiated in library/reduction) +void initialize_all_reduction_op(Manifest &manifest); + ///////////////////////////////////////////////////////////////////////////////////////////////////////// /// List of operations diff --git a/tools/library/include/cutlass/library/operation_table.h b/tools/library/include/cutlass/library/operation_table.h index 3821f65ac..ba19ca123 100644 --- a/tools/library/include/cutlass/library/operation_table.h +++ b/tools/library/include/cutlass/library/operation_table.h @@ -208,6 +208,262 @@ using GemmOperationFunctionalMap = std::unordered_map< >; ///////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////// +// Data Structures for Conv Functional Maps +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Tuple uniquely identifying conv2d functional behavior +struct ConvFunctionalKey { + library::Provider provider; + library::ConvKind conv_kind; + library::NumericTypeID element_A; + library::LayoutTypeID layout_A; + library::NumericTypeID element_B; + library::LayoutTypeID layout_B; + library::NumericTypeID element_C; + library::LayoutTypeID layout_C; + library::NumericTypeID element_accumulator; + library::NumericTypeID element_compute; + + + // + // Methods + // + + inline + ConvFunctionalKey( + library::Provider provider = library::Provider::kInvalid, + library::ConvKind conv_kind = library::ConvKind::kFprop, + library::NumericTypeID element_A = library::NumericTypeID::kF16, + library::LayoutTypeID layout_A = library::LayoutTypeID::kTensorNHWC, + library::NumericTypeID element_B = library::NumericTypeID::kF16, + library::LayoutTypeID layout_B = library::LayoutTypeID::kTensorNHWC, + library::NumericTypeID element_C = library::NumericTypeID::kF16, + library::LayoutTypeID layout_C = library::LayoutTypeID::kTensorNHWC, + library::NumericTypeID element_accumulator = library::NumericTypeID::kF32, + library::NumericTypeID element_compute = library::NumericTypeID::kF32 + ): + provider(provider), + conv_kind(conv_kind), + element_A(element_A), + layout_A(layout_A), + element_B(element_B), + layout_B(layout_B), + element_C(element_C), + layout_C(layout_C), + element_accumulator(element_accumulator), + element_compute(element_compute) + { } + + inline + bool operator==(ConvFunctionalKey const &rhs) const { + return + (provider == rhs.provider) && + (conv_kind == rhs.conv_kind) && + (element_A == rhs.element_A) && + (layout_A == rhs.layout_A) && + (element_B == rhs.element_B) && + (layout_B == rhs.layout_B) && + (element_C == rhs.element_C) && + (layout_C == rhs.layout_C) && + (element_accumulator == rhs.element_accumulator) && + (element_compute == rhs.element_compute); + } + + inline + bool operator!=(ConvFunctionalKey const &rhs) const { + return !(*this == rhs); + } +}; +///////////////////////////////////////////////////////////////////////////////////////////////// +inline +std::ostream& operator<< (std::ostream& out, const cutlass::library::ConvFunctionalKey& key) { + out << "{\n" + << "provider: " << to_string(key.provider) << std::endl + << "conv_kind: " << to_string(key.conv_kind) << std::endl + << "element_A: " << to_string(key.element_A) << std::endl + << "layout_A: " << to_string(key.layout_A) << std::endl + << "element_B: " << to_string(key.element_B) << std::endl + << "layout_B: " << to_string(key.layout_B) << std::endl + << "element_C: " << to_string(key.element_C) << std::endl + << "layout_C: " << to_string(key.layout_C) << std::endl + << "element_accumulator: " << to_string(key.element_accumulator) << std::endl + << "element_compute: " << to_string(key.element_compute) << std::endl + << "}"; + + return out; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +struct ConvFunctionalKeyHasher { + using IntHash = std::hash; + + inline + static size_t rotl(size_t key, int shl) { + return (key << shl) | (key >> (sizeof(key)*8 - shl)); + } + + inline + size_t operator()(ConvFunctionalKey const &key) const { + IntHash hash; + + return + rotl(hash(int(key.provider)), 1) ^ + rotl(hash(int(key.conv_kind)), 2) ^ + rotl(hash(int(key.element_A)), 3) ^ + rotl(hash(int(key.layout_A)), 4) ^ + rotl(hash(int(key.element_B)), 5) ^ + rotl(hash(int(key.layout_B)), 6) ^ + rotl(hash(int(key.element_C)), 7) ^ + rotl(hash(int(key.layout_C)), 8) ^ + rotl(hash(int(key.element_accumulator)), 9) ^ + rotl(hash(int(key.element_compute)), 10); + } +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Establishes a partial ordering to search for Conv2d operators +struct ConvPreferenceKey { + + int compute_capability; + IteratorAlgorithmID iterator_algorithm; + + + // + // Methods + // + + ConvPreferenceKey(): compute_capability(), iterator_algorithm() { } + + ConvPreferenceKey(int cc, IteratorAlgorithmID iterator_algorithm): + compute_capability(cc), iterator_algorithm(iterator_algorithm) { } + + bool operator<(ConvPreferenceKey const &rhs) const { + return (compute_capability < rhs.compute_capability) || + ((compute_capability == rhs.compute_capability) && (iterator_algorithm < rhs.iterator_algorithm)); + } + + bool operator==(ConvPreferenceKey const &rhs) const { + return (compute_capability == rhs.compute_capability) && + (iterator_algorithm == rhs.iterator_algorithm); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Maps minimum compute capability onto a vector of possible operations +using ConvOperationVectorMap = std::map< + ConvPreferenceKey, + std::vector +>; + +/// Maps a GemmFunctionalKey onto a vector of Operation * objects expected to be of kind kGemm +using ConvOperationFunctionalMap = std::unordered_map< + ConvFunctionalKey, + ConvOperationVectorMap, + ConvFunctionalKeyHasher +>; +///////////////////////////////////////////////////////////////////////////////////////////////// + + +/// Tuple uniquely identifying conv2d functional behavior +struct ReductionFunctionalKey { + library::Provider provider; + library::NumericTypeID element_workspace; + library::NumericTypeID element_accumulator; + library::NumericTypeID element_output; + library::NumericTypeID element_compute; + library::MathOperationID reduce_math_op; + library::EpilogueKind epilogue_math_op; + + + // + // Methods + // + + inline + ReductionFunctionalKey( + library::Provider provider = library::Provider::kInvalid, + library::NumericTypeID element_workspace = library::NumericTypeID::kF16, + library::NumericTypeID element_accumulator = library::NumericTypeID::kF32, + library::NumericTypeID element_output = library::NumericTypeID::kF16, + library::NumericTypeID element_compute = library::NumericTypeID::kF32, + library::MathOperationID reduce_math_op = library::MathOperationID::kAdd, + library::EpilogueKind epilogue_math_op = library::EpilogueKind::kLinearCombination + ): + provider(provider), + element_workspace(element_workspace), + element_accumulator(element_accumulator), + element_output(element_output), + element_compute(element_compute), + reduce_math_op(reduce_math_op), + epilogue_math_op(epilogue_math_op) + { } + + inline + bool operator==(ReductionFunctionalKey const &rhs) const { + return + (provider == rhs.provider) && + (element_workspace == rhs.element_workspace) && + (element_accumulator == rhs.element_accumulator) && + (element_output == rhs.element_output) && + (element_compute == rhs.element_compute) && + (reduce_math_op == rhs.reduce_math_op) && + (epilogue_math_op == rhs.epilogue_math_op); + } + + inline + bool operator!=(ReductionFunctionalKey const &rhs) const { + return !(*this == rhs); + } +}; + + +struct ReductionFunctionalKeyHasher { + using IntHash = std::hash; + + inline + static size_t rotl(size_t key, int shl) { + return (key << shl) | (key >> (sizeof(key)*8 - shl)); + } + + inline + size_t operator()(ReductionFunctionalKey const &key) const { + IntHash hash; + + return + rotl(hash(int(key.provider)), 1) ^ + rotl(hash(int(key.element_workspace)), 2) ^ + rotl(hash(int(key.element_accumulator)), 3) ^ + rotl(hash(int(key.element_output)), 4) ^ + rotl(hash(int(key.element_compute)), 5) ^ + rotl(hash(int(key.reduce_math_op)), 6) ^ + rotl(hash(int(key.epilogue_math_op)), 7); + } +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + +inline +std::ostream& operator<< (std::ostream& out, const ReductionFunctionalKey& key) { + out << "{\n" + << "provider: " << library::to_string(key.provider) << std::endl + << "element_workspace : " << library::to_string(key.element_workspace) << std::endl + << "element_accumulator : " << library::to_string(key.element_accumulator) << std::endl + << "element_output : " << library::to_string(key.element_output) << std::endl + << "element_compute : " << library::to_string(key.element_compute) << std::endl + << "}"; + return out; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// ReductionOperationFunctionalMap has NO preference key and a single instance per functional key +// i.e. only one tile size configuration per functional key +using ReductionOperationFunctionalMap = std::unordered_map< + ReductionFunctionalKey, + library::Operation const *, + ReductionFunctionalKeyHasher +>; + ///////////////////////////////////////////////////////////////////////////////////////////////// /// Table of cutlass::library::Operation instances @@ -218,6 +474,18 @@ public: // provider (kCUTLASS) GemmOperationFunctionalMap gemm_operations; + /// Map of all operations of type kConv2d + // provider (kCUTLASS, kReferenceHost, kReferenceDevice) + ConvOperationFunctionalMap conv2d_operations; + + /// Map of all operations of type kConv3d + // provider (kCUTLASS, kReferenceHost, kReferenceDevice) + ConvOperationFunctionalMap conv3d_operations; + + /// Map of all operations of type kConv2d + // provider (kCUTLASS) + ReductionOperationFunctionalMap reduction_operations; + public: void append(Manifest const &manifest); diff --git a/tools/library/include/cutlass/library/util.h b/tools/library/include/cutlass/library/util.h index 526f836b2..2e4a28c14 100644 --- a/tools/library/include/cutlass/library/util.h +++ b/tools/library/include/cutlass/library/util.h @@ -122,6 +122,27 @@ char const *to_string(SplitKMode split_k_mode, bool pretty = false); template <> SplitKMode from_string(std::string const &str); +/// Converts a ConvModeID enumerant to a string +char const *to_string(ConvModeID type, bool pretty = false); + +/// Converts a ConvModeID enumerant from a string +template <> +ConvModeID from_string(std::string const &str); + +/// Converts a IteratorAlgorithmID enumerant to a string +char const *to_string(IteratorAlgorithmID type, bool pretty = false); + +/// Converts a IteratorAlgorithmID enumerant from a string +template <> +IteratorAlgorithmID from_string(std::string const &str); + +/// Converts a ConvKind enumerant to a string +char const *to_string(ConvKind type, bool pretty = false); + +/// Converts a ConvKind enumerant from a string +template <> +ConvKind from_string(std::string const &str); + /// Lexical cast from int64_t to string std::string lexical_cast(int64_t int_value); diff --git a/tools/library/scripts/conv2d_operation.py b/tools/library/scripts/conv2d_operation.py new file mode 100644 index 000000000..e164bd007 --- /dev/null +++ b/tools/library/scripts/conv2d_operation.py @@ -0,0 +1,344 @@ +# +# \file generator.py +# +# \brief Generates the CUTLASS Library's instances +# +# + +import enum +import os.path +import shutil + +from library import * + +################################################################################################### + +# +class Conv2dOperation: + # + def __init__(self, conv_kind, iterator_algorithm, arch, tile_description, A, B, C, element_epilogue, \ + stride_support, epilogue_functor = EpilogueFunctor.LinearCombination, swizzling_functor = SwizzlingFunctor.Identity4): + + self.operation_kind = OperationKind.Conv2d + self.arch = arch + self.tile_description = tile_description + self.conv_kind = conv_kind + self.A = A + self.B = B + self.C = C + self.element_epilogue = element_epilogue + self.epilogue_functor = epilogue_functor + self.iterator_algorithm = iterator_algorithm + self.stride_support = stride_support + self.swizzling_functor = swizzling_functor + # + def is_complex(self): + complex_operators = [ + MathOperation.multiply_add_complex, + MathOperation.multiply_add_complex_gaussian + ] + return self.tile_description.math_instruction.math_operation in complex_operators + + # + def accumulator_type(self): + accum = self.tile_description.math_instruction.element_accumulator + + if self.is_complex(): + return get_complex_from_real(accum) + + return accum + + # + def core_name(self): + ''' The basic operation kind is prefixed with a letter indicating the accumulation type. ''' + + intermediate_type = '' + + if self.tile_description.math_instruction.opcode_class == OpcodeClass.TensorOp: + inst_shape = "%d%d%d" % tuple(self.tile_description.math_instruction.instruction_shape) + if self.tile_description.math_instruction.element_a != self.A.element and \ + self.tile_description.math_instruction.element_a != self.accumulator_type(): + intermediate_type = DataTypeNames[self.tile_description.math_instruction.element_a] + else: + inst_shape = '' + + return "%s%s%s%s_%s" % (ShortDataTypeNames[self.accumulator_type()], \ + inst_shape, intermediate_type, ConvKindNames[self.conv_kind], IteratorAlgorithmNames[self.iterator_algorithm]) + + # + def extended_name(self): + ''' Append data types if they differ from compute type. ''' + if self.C.element != self.tile_description.math_instruction.element_accumulator and \ + self.A.element != self.tile_description.math_instruction.element_accumulator: + extended_name = "${element_c}_${core_name}_${element_a}" + elif self.C.element == self.tile_description.math_instruction.element_accumulator and \ + self.A.element != self.tile_description.math_instruction.element_accumulator: + extended_name = "${core_name}_${element_a}" + else: + extended_name = "${core_name}" + + extended_name = SubstituteTemplate(extended_name, { + 'element_a': DataTypeNames[self.A.element], + 'element_c': DataTypeNames[self.C.element], + 'core_name': self.core_name() + }) + + return extended_name + + # + def layout_name(self): + return "%s" % (ShortLayoutTypeNames[self.A.layout]) + + # + def configuration_name(self): + ''' The full procedural name indicates architecture, extended name, tile size, and layout. ''' + + opcode_class_name = OpcodeClassNames[self.tile_description.math_instruction.opcode_class] + + threadblock = "%dx%d_%dx%d" % ( + self.tile_description.threadblock_shape[0], + self.tile_description.threadblock_shape[1], + self.tile_description.threadblock_shape[2], + self.tile_description.stages + ) + + if self.stride_support == StrideSupport.Unity: + configuration_name = "cutlass_${opcode_class}_${extended_name}_${threadblock}_${layout}_unity_stride" + else: + configuration_name = "cutlass_${opcode_class}_${extended_name}_${threadblock}_${layout}" + + return SubstituteTemplate( + configuration_name, + { + 'opcode_class': opcode_class_name, + 'extended_name': self.extended_name(), + 'threadblock': threadblock, + 'layout': self.layout_name(), + } + ) + + # + def procedural_name(self): + ''' The full procedural name indicates architecture, extended name, tile size, and layout. ''' + return self.configuration_name() + +################################################################################################### +# +# Emits single instances of a CUTLASS device-wide operator +# +################################################################################################### + +class EmitConv2dInstance: + def __init__(self): + self.template = """ + // Conv2d${conv_kind_name} ${iterator_algorithm_name} kernel instance "${operation_name}" + using ${operation_name}_base = + typename cutlass::conv::kernel::DefaultConv2d${conv_kind_name}< + ${element_a}, + ${layout_a}, + ${element_b}, + ${layout_b}, + ${element_c}, + ${layout_c}, + ${element_accumulator}, + ${opcode_class}, + ${arch}, + cutlass::gemm::GemmShape<${threadblock_shape_m}, ${threadblock_shape_n}, ${threadblock_shape_k}>, + cutlass::gemm::GemmShape<${warp_shape_m}, ${warp_shape_n}, ${warp_shape_k} >, + cutlass::gemm::GemmShape<${instruction_shape_m}, ${instruction_shape_n}, ${instruction_shape_k}>, + ${epilogue_functor}< + ${element_c}, + ${epilogue_vector_length}, + ${element_accumulator}, + ${element_epilogue} + >, + ${swizzling_functor}, // cutlass::gemm::threadblock::GemmSplitKIdentityThreadblockSwizzle<>, + ${stages}, + ${math_operator}, + ${iterator_algorithm}, + ${stride_support} + >::Kernel; +""" + + + def emit(self, operation): + + warp_shape = [int(operation.tile_description.threadblock_shape[idx] / operation.tile_description.warp_count[idx]) for idx in range(3)] + + epilogue_vector_length = int(min(operation.C.alignment * DataTypeSize[operation.C.element], 128) / DataTypeSize[operation.C.element]) + + values = { + 'operation_name': operation.procedural_name(), + 'conv_kind': ConvKindTag[operation.conv_kind], + 'conv_kind_name': ConvKindNames[operation.conv_kind].capitalize(), + 'element_a': DataTypeTag[operation.A.element], + 'layout_a': LayoutTag[operation.A.layout], + 'element_b': DataTypeTag[operation.B.element], + 'layout_b': LayoutTag[operation.B.layout], + 'element_c': DataTypeTag[operation.C.element], + 'layout_c': LayoutTag[operation.C.layout], + 'element_accumulator': DataTypeTag[operation.accumulator_type()], + 'opcode_class': OpcodeClassTag[operation.tile_description.math_instruction.opcode_class], + 'arch': "cutlass::arch::Sm%d" % operation.arch, + 'threadblock_shape_m': str(operation.tile_description.threadblock_shape[0]), + 'threadblock_shape_n': str(operation.tile_description.threadblock_shape[1]), + 'threadblock_shape_k': str(operation.tile_description.threadblock_shape[2]), + 'warp_shape_m': str(warp_shape[0]), + 'warp_shape_n': str(warp_shape[1]), + 'warp_shape_k': str(warp_shape[2]), + 'instruction_shape_m': str(operation.tile_description.math_instruction.instruction_shape[0]), + 'instruction_shape_n': str(operation.tile_description.math_instruction.instruction_shape[1]), + 'instruction_shape_k': str(operation.tile_description.math_instruction.instruction_shape[2]), + 'epilogue_vector_length': str(epilogue_vector_length), + 'epilogue_functor': EpilogueFunctorTag[operation.epilogue_functor], + 'element_epilogue': str(DataTypeTag[operation.element_epilogue]), + 'swizzling_functor': SwizzlingFunctorTag[operation.swizzling_functor], + 'stages': str(operation.tile_description.stages), + 'iterator_algorithm': IteratorAlgorithmTag[operation.iterator_algorithm], + 'iterator_algorithm_name': IteratorAlgorithmNames[operation.iterator_algorithm].capitalize(), + 'stride_support': StrideSupportTag[operation.stride_support], + 'math_operator': 'cutlass::arch::OpMultiplyAddComplex' if operation.is_complex() else \ + MathOperationTag[operation.tile_description.math_instruction.math_operation] + } + + return SubstituteTemplate(self.template, values) + +################################################################################################### +# +# Generator functions for all layouts +# +################################################################################################### + +# +def GenerateConv2dTensorOp(manifest, tile_descriptions, min_cc, align = 128): + + for tile in tile_descriptions: + for conv_kind in [ConvKind.Fprop, ConvKind.Dgrad, ConvKind.Wgrad]: + + if conv_kind == ConvKind.Fprop or (tile.math_instruction.element_accumulator in [DataType.f16, DataType.f32]): + + # + output_types = [tile.math_instruction.element_a, tile.math_instruction.element_accumulator] \ + if DataTypeSize[tile.math_instruction.element_accumulator] == 32 \ + else [tile.math_instruction.element_accumulator,] + + for output_type in output_types: + A = TensorDescription(tile.math_instruction.element_a, LayoutType.TensorNHWC, int(align / DataTypeSize[tile.math_instruction.element_a])) + B = TensorDescription(tile.math_instruction.element_b, LayoutType.TensorNHWC, int(align / DataTypeSize[tile.math_instruction.element_b])) + C = TensorDescription(output_type, LayoutType.TensorNHWC, max(1, int(align / DataTypeSize[output_type]))) + + manifest.append(Conv2dOperation(conv_kind, min_cc, tile, A, B, C, tile.math_instruction.element_accumulator)) + +################################################################################################### +# +# Emitters functions for all targets +# +################################################################################################### + +class EmitConv2dConfigurationLibrary: + def __init__(self, operation_path, configuration_name): + self.configuration_name = configuration_name + self.configuration_path = os.path.join(operation_path, "%s.cu" % configuration_name) + + self.instance_emitter = EmitConv2dInstance() + + self.instance_template = """ +${operation_instance} + +// Derived class +struct ${operation_name} : + public ${operation_name}_base { }; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +""" + self.header_template = """ +/* + Generated by conv2d_operation.py - Do not edit. +*/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "cutlass/cutlass.h" +#include "cutlass/library/library.h" +#include "cutlass/library/manifest.h" + +#include "library_internal.h" +#include "conv2d_operation.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +""" + + self.configuration_header = """ + +namespace cutlass { +namespace library { + +// Initialize all instances +void initialize_${configuration_name}(Manifest &manifest) { + +""" + + self.configuration_instance = """ + using Operation_${operation_name} = cutlass::conv::device::ImplicitGemmConvolution< + ${operation_name}>; + + manifest.append(new cutlass::library::Conv2dOperation< + Operation_${operation_name}>( + "${operation_name}")); + +""" + + self.configuration_epilogue = """ +} +""" + self.epilogue_template = """ + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace library +} // namespace cutlass + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +""" + + # + def __enter__(self): + self.configuration_file = open(self.configuration_path, "w") + self.configuration_file.write(SubstituteTemplate(self.header_template, { + 'configuration_name': self.configuration_name + })) + self.operations = [] + return self + + # + def emit(self, operation): + self.operations.append(operation) + self.configuration_file.write(SubstituteTemplate(self.instance_template, { + 'configuration_name': self.configuration_name, + 'operation_name': operation.procedural_name(), + 'operation_instance': self.instance_emitter.emit(operation) + })) + + # + def __exit__(self, exception_type, exception_value, traceback): + + self.configuration_file.write(SubstituteTemplate(self.configuration_header, { + 'configuration_name': self.configuration_name + })) + + for operation in self.operations: + self.configuration_file.write(SubstituteTemplate(self.configuration_instance, { + 'configuration_name': self.configuration_name, + 'operation_name': operation.procedural_name() + })) + + self.configuration_file.write(self.configuration_epilogue) + self.configuration_file.write(self.epilogue_template) + self.configuration_file.close() + + +################################################################################################### +################################################################################################### + diff --git a/tools/library/scripts/conv3d_operation.py b/tools/library/scripts/conv3d_operation.py new file mode 100644 index 000000000..4ba31b039 --- /dev/null +++ b/tools/library/scripts/conv3d_operation.py @@ -0,0 +1,321 @@ +# +# \file generator.py +# +# \brief Generates the CUTLASS Library's instances +# +# + +import enum +import os.path +import shutil + +from library import * + +################################################################################################### + +# +class Conv3dOperation: + # + def __init__(self, conv_kind, iterator_algorithm, arch, tile_description, A, B, C, element_epilogue, \ + stride_support, epilogue_functor = EpilogueFunctor.LinearCombination, swizzling_functor = SwizzlingFunctor.Identity4): + + self.operation_kind = OperationKind.Conv3d + self.arch = arch + self.tile_description = tile_description + self.conv_kind = conv_kind + self.A = A + self.B = B + self.C = C + self.element_epilogue = element_epilogue + self.epilogue_functor = epilogue_functor + self.iterator_algorithm = iterator_algorithm + self.stride_support = stride_support + self.swizzling_functor = swizzling_functor + + # + def core_name(self): + ''' The basic operation kind is prefixed with a letter indicating the accumulation type. ''' + + intermediate_type = '' + + if self.tile_description.math_instruction.opcode_class == OpcodeClass.TensorOp: + inst_shape = "%d%d%d" % tuple(self.tile_description.math_instruction.instruction_shape) + if self.tile_description.math_instruction.element_a != self.A.element and \ + self.tile_description.math_instruction.element_a != self.tile_description.math_instruction.element_accumulator: + intermediate_type = DataTypeNames[self.tile_description.math_instruction.element_a] + else: + inst_shape = '' + + return "%s%s%s%s3d_%s" % (ShortDataTypeNames[self.tile_description.math_instruction.element_accumulator], \ + inst_shape, intermediate_type, ConvKindNames[self.conv_kind], IteratorAlgorithmNames[self.iterator_algorithm]) + + # + def extended_name(self): + ''' Append data types if they differ from compute type. ''' + if self.C.element != self.tile_description.math_instruction.element_accumulator and \ + self.A.element != self.tile_description.math_instruction.element_accumulator: + extended_name = "${element_c}_${core_name}_${element_a}" + elif self.C.element == self.tile_description.math_instruction.element_accumulator and \ + self.A.element != self.tile_description.math_instruction.element_accumulator: + extended_name = "${core_name}_${element_a}" + else: + extended_name = "${core_name}" + + extended_name = SubstituteTemplate(extended_name, { + 'element_a': DataTypeNames[self.A.element], + 'element_c': DataTypeNames[self.C.element], + 'core_name': self.core_name() + }) + + return extended_name + + # + def configuration_name(self): + ''' The full procedural name indicates architecture, extended name, tile size, and layout. ''' + + opcode_class_name = OpcodeClassNames[self.tile_description.math_instruction.opcode_class] + + threadblock = "%dx%d_%dx%d" % ( + self.tile_description.threadblock_shape[0], + self.tile_description.threadblock_shape[1], + self.tile_description.threadblock_shape[2], + self.tile_description.stages + ) + + if self.stride_support == StrideSupport.Unity: + configuration_name = "cutlass_${opcode_class}_${extended_name}_${threadblock}_unity_stride" + else: + configuration_name = "cutlass_${opcode_class}_${extended_name}_${threadblock}" + + return SubstituteTemplate( + configuration_name, + { + 'opcode_class': opcode_class_name, + 'extended_name': self.extended_name(), + 'threadblock': threadblock, + } + ) + + # + def procedural_name(self): + ''' The full procedural name indicates architecture, extended name, tile size, and layout. ''' + return self.configuration_name() + +################################################################################################### +# +# Emits single instances of a CUTLASS device-wide operator +# +################################################################################################### + +class EmitConv3dInstance: + def __init__(self): + self.template = """ + // Conv3d${conv_kind_name} ${iterator_algorithm_name} kernel instance "${operation_name}" + using ${operation_name}_base = + typename cutlass::conv::kernel::DefaultConv3d${conv_kind_name}< + ${element_a}, + cutlass::layout::TensorNDHWC, + ${element_b}, + cutlass::layout::TensorNDHWC, + ${element_c}, + cutlass::layout::TensorNDHWC, + ${element_accumulator}, + ${opcode_class}, + ${arch}, + cutlass::gemm::GemmShape<${threadblock_shape_m}, ${threadblock_shape_n}, ${threadblock_shape_k}>, + cutlass::gemm::GemmShape<${warp_shape_m}, ${warp_shape_n}, ${warp_shape_k} >, + cutlass::gemm::GemmShape<${instruction_shape_m}, ${instruction_shape_n}, ${instruction_shape_k}>, + ${epilogue_functor}< + ${element_c}, + ${epilogue_vector_length}, + ${element_accumulator}, + ${element_epilogue} + >, + ${swizzling_functor}, // cutlass::gemm::threadblock::GemmSplitKIdentityThreadblockSwizzle<>, + ${stages}, + cutlass::arch::OpMultiplyAdd, + ${iterator_algorithm}, + ${stride_support} + >::Kernel; +""" + + + def emit(self, operation): + + warp_shape = [int(operation.tile_description.threadblock_shape[idx] / operation.tile_description.warp_count[idx]) for idx in range(3)] + + epilogue_vector_length = int(min(operation.C.alignment * DataTypeSize[operation.C.element], 128) / DataTypeSize[operation.C.element]) + + values = { + 'operation_name': operation.procedural_name(), + 'conv_kind': ConvKindTag[operation.conv_kind], + 'conv_kind_name': ConvKindNames[operation.conv_kind].capitalize(), + 'element_a': DataTypeTag[operation.A.element], + 'layout_a': LayoutTag[operation.A.layout], + 'element_b': DataTypeTag[operation.B.element], + 'layout_b': LayoutTag[operation.B.layout], + 'element_c': DataTypeTag[operation.C.element], + 'layout_c': LayoutTag[operation.C.layout], + 'element_accumulator': DataTypeTag[operation.tile_description.math_instruction.element_accumulator], + 'opcode_class': OpcodeClassTag[operation.tile_description.math_instruction.opcode_class], + 'arch': "cutlass::arch::Sm%d" % operation.arch, + 'threadblock_shape_m': str(operation.tile_description.threadblock_shape[0]), + 'threadblock_shape_n': str(operation.tile_description.threadblock_shape[1]), + 'threadblock_shape_k': str(operation.tile_description.threadblock_shape[2]), + 'warp_shape_m': str(warp_shape[0]), + 'warp_shape_n': str(warp_shape[1]), + 'warp_shape_k': str(warp_shape[2]), + 'instruction_shape_m': str(operation.tile_description.math_instruction.instruction_shape[0]), + 'instruction_shape_n': str(operation.tile_description.math_instruction.instruction_shape[1]), + 'instruction_shape_k': str(operation.tile_description.math_instruction.instruction_shape[2]), + 'epilogue_vector_length': str(epilogue_vector_length), + 'epilogue_functor': EpilogueFunctorTag[operation.epilogue_functor], + 'element_epilogue': str(DataTypeTag[operation.element_epilogue]), + 'swizzling_functor': SwizzlingFunctorTag[operation.swizzling_functor], + 'stages': str(operation.tile_description.stages), + 'iterator_algorithm': IteratorAlgorithmTag[operation.iterator_algorithm], + 'iterator_algorithm_name': IteratorAlgorithmNames[operation.iterator_algorithm].capitalize(), + 'stride_support': StrideSupportTag[operation.stride_support] + } + + return SubstituteTemplate(self.template, values) + +################################################################################################### +# +# Generator functions for all layouts +# +################################################################################################### + +# +def GenerateConv3dTensorOp(manifest, tile_descriptions, min_cc, align = 128): + + for tile in tile_descriptions: + for conv_kind in [ConvKind.Fprop, ConvKind.Dgrad, ConvKind.Wgrad]: + + if conv_kind == ConvKind.Fprop or (tile.math_instruction.element_accumulator in [DataType.f16, DataType.f32]): + + # + output_types = [tile.math_instruction.element_a, tile.math_instruction.element_accumulator] \ + if DataTypeSize[tile.math_instruction.element_accumulator] == 32 \ + else [tile.math_instruction.element_accumulator,] + + for output_type in output_types: + A = TensorDescription(tile.math_instruction.element_a, LayoutType.TensorNDHWC, int(align / DataTypeSize[tile.math_instruction.element_a])) + B = TensorDescription(tile.math_instruction.element_b, LayoutType.TensorNDHWC, int(align / DataTypeSize[tile.math_instruction.element_b])) + C = TensorDescription(output_type, LayoutType.TensorNDHWC, max(1, int(align / DataTypeSize[output_type]))) + + manifest.append(Conv3dOperation(conv_kind, min_cc, tile, A, B, C, tile.math_instruction.element_accumulator)) + +################################################################################################### +# +# Emitters functions for all targets +# +################################################################################################### + +class EmitConv3dConfigurationLibrary: + def __init__(self, operation_path, configuration_name): + self.configuration_name = configuration_name + self.configuration_path = os.path.join(operation_path, "%s.cu" % configuration_name) + + self.instance_emitter = EmitConv3dInstance() + + self.instance_template = """ +${operation_instance} + +// Derived class +struct ${operation_name} : + public ${operation_name}_base { }; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +""" + self.header_template = """ +/* + Generated by conv3d_operation.py - Do not edit. +*/ + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "cutlass/cutlass.h" +#include "cutlass/library/library.h" +#include "cutlass/library/manifest.h" + +#include "library_internal.h" +#include "conv3d_operation.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +""" + + self.configuration_header = """ + +namespace cutlass { +namespace library { + +// Initialize all instances +void initialize_${configuration_name}(Manifest &manifest) { + +""" + + self.configuration_instance = """ + using Operation_${operation_name} = cutlass::conv::device::ImplicitGemmConvolution< + ${operation_name}>; + + manifest.append(new cutlass::library::Conv3dOperation< + Operation_${operation_name}>( + "${operation_name}")); + +""" + + self.configuration_epilogue = """ +} +""" + self.epilogue_template = """ + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace library +} // namespace cutlass + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +""" + + # + def __enter__(self): + self.configuration_file = open(self.configuration_path, "w") + self.configuration_file.write(SubstituteTemplate(self.header_template, { + 'configuration_name': self.configuration_name + })) + self.operations = [] + return self + + # + def emit(self, operation): + self.operations.append(operation) + self.configuration_file.write(SubstituteTemplate(self.instance_template, { + 'configuration_name': self.configuration_name, + 'operation_name': operation.procedural_name(), + 'operation_instance': self.instance_emitter.emit(operation) + })) + + # + def __exit__(self, exception_type, exception_value, traceback): + + self.configuration_file.write(SubstituteTemplate(self.configuration_header, { + 'configuration_name': self.configuration_name + })) + + for operation in self.operations: + self.configuration_file.write(SubstituteTemplate(self.configuration_instance, { + 'configuration_name': self.configuration_name, + 'operation_name': operation.procedural_name() + })) + + self.configuration_file.write(self.configuration_epilogue) + self.configuration_file.write(self.epilogue_template) + self.configuration_file.close() + + +################################################################################################### +################################################################################################### + diff --git a/tools/library/scripts/generator.py b/tools/library/scripts/generator.py index f21acaaf6..491997cb8 100644 --- a/tools/library/scripts/generator.py +++ b/tools/library/scripts/generator.py @@ -11,7 +11,6 @@ import argparse from library import * from manifest import * -from gemm_operation import * ################################################################################################### # @@ -118,10 +117,9 @@ def CreateGemmPlanarComplexOperator(manifest, layouts, tile_descriptions, data_t gemm_kinds = [GemmKind.PlanarComplex, GemmKind.PlanarComplexArray] - # by default, only generate the largest tile and largest alignment + # by default, planar complex gemm kernels are not generated if manifest.args.kernels == '': - tile_descriptions = [tile_descriptions[0],] - alignment_constraints = [alignment_constraints[0],] + return for gemm_kind in gemm_kinds: for layout in layouts: @@ -141,6 +139,103 @@ def CreateGemmPlanarComplexOperator(manifest, layouts, tile_descriptions, data_t return ########################################################################################################### +# ConvolutionOperator support variations +# ____________________________________________________________________ +# ConvolutionalOperator | Analytic | Optimized +# ____________________________________________________________________ +# | Fprop | (strided) | (strided) +# | Dgrad | (strided, unity*) | (unity) +# | Wgrad | (strided) | (strided) +# ____________________________________________________________________ +# +# Note : Operator marked (*) are supported but not generated to keep the instantiated kernel count low +########################################################################################################### +# Convolution for 2D operations +def CreateConv2dOperator(manifest, layout, tile_descriptions, data_type, alignment, \ + conv_kinds = [ConvKind.Fprop, ConvKind.Dgrad, ConvKind.Wgrad], epilogue_functor = EpilogueFunctor.LinearCombination): + + element_a, element_b, element_c, element_epilogue = data_type + + # one exceptional case + alignment_c = min(8, alignment) + + # iterator algorithm (analytic and optimized) + iterator_algorithms = [IteratorAlgorithm.Analytic, IteratorAlgorithm.Optimized] + + # by default, only generate the largest tile size + if manifest.args.kernels == '': + tile_descriptions = [tile_descriptions[0],] + + operations = [] + + for tile in tile_descriptions: + for conv_kind in conv_kinds: + for iterator_algorithm in iterator_algorithms: + A = TensorDescription(element_a, layout[0], alignment) + B = TensorDescription(element_b, layout[1], alignment) + C = TensorDescription(element_c, layout[2], alignment_c) + + # unity stride only for Optimized Dgrad + if (iterator_algorithm == IteratorAlgorithm.Optimized) and (conv_kind == ConvKind.Dgrad): + new_operation = Conv2dOperation(conv_kind, iterator_algorithm, tile.minimum_compute_capability, tile,\ + A, B, C, element_epilogue, StrideSupport.Unity, epilogue_functor) + + manifest.append(new_operation) + operations.append(new_operation) + + # strided dgrad is not supported by Optimized Dgrad + if (iterator_algorithm == IteratorAlgorithm.Optimized) and (conv_kind == ConvKind.Dgrad): + continue + + # strided support for Fprop (Analytic/Optimized), Dgrad (Analytic), and Wgrad (Analytic) + new_operation = Conv2dOperation(conv_kind, iterator_algorithm, tile.minimum_compute_capability, tile,\ + A, B, C, element_epilogue, StrideSupport.Strided, epilogue_functor) + + manifest.append(new_operation) + operations.append(new_operation) + + return operations + +# Convolution for 3D operations +def CreateConv3dOperator(manifest, layout, tile_descriptions, data_type, alignment, \ + conv_kinds = [ConvKind.Fprop, ConvKind.Dgrad, ConvKind.Wgrad], epilogue_functor = EpilogueFunctor.LinearCombination): + + element_a, element_b, element_c, element_epilogue = data_type + + # one exceptional case + alignment_c = min(8, alignment) + + # iterator algorithm (analytic and optimized) + iterator_algorithms = [IteratorAlgorithm.Analytic, IteratorAlgorithm.Optimized] + + # by default, only generate the largest tile size + if manifest.args.kernels == '': + tile_descriptions = [tile_descriptions[0],] + + operations = [] + + for tile in tile_descriptions: + for conv_kind in conv_kinds: + for iterator_algorithm in iterator_algorithms: + A = TensorDescription(element_a, layout, alignment) + B = TensorDescription(element_b, layout, alignment) + C = TensorDescription(element_c, layout, alignment_c) + + # optimized conv3d iterator algorithm is only for Wgrad + if (iterator_algorithm == IteratorAlgorithm.Optimized) \ + and ((conv_kind == ConvKind.Fprop) or (conv_kind == ConvKind.Dgrad)): + continue + + # strided support for Fprop (Analytic/Optimized), Dgrad (Analytic), and Wgrad (Analytic) + new_operation = Conv3dOperation(conv_kind, iterator_algorithm, tile.minimum_compute_capability, tile,\ + A, B, C, element_epilogue, StrideSupport.Strided, epilogue_functor) + + manifest.append(new_operation) + operations.append(new_operation) + + + return operations + ################################################################################################### ################################################################################################### @@ -191,11 +286,57 @@ def GenerateSM50_Simt(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type, alignment_constraints) + if math_inst.element_a == DataType.f32: + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1) +# + +# +def GenerateSM50_Simt_complex(manifest, args): + layouts = [ + (LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor), + (LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor), + (LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor), + (LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor), + ] + + math_instructions = [ + MathInstruction( \ + [1, 1, 1], \ + DataType.f32, DataType.f32, DataType.f32, \ + OpcodeClass.Simt, \ + MathOperation.multiply_add_complex), + ] + + min_cc = 50 + max_cc = 1024 + + alignment_constraints = [1,] + + for math_inst in math_instructions: + tile_descriptions = [ + TileDescription([128, 128, 8], 2, [4, 2, 1], math_inst, min_cc, max_cc), + ] + + data_type = [ + DataType.cf32, + DataType.cf32, + DataType.cf32, + DataType.cf32, + ] + + + CreateGemmOperator(manifest, layouts, tile_descriptions, \ + data_type, alignment_constraints) + + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1) # # def GenerateSM50(manifest, args): GenerateSM50_Simt(manifest, args) + GenerateSM50_Simt_complex(manifest, args) ################################################################################################### ################################################################################################### @@ -362,6 +503,9 @@ def GenerateSM70_TensorOp_884(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type, alignment_constraints) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 8) + # Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation) if math_inst.element_a != math_inst.element_accumulator: @@ -375,6 +519,8 @@ def GenerateSM70_TensorOp_884(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type_mixed, 8) + # def GenerateSM70_PlanarComplexTensorOp_884(manifest, args): @@ -504,50 +650,10 @@ def GenerateSM70_WmmaTensorOp_161616(manifest, args): # ################################################################################################## # -def GenerateSM70_Simt_complex(manifest, args): - math_instructions = [ - MathInstruction( \ - [1, 1, 1], \ - DataType.f32, DataType.f32, DataType.f32, \ - OpcodeClass.Simt, \ - MathOperation.multiply_add_complex), - ] - - min_cc = 70 - max_cc = 1024 - - alignment_constraints = [1,] - - for math_inst in math_instructions: - tile_descriptions = [ - TileDescription([128, 128, 8], 2, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 128, 32], 2, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 32], 2, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 64, 32], 2, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([64, 32, 16], 2, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([32, 64, 16], 2, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([32, 32, 16], 2, [2, 2, 1], math_inst, min_cc, max_cc), - ] - data_type = [ - DataType.cf32, - DataType.cf32, - DataType.cf32, - DataType.cf32 - ] - - complex_transforms = [ - (ComplexTransform.none, ComplexTransform.none), - (ComplexTransform.conj, ComplexTransform.none), - (ComplexTransform.none, ComplexTransform.conj), - (ComplexTransform.conj, ComplexTransform.conj) - ] - -# def GenerateSM70(manifest, args): GenerateSM70_TensorOp_884(manifest, args) GenerateSM70_PlanarComplexTensorOp_884(manifest, args) - GenerateSM70_Simt_complex(manifest, args) # To limit build size, WMMA GEMMs are disabled for now. # @@ -607,6 +713,9 @@ def GenerateSM75_TensorOp_1688(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type, alignment_constraints) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 8) + # Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation) if math_inst.element_a != math_inst.element_accumulator: @@ -620,6 +729,8 @@ def GenerateSM75_TensorOp_1688(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type_mixed, 8) + # # @@ -738,6 +849,10 @@ def GenerateSM75_TensorOp_8816_TN(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, + data_type, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + # Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation) if math_inst.element_a != math_inst.element_accumulator: @@ -753,6 +868,9 @@ def GenerateSM75_TensorOp_8816_TN(manifest, args): operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) + operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions, + data_type_mixed, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + for op in operations: if op.tile_description.threadblock_shape[1] >= 128: op.C.alignment = 16 @@ -794,6 +912,8 @@ def GenerateSM75_TensorOp_8816_Interleaved(manifest, args): TileDescription([256, 128, 64], 2, [4, 2, 1], math_inst, min_cc, max_cc), TileDescription([128, 256, 64], 2, [2, 4, 1], math_inst, min_cc, max_cc), TileDescription([128, 128, 64], 2, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([256, 64, 64], 2, [4, 1, 1], math_inst, min_cc, max_cc), + TileDescription([ 64, 256, 64], 2, [1, 4, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 64], 2, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([128, 64, 64], 2, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 64], 2, [2, 2, 1], math_inst, min_cc, max_cc), @@ -809,9 +929,13 @@ def GenerateSM75_TensorOp_8816_Interleaved(manifest, args): operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) +# conv_layout = (LayoutType.TensorNC32HW32, LayoutType.TensorC32RSK32, LayoutType.TensorNC32HW32) +# +# operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions, +# data_type_mixed, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + for op in operations: op.C.alignment = 8 - # # @@ -862,6 +986,10 @@ def GenerateSM75_TensorOp_8832_TN(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, + data_type, 32, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + # Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation) if math_inst.element_a != math_inst.element_accumulator: @@ -877,6 +1005,9 @@ def GenerateSM75_TensorOp_8832_TN(manifest, args): operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) + operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions, + data_type_mixed, 32, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + for op in operations: if op.tile_description.threadblock_shape[1] >= 128: op.C.alignment = 8 @@ -920,9 +1051,9 @@ def GenerateSM75_TensorOp_8832_Interleaved(manifest, args): TileDescription([256, 128, 128], 2, [4, 2, 1], math_inst, min_cc, max_cc), TileDescription([128, 256, 128], 2, [2, 4, 1], math_inst, min_cc, max_cc), TileDescription([128, 128, 128], 2, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([256, 64, 128], 2, [4, 1, 1], math_inst, min_cc, max_cc), + TileDescription([ 64, 256, 128], 2, [1, 4, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 128], 2, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 128], 2, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 64, 128], 2, [2, 2, 1], math_inst, min_cc, max_cc), ] # Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation) @@ -938,9 +1069,13 @@ def GenerateSM75_TensorOp_8832_Interleaved(manifest, args): operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) +# conv_layout = (LayoutType.TensorNC64HW64, LayoutType.TensorC64RSK64, LayoutType.TensorNC64HW64) +# +# operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions, +# data_type_mixed, 32, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + for op in operations: op.C.alignment = 16 - # # @@ -1074,6 +1209,8 @@ def GenerateSM75_Simt_complex(manifest, args): (ComplexTransform.conj, ComplexTransform.conj) ] + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1) # def GenerateSM75(manifest, args): @@ -1124,6 +1261,7 @@ def GenerateSM80_TensorOp_16816(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [8, 4, 2] @@ -1137,10 +1275,10 @@ def GenerateSM80_TensorOp_16816(manifest, args): TileDescription([128, 64, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 32], 10, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 64], 4, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 256, 64], 4, [1, 4, 1], math_inst, min_cc, max_cc), + TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 64, 64], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 256, 64], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([128, 128, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([128, 64, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc), @@ -1157,6 +1295,10 @@ def GenerateSM80_TensorOp_16816(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type, alignment_constraints) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 8) + CreateConv3dOperator(manifest, LayoutType.TensorNDHWC, tile_descriptions, data_type, 8) + # Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation) if math_inst.element_a != math_inst.element_accumulator: @@ -1170,6 +1312,8 @@ def GenerateSM80_TensorOp_16816(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type_mixed, 8) + CreateConv3dOperator(manifest, LayoutType.TensorNDHWC, tile_descriptions, data_type_mixed, 8) # # @@ -1205,22 +1349,23 @@ def GenerateSM80_SparseTensorOp_16832(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [8, 4, 2] for math_inst in math_instructions: tile_descriptions = [ - TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc), + TileDescription([ 64, 128, 64], 6, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([128, 128, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([256, 64, 64], 3, [4, 1, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 256, 64], 4, [1, 4, 1], math_inst, min_cc, max_cc), TileDescription([128, 64, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 128, 64], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([128, 128, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([ 64, 128, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc), ] @@ -1348,6 +1493,7 @@ def GenerateSM80_TensorOp_16832_TN(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [16,] @@ -1361,10 +1507,10 @@ def GenerateSM80_TensorOp_16832_TN(manifest, args): TileDescription([128, 64, 64], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 64], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 64], 10, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 128], 4, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc), + TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 64, 128], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([128, 128, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([128, 64, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc), @@ -1382,6 +1528,13 @@ def GenerateSM80_TensorOp_16832_TN(manifest, args): operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, + data_type, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + + operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions, + data_type_mixed, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + for op in operations: if op.tile_description.threadblock_shape[1] >= 128: op.C.alignment = 16 @@ -1409,21 +1562,22 @@ def GenerateSM80_SparseTensorOp_16864_TN(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [16,] tile_descriptions = [ - TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc), TileDescription([128, 64, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 128, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 128, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc), + TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 128, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 64, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([ 64, 64, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc), ] @@ -1489,10 +1643,14 @@ def GenerateSM80_TensorOp_16832_Interleaved(manifest, args): operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) - + +# conv_layout = (LayoutType.TensorNC32HW32, LayoutType.TensorC32RSK32, LayoutType.TensorNC32HW32) +# +# operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions, +# data_type_mixed, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + for op in operations: op.C.alignment = 8 - # # @@ -1520,6 +1678,7 @@ def GenerateSM80_TensorOp_16864_TN(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [32,] @@ -1533,14 +1692,14 @@ def GenerateSM80_TensorOp_16864_TN(manifest, args): TileDescription([128, 64, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 128], 10, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 256], 4, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 256, 256], 4, [1, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 64, 256], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 256, 256], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 128, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([128, 64, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 64, 256], 5, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([ 64, 64, 256], 5, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), ] data_type = [math_inst.element_a, math_inst.element_b, math_inst.element_accumulator, DataType.s32] @@ -1582,20 +1741,21 @@ def GenerateSM80_SparseTensorOp_168128_TN(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [32,] tile_descriptions = [ - TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 256], 3, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 256, 256], 4, [1, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 128, 256], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 512], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 512], 4, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([256, 64, 256], 3, [4, 1, 1], math_inst, min_cc, max_cc), + TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 256, 256], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 64, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 128, 256], 6, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 128, 512], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 64, 512], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([ 64, 128, 512], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 512], 3, [2, 2, 1], math_inst, min_cc, max_cc), ] @@ -1655,9 +1815,7 @@ def GenerateSM80_TensorOp_16864_Interleaved(manifest, args): TileDescription([256, 64, 128], 4, [4, 1, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc), TileDescription([128, 128, 128], 5, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 64, 128], 10, [2, 2, 1], math_inst, min_cc, max_cc), ] data_type_mixed = [math_inst.element_a, math_inst.element_b, math_inst.element_a, DataType.f32] @@ -1666,7 +1824,12 @@ def GenerateSM80_TensorOp_16864_Interleaved(manifest, args): operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp) - + +# conv_layout = (LayoutType.TensorNC64HW64, LayoutType.TensorC64RSK64, LayoutType.TensorNC64HW64) +# +# operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions, +# data_type_mixed, 32, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp) + for op in operations: op.C.alignment = 16 # @@ -1744,6 +1907,7 @@ def GenerateSM80_TensorOp_1688(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [4, 2, 1] @@ -1757,11 +1921,11 @@ def GenerateSM80_TensorOp_1688(manifest, args): TileDescription([128, 64, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 16], 10, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([128, 64, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([64, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 32], 5, [2, 2, 1], math_inst, min_cc, max_cc), @@ -1787,6 +1951,10 @@ def GenerateSM80_TensorOp_1688(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type_mixed, alignment_constraints) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 4) + + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type_mixed, 4) # # @@ -1822,6 +1990,7 @@ def GenerateSM80_TensorOp_1688_fast_math(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [4, 2, 1] @@ -1835,11 +2004,11 @@ def GenerateSM80_TensorOp_1688_fast_math(manifest, args): TileDescription([128, 64, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 16], 10, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([128, 64, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 32], 5, [2, 2, 1], math_inst, min_cc, max_cc), @@ -1850,6 +2019,8 @@ def GenerateSM80_TensorOp_1688_fast_math(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type, alignment_constraints) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 4) # # @@ -1875,22 +2046,23 @@ def GenerateSM80_SparseTensorOp_16816_fast_math(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [4, 2, 1] for math_inst in math_instructions: tile_descriptions = [ - TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([128, 64, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([128, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([256, 64, 32], 3, [4, 1, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 128, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 128, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc), - TileDescription([256, 64, 64], 3, [4, 1, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([128, 128, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([256, 64, 64], 3, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 64, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([ 64, 128, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([ 64, 64, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc), ] @@ -1971,13 +2143,14 @@ def GenerateSM80_TensorOp_884(manifest, args): min_cc = 80 max_cc = 1024 + max_cc_smem_limited = 80 alignment_constraints = [1,] tile_descriptions = [ - TileDescription([128, 128, 16], 3, [4, 2, 1], math_inst, min_cc, max_cc), - TileDescription([64, 128, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc), - TileDescription([128, 64, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([128, 128, 16], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([64, 128, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), + TileDescription([128, 64, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited), TileDescription([64, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([64, 32, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([32, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc), @@ -2090,7 +2263,7 @@ def GenerateSM80_TensorOp_884_complex_gaussian(manifest, args): ################################################################################################### # -def GenerateSM80_Simt(manifest, args): +def GenerateSM80_Simt_f32(manifest, args): layouts = [ (LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor), (LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor), @@ -2136,8 +2309,55 @@ def GenerateSM80_Simt(manifest, args): CreateGemmOperator(manifest, layouts, tile_descriptions, \ data_type, alignment_constraints) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1) # + +# +def GenerateSM80_Simt_f64(manifest, args): + layouts = [ + (LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor), + (LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor), + (LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor), + (LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor), + ] + + math_instructions = [ + MathInstruction( \ + [1, 1, 1], \ + DataType.f64, DataType.f64, DataType.f64, \ + OpcodeClass.Simt, \ + MathOperation.multiply_add), + ] + + min_cc = 80 + max_cc = 1024 + + alignment_constraints = [1,] + + for math_inst in math_instructions: + tile_descriptions = [ + TileDescription([128, 128, 8], 3, [4, 2, 1], math_inst, min_cc, max_cc), + TileDescription([128, 64, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([ 64, 128, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc), + TileDescription([ 64, 64, 8], 5, [2, 1, 1], math_inst, min_cc, max_cc), + TileDescription([128, 32, 8], 5, [2, 1, 1], math_inst, min_cc, max_cc), + TileDescription([ 32, 128, 8], 5, [1, 2, 1], math_inst, min_cc, max_cc), + ] + + data_type = [ + math_inst.element_a, + math_inst.element_b, + math_inst.element_accumulator, + math_inst.element_accumulator, + ] + + CreateGemmOperator(manifest, layouts, tile_descriptions, \ + data_type, alignment_constraints) +# + + ################################################################################################## # def GenerateSM80_Simt_complex(manifest, args): @@ -2154,7 +2374,29 @@ def GenerateSM80_Simt_complex(manifest, args): alignment_constraints = [1,] + data_type = [ + DataType.cf32, + DataType.cf32, + DataType.cf32, + DataType.cf32 + ] + + layouts = [ + (LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor), + (LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor), + (LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor), + (LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor), + ] + + complex_transforms = [ + (ComplexTransform.none, ComplexTransform.none), + (ComplexTransform.conj, ComplexTransform.none), + (ComplexTransform.none, ComplexTransform.conj), + (ComplexTransform.conj, ComplexTransform.conj) + ] + for math_inst in math_instructions: + tile_descriptions = [ TileDescription([128, 128, 8], 5, [4, 2, 1], math_inst, min_cc, max_cc), TileDescription([128, 128, 8], 4, [4, 2, 1], math_inst, min_cc, max_cc), @@ -2165,20 +2407,11 @@ def GenerateSM80_Simt_complex(manifest, args): TileDescription([32, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc), TileDescription([32, 32, 16], 5, [2, 2, 1], math_inst, min_cc, max_cc), ] - data_type = [ - DataType.cf32, - DataType.cf32, - DataType.cf32, - DataType.cf32 - ] - complex_transforms = [ - (ComplexTransform.none, ComplexTransform.none), - (ComplexTransform.conj, ComplexTransform.none), - (ComplexTransform.none, ComplexTransform.conj), - (ComplexTransform.conj, ComplexTransform.conj) - ] + CreateGemmOperator(manifest, layouts, tile_descriptions, data_type, alignment_constraints, complex_transforms) + conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC) + CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1) # ################################################################################################### @@ -2202,7 +2435,8 @@ def GenerateSM80(manifest, args): GenerateSM80_SparseTensorOp_168128_TN(manifest, args) GenerateSM80_TensorOp_16864_Interleaved(manifest, args) GenerateSM80_TensorOp_168256(manifest, args) - GenerateSM80_Simt(manifest, args) + GenerateSM80_Simt_f32(manifest, args) + GenerateSM80_Simt_f64(manifest, args) GenerateSM80_Simt_complex(manifest, args) ################################################################################################### diff --git a/tools/library/scripts/library.py b/tools/library/scripts/library.py index 2bb062da9..b9538cdbc 100644 --- a/tools/library/scripts/library.py +++ b/tools/library/scripts/library.py @@ -71,6 +71,7 @@ class DataType(enum.Enum): cu16 = enum_auto() cu32 = enum_auto() cu64 = enum_auto() + invalid = enum_auto() # ShortDataTypeNames = { @@ -260,6 +261,8 @@ MathOperationTag = { class LayoutType(enum.Enum): ColumnMajor = enum_auto() RowMajor = enum_auto() + ColumnMajorInterleaved2 = enum_auto() + RowMajorInterleaved2 = enum_auto() ColumnMajorInterleaved32 = enum_auto() RowMajorInterleaved32 = enum_auto() ColumnMajorInterleaved64 = enum_auto() @@ -268,13 +271,17 @@ class LayoutType(enum.Enum): TensorNDHWC = enum_auto() TensorNCHW = enum_auto() TensorNGHWC = enum_auto() - TensorNCxHW32 = enum_auto() - TensorNCxHW64 = enum_auto() + TensorNC32HW32 = enum_auto() + TensorNC64HW64 = enum_auto() + TensorC32RSK32 = enum_auto() + TensorC64RSK64 = enum_auto() # LayoutTag = { LayoutType.ColumnMajor: 'cutlass::layout::ColumnMajor', LayoutType.RowMajor: 'cutlass::layout::RowMajor', + LayoutType.ColumnMajorInterleaved2: 'cutlass::layout::ColumnMajorInterleaved<2>', + LayoutType.RowMajorInterleaved2: 'cutlass::layout::RowMajorInterleaved<2>', LayoutType.ColumnMajorInterleaved32: 'cutlass::layout::ColumnMajorInterleaved<32>', LayoutType.RowMajorInterleaved32: 'cutlass::layout::RowMajorInterleaved<32>', LayoutType.ColumnMajorInterleaved64: 'cutlass::layout::ColumnMajorInterleaved<64>', @@ -283,14 +290,18 @@ LayoutTag = { LayoutType.TensorNDHWC: 'cutlass::layout::TensorNDHWC', LayoutType.TensorNCHW: 'cutlass::layout::TensorNCHW', LayoutType.TensorNGHWC: 'cutlass::layout::TensorNGHWC', - LayoutType.TensorNCxHW32: 'cutlass::layout::TensorNCxHW32', - LayoutType.TensorNCxHW64: 'cutlass::layout::TensorNCxHW64' + LayoutType.TensorNC32HW32: 'cutlass::layout::TensorNCxHWx<32>', + LayoutType.TensorC32RSK32: 'cutlass::layout::TensorCxRSKx<32>', + LayoutType.TensorNC64HW64: 'cutlass::layout::TensorNCxHWx<64>', + LayoutType.TensorC64RSK64: 'cutlass::layout::TensorCxRSKx<64>', } # TransposedLayout = { LayoutType.ColumnMajor: LayoutType.RowMajor, LayoutType.RowMajor: LayoutType.ColumnMajor, + LayoutType.ColumnMajorInterleaved2: LayoutType.RowMajorInterleaved2, + LayoutType.RowMajorInterleaved2: LayoutType.ColumnMajorInterleaved2, LayoutType.ColumnMajorInterleaved32: LayoutType.RowMajorInterleaved32, LayoutType.RowMajorInterleaved32: LayoutType.ColumnMajorInterleaved32, LayoutType.ColumnMajorInterleaved64: LayoutType.RowMajorInterleaved64, @@ -301,17 +312,21 @@ TransposedLayout = { # ShortLayoutTypeNames = { LayoutType.ColumnMajor: 'n', + LayoutType.ColumnMajorInterleaved32: 'n2', LayoutType.ColumnMajorInterleaved32: 'n32', LayoutType.ColumnMajorInterleaved64: 'n64', LayoutType.RowMajor: 't', + LayoutType.RowMajorInterleaved2: 't2', LayoutType.RowMajorInterleaved32: 't32', LayoutType.RowMajorInterleaved64: 't64', LayoutType.TensorNHWC: 'nhwc', LayoutType.TensorNDHWC: 'ndhwc', LayoutType.TensorNCHW: 'nchw', LayoutType.TensorNGHWC: 'nghwc', - LayoutType.TensorNCxHW32: 'ncxhw32', - LayoutType.TensorNCxHW64: 'ncxhw64' + LayoutType.TensorNC32HW32: 'nc32hw32', + LayoutType.TensorNC64HW64: 'nc64hw64', + LayoutType.TensorC32RSK32: 'c32rsk32', + LayoutType.TensorC64RSK64: 'c64rsk64' } # @@ -346,9 +361,14 @@ OpcodeClassTag = { # class OperationKind(enum.Enum): Gemm = enum_auto() + Conv2d = enum_auto() + Conv3d = enum_auto() + # OperationKindNames = { OperationKind.Gemm: 'gemm' + , OperationKind.Conv2d: 'conv2d' + , OperationKind.Conv3d: 'conv3d' } # @@ -424,6 +444,61 @@ SwizzlingFunctorTag = { SwizzlingFunctor.Identity4: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<4>', SwizzlingFunctor.Identity8: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<8>', } + +################################################################################################### + +# +class ConvKind(enum.Enum): + Fprop = enum_auto() + Dgrad = enum_auto() + Wgrad = enum_auto() + +# +ConvKindTag = { + ConvKind.Fprop: 'cutlass::conv::Operator::kFprop', + ConvKind.Dgrad: 'cutlass::conv::Operator::kDgrad', + ConvKind.Wgrad: 'cutlass::conv::Operator::kWgrad' +} + +ConvKindNames = { + ConvKind.Fprop: 'fprop', + ConvKind.Dgrad: 'dgrad', + ConvKind.Wgrad: 'wgrad', +} + +# +class IteratorAlgorithm(enum.Enum): + Analytic = enum_auto() + Optimized = enum_auto() + +# +IteratorAlgorithmTag = { + IteratorAlgorithm.Analytic: 'cutlass::conv::IteratorAlgorithm::kAnalytic', + IteratorAlgorithm.Optimized: 'cutlass::conv::IteratorAlgorithm::kOptimized', +} + +IteratorAlgorithmNames = { + IteratorAlgorithm.Analytic: 'analytic', + IteratorAlgorithm.Optimized: 'optimized', +} + +# +class StrideSupport(enum.Enum): + Strided = enum_auto() + Unity = enum_auto() + +# +StrideSupportTag = { + StrideSupport.Strided: 'cutlass::conv::StrideSupport::kStrided', + StrideSupport.Unity: 'cutlass::conv::StrideSupport::kUnity', +} + +StrideSupportNames = { + StrideSupport.Strided: '', + StrideSupport.Unity: 'unity_stride', +} + + ################################################################################################### # diff --git a/tools/library/scripts/manifest.py b/tools/library/scripts/manifest.py index 2f0aa24ec..409ec09a2 100644 --- a/tools/library/scripts/manifest.py +++ b/tools/library/scripts/manifest.py @@ -10,6 +10,9 @@ import shutil from library import * from gemm_operation import * +from conv2d_operation import * +from conv3d_operation import * + ################################################################################################### class EmitOperationKindLibrary: @@ -20,6 +23,8 @@ class EmitOperationKindLibrary: self.emitters = { OperationKind.Gemm: EmitGemmConfigurationLibrary + , OperationKind.Conv2d: EmitConv2dConfigurationLibrary + , OperationKind.Conv3d: EmitConv3dConfigurationLibrary } self.configurations = []; @@ -112,7 +117,10 @@ class Manifest: def __init__(self, args): self.operations = {} self.args = args - self.compute_capabilities = [int(x) for x in args.architectures.split(';')] + + architectures = args.architectures.split(';') if len(args.architectures) else ['50',] + self.compute_capabilities = [int(x) for x in architectures] + self.selected_kernels = [] if args.operations == 'all': @@ -121,6 +129,8 @@ class Manifest: operations_list = [ OperationKind.Gemm + , OperationKind.Conv2d + , OperationKind.Conv3d ] self.operations_enabled = [x for x in operations_list if OperationKindNames[x] in args.operations.split(',')] diff --git a/tools/library/src/conv2d_operation.h b/tools/library/src/conv2d_operation.h new file mode 100644 index 000000000..5e8f887fd --- /dev/null +++ b/tools/library/src/conv2d_operation.h @@ -0,0 +1,380 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Defines operations for all CONV operation kinds in CUTLASS Library. +*/ + +#pragma once +#include +#include "cutlass/cutlass.h" +#include "cutlass/conv/kernel/default_conv2d_fprop.h" +#include "cutlass/conv/kernel/default_conv2d_dgrad.h" +#include "cutlass/conv/kernel/default_conv2d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "cutlass/library/library.h" +#include "library_internal.h" +#include "cutlass/util/host_tensor.h" + +#include "cutlass/util/reference/host/convolution.h" +#include "cutlass/util/reference/host/tensor_compare.h" +#include "cutlass/core_io.h" +/////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace library { + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class Conv2dOperationBase : public Operation { +public: + + using Operator = Operator_; + + using ElementA = typename Operator::ElementA; + using LayoutA = typename Operator::LayoutA; + using ElementB = typename Operator::ElementB; + using LayoutB = typename Operator::LayoutB; + using ElementC = typename Operator::ElementC; + using LayoutC = typename Operator::LayoutC; + using ElementAccumulator = typename Operator::ElementAccumulator; + using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute; + static cutlass::conv::IteratorAlgorithm const kIteratorAlgorithm = Operator::kIteratorAlgorithm; + static cutlass::conv::Operator const kConvolutionalOperator = Operator::kConvolutionalOperator; + + using OperatorArguments = typename Operator::Arguments; + +protected: + + /// + ConvDescription description_; + +public: + + /// Constructor + Conv2dOperationBase(char const *name = "unknown_conv2d") { + + description_.name = name; + description_.provider = Provider::kCUTLASS; + description_.kind = OperationKind::kConv2d; + description_.conv_dim = Operator::kConvDim; + + description_.iterator_algorithm = IteratorAlgorithmMap::kId; + + description_.tile_description.threadblock_shape = make_Coord( + Operator::ThreadblockShape::kM, + Operator::ThreadblockShape::kN, + Operator::ThreadblockShape::kK); + + description_.tile_description.threadblock_stages = Operator::kStages; + + description_.tile_description.warp_count = make_Coord( + Operator::ImplicitGemmKernel::WarpCount::kM, + Operator::ImplicitGemmKernel::WarpCount::kN, + Operator::ImplicitGemmKernel::WarpCount::kK); + + description_.tile_description.math_instruction.instruction_shape = make_Coord( + Operator::InstructionShape::kM, + Operator::InstructionShape::kN, + Operator::InstructionShape::kK); + + description_.tile_description.math_instruction.element_accumulator = + NumericTypeMap::kId; + + description_.tile_description.math_instruction.opcode_class = + OpcodeClassMap::kId; + + description_.tile_description.math_instruction.math_operation = + MathOperationMap::kId; + + description_.tile_description.minimum_compute_capability = + ArchMap::kMin; + + description_.tile_description.maximum_compute_capability = + ArchMap::kMax; + + description_.A = make_TensorDescription(); + description_.B = make_TensorDescription(); + description_.C = make_TensorDescription(); + description_.element_epilogue = NumericTypeMap::kId; + + // TODO: Add split k mode Serial and parallel to convolutions + // description_.split_k_mode = Operator::kSplitK ? SplitKMode::kSerial : SplitKMode::kNone; + + } + + /// Returns the description of the GEMM operation + virtual OperationDescription const & description() const { + return description_; + } +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Conv2d library operation class for cutlass profiler +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class Conv2dOperation : public Conv2dOperationBase { +public: + + using Operator = Operator_; + + using ElementA = typename Operator::ElementA; + using LayoutA = typename Operator::LayoutA; + using ElementB = typename Operator::ElementB; + using LayoutB = typename Operator::LayoutB; + using ElementC = typename Operator::ElementC; + using LayoutC = typename Operator::LayoutC; + using ElementAccumulator = typename Operator::ElementAccumulator; + using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute; + static cutlass::conv::Operator const kConvolutionalOperator = Operator::kConvolutionalOperator; + + using OperatorArguments = typename Operator::Arguments; + +public: + /// Constructor + Conv2dOperation(char const *name = "unknown_conv2d_fprop") : Conv2dOperationBase(name) { + this->description_.conv_kind = ConvKindMap::kId; + } + +protected: + + /// Constructs the arguments structure given the configuration and arguments + static Status construct_arguments_( + OperatorArguments &operator_args, + Conv2dConfiguration const *configuration) { + + + operator_args.problem_size = configuration->problem_size; + + operator_args.ref_A = + { + nullptr, + LayoutA::packed(implicit_gemm_tensor_a_extent(kConvolutionalOperator, configuration->problem_size)) + }; + + operator_args.ref_B = + { + nullptr, + LayoutB::packed(implicit_gemm_tensor_b_extent(kConvolutionalOperator, configuration->problem_size)) + }; + + operator_args.ref_C = + { + nullptr, + LayoutC::packed(implicit_gemm_tensor_c_extent(kConvolutionalOperator, configuration->problem_size)) + }; + + operator_args.ref_D = + { + nullptr, + LayoutC::packed(implicit_gemm_tensor_c_extent(kConvolutionalOperator, configuration->problem_size)) + }; + + operator_args.split_k_mode = configuration->split_k_mode; + + return Status::kSuccess; + } + + /// Constructs the arguments structure given the configuration and arguments + static Status update_arguments_( + OperatorArguments &operator_args, + ConvArguments const *arguments) { + + if (arguments->pointer_mode == ScalarPointerMode::kHost) { + typename Operator::EpilogueOutputOp::Params params( + *static_cast(arguments->alpha), + *static_cast(arguments->beta) + ); + operator_args.output_op = params; + } + else if (arguments->pointer_mode == ScalarPointerMode::kDevice){ + typename Operator::EpilogueOutputOp::Params params( + static_cast(arguments->alpha), + static_cast(arguments->beta) + ); + operator_args.output_op = params; + } + else { + return Status::kErrorInvalidProblem; + } + + operator_args.ref_A.reset(static_cast(const_cast(arguments->A))); + operator_args.ref_B.reset(static_cast(const_cast(arguments->B))); + operator_args.ref_C.reset(static_cast(const_cast(arguments->C))); + operator_args.ref_D.reset(static_cast(const_cast(arguments->D))); + + return Status::kSuccess; + } + +public: + + /// Returns success if the operation can proceed + virtual Status can_implement( + void const *configuration_ptr, + void const *arguments_ptr) const { + + Conv2dConfiguration const *configuration = + static_cast(configuration_ptr); + + ConvArguments const *arguments = + static_cast(arguments_ptr); + + OperatorArguments args; + + Status status = construct_arguments_(args, configuration); + + if (status != Status::kSuccess) { + return status; + } + + status = update_arguments_(args, arguments); + + if (status != Status::kSuccess) { + return status; + } + + return Operator::can_implement(args); + + } + + /// Gets the host-side workspace + virtual uint64_t get_host_workspace_size( + void const *configuration) const { + + return sizeof(Operator); + } + + /// Gets the device-side workspace + virtual uint64_t get_device_workspace_size( + void const *configuration_ptr) const { + + OperatorArguments args; + + Status status = construct_arguments_( + args, + static_cast(configuration_ptr)); + + if (status != Status::kSuccess) { + return 0; + } + + return Operator::get_workspace_size(args); + } + + /// Initializes the workspace + virtual Status initialize( + void const *configuration_ptr, + void *host_workspace, + void *device_workspace, + cudaStream_t stream = nullptr) const { + + OperatorArguments args; + + Status status = construct_arguments_( + args, + static_cast(configuration_ptr)); + + if (status != Status::kSuccess) { + return status; + } + + Operator *op = new (host_workspace) Operator; + //std::cout << "initialize library::Conv2dOperation" << std::endl; + //print_operator_args(args); + return op->initialize(args, device_workspace, stream); + + } + + /// Runs the kernel + virtual Status run( + void const *arguments_ptr, + void *host_workspace, + void *device_workspace = nullptr, + cudaStream_t stream = nullptr) const { + + OperatorArguments args; + + Status status = update_arguments_( + args, + static_cast(arguments_ptr)); + + if (status != Status::kSuccess) { + return status; + } + + Operator *op = static_cast(host_workspace); + + status = op->update(args, device_workspace); + + if (status != Status::kSuccess) { + return status; + } + //std::cout << "run library::Conv2dOperation" << std::endl; + //print_operator_args(args); + return op->run(stream); + } + + /// Call print_operator_args from the Conv2dOperation::initialize() + // to dump arguments passed on to cutlass operator for debugging + void print_operator_args(OperatorArguments &operator_args) const { + std::cout << "Conv2dOperation::OperatorArguments" << std::endl + << " problem_size:" << std::endl + << operator_args.problem_size << std::endl + << " split_k_mode: " + << (operator_args.split_k_mode == cutlass::conv::SplitKMode::kSerial ? "serial" : "parallel") << std::endl + << " epilouge (alpha, beta): " + << operator_args.output_op.alpha << ", " + << operator_args.output_op.beta << std::endl + << " ref_A (ptr, {stride}): " + << operator_args.ref_A.data() << ", {" + << operator_args.ref_A.stride(0) << ", " + << operator_args.ref_A.stride(1) << ", " + << operator_args.ref_A.stride(2) << "}" << std::endl + << " ref_B (ptr, {stride}): " + << operator_args.ref_B.data() << ", {" + << operator_args.ref_B.stride(0) << ", " + << operator_args.ref_B.stride(1) << ", " + << operator_args.ref_B.stride(2) << "}" << std::endl + << " ref_C (ptr, {stride}): " + << operator_args.ref_C.data() << ", {" + << operator_args.ref_C.stride(0) << ", " + << operator_args.ref_C.stride(1) << ", " + << operator_args.ref_C.stride(2) << "}" << std::endl + << " ref_D (ptr, {stride}): " + << operator_args.ref_D.data() << ", {" + << operator_args.ref_D.stride(0) << ", " + << operator_args.ref_D.stride(1) << ", " + << operator_args.ref_D.stride(2) << "}" << std::endl; + } +}; + +} // namespace library +} // namespace cutlass + +/////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/library/src/conv3d_operation.h b/tools/library/src/conv3d_operation.h new file mode 100644 index 000000000..32ad03632 --- /dev/null +++ b/tools/library/src/conv3d_operation.h @@ -0,0 +1,378 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Defines operations for all CONV operation kinds in CUTLASS Library. +*/ + +#pragma once +#include +#include "cutlass/cutlass.h" +#include "cutlass/conv/kernel/default_conv3d_fprop.h" +#include "cutlass/conv/kernel/default_conv3d_dgrad.h" +#include "cutlass/conv/kernel/default_conv3d_wgrad.h" +#include "cutlass/conv/device/implicit_gemm_convolution.h" + +#include "cutlass/library/library.h" +#include "library_internal.h" +#include "cutlass/util/host_tensor.h" + +#include "cutlass/util/reference/host/convolution.h" +#include "cutlass/util/reference/host/tensor_compare.h" +#include "cutlass/core_io.h" +/////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace library { + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class Conv3dOperationBase : public Operation { +public: + + using Operator = Operator_; + + using ElementA = typename Operator::ElementA; + using LayoutA = typename Operator::LayoutA; + using ElementB = typename Operator::ElementB; + using LayoutB = typename Operator::LayoutB; + using ElementC = typename Operator::ElementC; + using LayoutC = typename Operator::LayoutC; + using ElementAccumulator = typename Operator::ElementAccumulator; + using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute; + static cutlass::conv::IteratorAlgorithm const kIteratorAlgorithm = Operator::kIteratorAlgorithm; + static cutlass::conv::Operator const kConvolutionalOperator = Operator::kConvolutionalOperator; + + using OperatorArguments = typename Operator::Arguments; + +protected: + + /// + ConvDescription description_; + +public: + + /// Constructor + Conv3dOperationBase(char const *name = "unknown_conv3d") { + + description_.name = name; + description_.provider = Provider::kCUTLASS; + description_.kind = OperationKind::kConv3d; + description_.conv_dim = Operator::kConvDim; + + description_.iterator_algorithm = IteratorAlgorithmMap::kId; + + description_.tile_description.threadblock_shape = make_Coord( + Operator::ThreadblockShape::kM, + Operator::ThreadblockShape::kN, + Operator::ThreadblockShape::kK); + + description_.tile_description.threadblock_stages = Operator::kStages; + + description_.tile_description.warp_count = make_Coord( + Operator::ImplicitGemmKernel::WarpCount::kM, + Operator::ImplicitGemmKernel::WarpCount::kN, + Operator::ImplicitGemmKernel::WarpCount::kK); + + description_.tile_description.math_instruction.instruction_shape = make_Coord( + Operator::InstructionShape::kM, + Operator::InstructionShape::kN, + Operator::InstructionShape::kK); + + description_.tile_description.math_instruction.element_accumulator = + NumericTypeMap::kId; + + description_.tile_description.math_instruction.opcode_class = + OpcodeClassMap::kId; + + description_.tile_description.minimum_compute_capability = + ArchMap::kMin; + + description_.tile_description.maximum_compute_capability = + ArchMap::kMax; + + description_.A = make_TensorDescription(); + description_.B = make_TensorDescription(); + description_.C = make_TensorDescription(); + description_.element_epilogue = NumericTypeMap::kId; + + } + + /// Returns the description of the GEMM operation + virtual OperationDescription const & description() const { + return description_; + } +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Conv2d library operation class for cutlass profiler +// +/////////////////////////////////////////////////////////////////////////////////////////////////// +template +class Conv3dOperation : public Conv3dOperationBase { +public: + + using Operator = Operator_; + + using ElementA = typename Operator::ElementA; + using LayoutA = typename Operator::LayoutA; + using ElementB = typename Operator::ElementB; + using LayoutB = typename Operator::LayoutB; + using ElementC = typename Operator::ElementC; + using LayoutC = typename Operator::LayoutC; + using ElementAccumulator = typename Operator::ElementAccumulator; + using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute; + static cutlass::conv::Operator const kConvolutionalOperator = Operator::kConvolutionalOperator; + + using OperatorArguments = typename Operator::Arguments; + +public: + /// Constructor + Conv3dOperation(char const *name = "unknown_conv3d_fprop") : Conv3dOperationBase(name) { + this->description_.conv_kind = ConvKindMap::kId; + } + +protected: + + /// Constructs the arguments structure given the configuration and arguments + static Status construct_arguments_( + OperatorArguments &operator_args, + Conv3dConfiguration const *configuration) { + + + operator_args.problem_size = configuration->problem_size; + + operator_args.ref_A = + { + nullptr, + LayoutA::packed(implicit_gemm_tensor_a_extent(kConvolutionalOperator, configuration->problem_size)) + }; + + operator_args.ref_B = + { + nullptr, + LayoutB::packed(implicit_gemm_tensor_b_extent(kConvolutionalOperator, configuration->problem_size)) + }; + + operator_args.ref_C = + { + nullptr, + LayoutC::packed(implicit_gemm_tensor_c_extent(kConvolutionalOperator, configuration->problem_size)) + }; + + operator_args.ref_D = + { + nullptr, + LayoutC::packed(implicit_gemm_tensor_c_extent(kConvolutionalOperator, configuration->problem_size)) + }; + + operator_args.split_k_mode = configuration->split_k_mode; + + return Status::kSuccess; + } + + /// Constructs the arguments structure given the configuration and arguments + static Status update_arguments_( + OperatorArguments &operator_args, + ConvArguments const *arguments) { + + if (arguments->pointer_mode == ScalarPointerMode::kHost) { + typename Operator::EpilogueOutputOp::Params params( + *static_cast(arguments->alpha), + *static_cast(arguments->beta) + ); + operator_args.output_op = params; + } + else if (arguments->pointer_mode == ScalarPointerMode::kDevice){ + typename Operator::EpilogueOutputOp::Params params( + static_cast(arguments->alpha), + static_cast(arguments->beta) + ); + operator_args.output_op = params; + } + else { + return Status::kErrorInvalidProblem; + } + + operator_args.ref_A.reset(static_cast(const_cast(arguments->A))); + operator_args.ref_B.reset(static_cast(const_cast(arguments->B))); + operator_args.ref_C.reset(static_cast(const_cast(arguments->C))); + operator_args.ref_D.reset(static_cast(const_cast(arguments->D))); + + return Status::kSuccess; + } + +public: + + /// Returns success if the operation can proceed + virtual Status can_implement( + void const *configuration_ptr, + void const *arguments_ptr) const { + + Conv3dConfiguration const *configuration = + static_cast(configuration_ptr); + + ConvArguments const *arguments = + static_cast(arguments_ptr); + + OperatorArguments args; + + Status status = construct_arguments_(args, configuration); + + if (status != Status::kSuccess) { + return status; + } + + status = update_arguments_(args, arguments); + + if (status != Status::kSuccess) { + return status; + } + + return Operator::can_implement(args); + + } + + /// Gets the host-side workspace + virtual uint64_t get_host_workspace_size( + void const *configuration) const { + + return sizeof(Operator); + } + + /// Gets the device-side workspace + virtual uint64_t get_device_workspace_size( + void const *configuration_ptr) const { + + OperatorArguments args; + + Status status = construct_arguments_( + args, + static_cast(configuration_ptr)); + + if (status != Status::kSuccess) { + return 0; + } + + return Operator::get_workspace_size(args); + } + + /// Initializes the workspace + virtual Status initialize( + void const *configuration_ptr, + void *host_workspace, + void *device_workspace, + cudaStream_t stream = nullptr) const { + + OperatorArguments args; + + Status status = construct_arguments_( + args, + static_cast(configuration_ptr)); + + if (status != Status::kSuccess) { + return status; + } + + Operator *op = new (host_workspace) Operator; + //std::cout << "initialize library::Conv3dOperation" << std::endl; + //print_operator_args(args); + return op->initialize(args, device_workspace, stream); + + } + + /// Runs the kernel + virtual Status run( + void const *arguments_ptr, + void *host_workspace, + void *device_workspace = nullptr, + cudaStream_t stream = nullptr) const { + + OperatorArguments args; + + Status status = update_arguments_( + args, + static_cast(arguments_ptr)); + + if (status != Status::kSuccess) { + return status; + } + + Operator *op = static_cast(host_workspace); + + status = op->update(args, device_workspace); + + if (status != Status::kSuccess) { + return status; + } + //std::cout << "run library::Conv3dOperation" << std::endl; + //print_operator_args(args); + return op->run(stream); + } + + /// Call print_operator_args from the Conv3dOperation::initialize() + // to dump arguments passed on to cutlass operator for debugging + void print_operator_args(OperatorArguments &operator_args) const { + std::cout << "Conv3dOperation::OperatorArguments" << std::endl + << " problem_size: " + << operator_args.problem_size << std::endl + << " split_k_mode: " + << (operator_args.split_k_mode == cutlass::conv::SplitKMode::kSerial ? "serial" : "parallel") << std::endl + << " epilouge (alpha, beta): " + << operator_args.output_op.alpha << ", " + << operator_args.output_op.beta << std::endl + << " ref_A (ptr, {stride}): " + << operator_args.ref_A.data() << ", {" + << operator_args.ref_A.stride(0) << ", " + << operator_args.ref_A.stride(1) << ", " + << operator_args.ref_A.stride(2) << ", " + << operator_args.ref_A.stride(3) << "}" << std::endl + << " ref_B (ptr, {stride}): " + << operator_args.ref_B.data() << ", {" + << operator_args.ref_B.stride(0) << ", " + << operator_args.ref_B.stride(1) << ", " + << operator_args.ref_B.stride(2) << ", " + << operator_args.ref_B.stride(3) << "}" << std::endl + << " ref_C (ptr, {stride}): " + << operator_args.ref_C.data() << ", {" + << operator_args.ref_C.stride(0) << ", " + << operator_args.ref_C.stride(1) << ", " + << operator_args.ref_C.stride(2) << ", " + << operator_args.ref_C.stride(3) << "}" << std::endl + << " ref_D (ptr, {stride}): " + << operator_args.ref_D.data() << ", {" + << operator_args.ref_D.stride(0) << ", " + << operator_args.ref_D.stride(1) << ", " + << operator_args.ref_D.stride(2) << ", " + << operator_args.ref_D.stride(3) << "}" << std::endl; + } +}; + +} // namespace library +} // namespace cutlass + +/////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/library/src/handle.cu b/tools/library/src/handle.cu index bdddf2d7c..3f19def65 100644 --- a/tools/library/src/handle.cu +++ b/tools/library/src/handle.cu @@ -1037,8 +1037,70 @@ Status Handle::gemm_planar_complex_array( } ///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Finds conv operation instances with Conv::ElementC = Reduction::ElementWorkspace +Operation const* find_conv_operation_for_parallel_reduction(Operation const *operation) { + + ConvDescription const &conv_desc = + static_cast(operation->description()); + + // if the curren conv operation accumulator and output data type match return operation + if(conv_desc.tile_description.math_instruction.element_accumulator == conv_desc.C.element) { + return operation; + } + + // find conv operation to match conv output and reduction workspace data type + ConvFunctionalKey key( + library::Provider::kCUTLASS, + conv_desc.conv_kind, + conv_desc.A.element, + conv_desc.A.layout, + conv_desc.B.element, + conv_desc.B.layout, + conv_desc.tile_description.math_instruction.element_accumulator, + conv_desc.C.layout, + conv_desc.tile_description.math_instruction.element_accumulator, + conv_desc.element_epilogue); + + // conv operation table for conv2d or conv3d + auto conv_operations = (conv_desc.kind == OperationKind::kConv2d) ? + Singleton::get().operation_table.conv2d_operations : + Singleton::get().operation_table.conv3d_operations; + + // find ConvFunctionalKey in convolution operation table + auto operators_it = conv_operations.find(key); + + if (operators_it == conv_operations.end()) { + return nullptr; + } + + if (operators_it->second.empty()) { + return nullptr; + } + + // conv operation for same compute capability and iterator algorithm + ConvPreferenceKey preference_key( + conv_desc.tile_description.minimum_compute_capability, + conv_desc.iterator_algorithm); + + auto it = operators_it->second.find(preference_key); + + if(it == operators_it->second.end()) { + return nullptr; + } + + // return matching conv opertion (same tile sizes and instruction) + for (auto op : it->second) { + if (op->description().tile_description == operation->description().tile_description) { + return op; + } + } + + return nullptr; +} +///////////////////////////////////////////////////////////////////////////////////////////////// + } // namespace library } // namespace cutlass ///////////////////////////////////////////////////////////////////////////////////////////////// - diff --git a/tools/library/src/library_internal.h b/tools/library/src/library_internal.h index 21190cc82..4bbd21c76 100644 --- a/tools/library/src/library_internal.h +++ b/tools/library/src/library_internal.h @@ -227,6 +227,23 @@ template <> struct LayoutMap { template <> struct LayoutMap { static LayoutTypeID const kId = LayoutTypeID::kTensorNDHWC; }; + +template <> struct LayoutMap> { + static LayoutTypeID const kId = LayoutTypeID::kTensorNC32HW32; +}; + +template <> struct LayoutMap> { + static LayoutTypeID const kId = LayoutTypeID::kTensorNC64HW64; +}; + +template <> struct LayoutMap> { + static LayoutTypeID const kId = LayoutTypeID::kTensorC32RSK32; +}; + +template <> struct LayoutMap> { + static LayoutTypeID const kId = LayoutTypeID::kTensorC64RSK64; +}; + ///////////////////////////////////////////////////////////////////////////////////////////////// template struct OpcodeClassMap; @@ -257,6 +274,43 @@ template <> struct ComplexTransformMap { ///////////////////////////////////////////////////////////////////////////////////////////////// +template struct ConvModeMap; + +template <> struct ConvModeMap { + static ConvModeID const kId = ConvModeID::kCrossCorrelation; +}; + +template <> struct ConvModeMap { + static ConvModeID const kId = ConvModeID::kConvolution; +}; + + +template struct ConvKindMap; + +template <> struct ConvKindMap { + static ConvKind const kId = ConvKind::kFprop; +}; + +template <> struct ConvKindMap { + static ConvKind const kId = ConvKind::kDgrad; +}; + +template <> struct ConvKindMap { + static ConvKind const kId = ConvKind::kWgrad; +}; + + +template struct IteratorAlgorithmMap; + +template <> struct IteratorAlgorithmMap { + static IteratorAlgorithmID const kId = IteratorAlgorithmID::kAnalytic; +}; + +template <> struct IteratorAlgorithmMap { + static IteratorAlgorithmID const kId = IteratorAlgorithmID::kOptimized; +}; +///////////////////////////////////////////////////////////////////////////////////////////////// + template TensorDescription make_TensorDescription(int alignment = 1) { TensorDescription desc; diff --git a/tools/library/src/manifest.cpp b/tools/library/src/manifest.cpp index 29d2ef156..12358dcdd 100644 --- a/tools/library/src/manifest.cpp +++ b/tools/library/src/manifest.cpp @@ -36,6 +36,11 @@ namespace cutlass { namespace library { ////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void initialize_reference_operations(Manifest &manifest); + +////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Top-level initialization Status Manifest::initialize() { @@ -46,6 +51,12 @@ Status Manifest::initialize() { // initialize procedurally generated cutlass op in manifest object initialize_all(*this); + // initialize manually instanced conv3d reference op in manifest object + initialize_reference_operations(*this); + + // initialize manually instanced reduction reference op in manifest object + initialize_all_reduction_op(*this); + return Status::kSuccess; } diff --git a/tools/library/src/operation_table.cu b/tools/library/src/operation_table.cu index 64e4f264c..482bded85 100644 --- a/tools/library/src/operation_table.cu +++ b/tools/library/src/operation_table.cu @@ -76,6 +76,55 @@ void OperationTable::append(Manifest const &manifest) { } + // insert all conv2d or conv3d operation into operation table + if (desc.kind == OperationKind::kConv2d || desc.kind == OperationKind::kConv3d) { + auto &conv_desc = static_cast(desc); + + ConvFunctionalKey functional_key( + conv_desc.provider, + conv_desc.conv_kind, + conv_desc.A.element, + conv_desc.A.layout, + conv_desc.B.element, + conv_desc.B.layout, + conv_desc.C.element, + conv_desc.C.layout, + conv_desc.tile_description.math_instruction.element_accumulator, + conv_desc.element_epilogue + ); + + Operation const *op = operation.get(); + + int cc = conv_desc.tile_description.minimum_compute_capability; + + ConvPreferenceKey preference_key(cc, conv_desc.iterator_algorithm); + + // insert conv operation to conv2d_operations or conv3d_operations map + (desc.kind == OperationKind::kConv2d) ? + conv2d_operations[functional_key][preference_key].push_back(op) : + conv3d_operations[functional_key][preference_key].push_back(op); + } + + // insert all reduction operation into operation table + if (desc.kind == OperationKind::kReduction) { + auto &reduce_desc = static_cast(desc); + + ReductionFunctionalKey functional_key( + reduce_desc.provider, + reduce_desc.element_workspace, + reduce_desc.tile_description.math_instruction.element_accumulator, + reduce_desc.element_output, + reduce_desc.element_epilogue, + library::MathOperationID::kAdd, + library::EpilogueKind::kLinearCombination + ); + + Operation const *op = operation.get(); + + reduction_operations[functional_key] = op; + + } + } } diff --git a/tools/library/src/reduction/init_reduction_operations.cu b/tools/library/src/reduction/init_reduction_operations.cu new file mode 100644 index 000000000..5f86b64f7 --- /dev/null +++ b/tools/library/src/reduction/init_reduction_operations.cu @@ -0,0 +1,57 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Initialize operations for reduction operation in CUTLASS Library. + +*/ + +#include "cutlass/cutlass.h" +#include "cutlass/library/library.h" +#include "cutlass/library/manifest.h" + +namespace cutlass { +namespace library { +/////////////////////////////////////////////////////////////////////////////////////////////// +// CUTLASS Reduction Instances // +/////////////////////////////////////////////////////////////////////////////////////////////// +void initialize_reduce_add_linear_combination_f32_f32_f16(Manifest &manifest); +void initialize_reduce_add_linear_combination_f32_f32_f32(Manifest &manifest); +void initialize_reduce_add_linear_combination_cf32_cf32_cf32(Manifest &manifest); + +// +// Entry point to construct operations +// +void initialize_all_reduction_op(Manifest &manifest) { + + initialize_reduce_add_linear_combination_f32_f32_f16(manifest); + initialize_reduce_add_linear_combination_f32_f32_f32(manifest); + initialize_reduce_add_linear_combination_cf32_cf32_cf32(manifest); + +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace library +} // namespace cutlass diff --git a/tools/library/src/reduction/reduction_device.cu b/tools/library/src/reduction/reduction_device.cu new file mode 100644 index 000000000..e2133cc0a --- /dev/null +++ b/tools/library/src/reduction/reduction_device.cu @@ -0,0 +1,145 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Defines operations for reduction operation in CUTLASS Library. +*/ + +#include "cutlass/cutlass.h" +#include "cutlass/library/library.h" +#include "cutlass/library/manifest.h" + +#include "reduction_operation.h" + +namespace cutlass { +namespace library { + +// naming convention initialize_reduce_[ReductionOp]_[EpilogueOp]_[ElementWorkspace]_[ElementAccumulator]_[ElementOutput] + +void initialize_reduce_add_linear_combination_f32_f32_f16(Manifest &manifest) { + + using ElementWorkspace = float; + using ElementAccumulator = float; + using ElementOutput = cutlass::half_t; + using ElementCompute = float; + + using EpilogueOutputOp = cutlass::epilogue::thread::LinearCombination< + ElementOutput, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >; + + using ReductionOp = cutlass::reduction::thread::ReduceAdd< + ElementAccumulator, + typename EpilogueOutputOp::ElementAccumulator, + EpilogueOutputOp::kCount + >; + + using Operation_reduce_add_linear_combination_f32_f32_f16 = cutlass::reduction::device::ReduceSplitK< + cutlass::reduction::kernel::ReduceSplitK< + cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>, + EpilogueOutputOp, + ReductionOp + > + >; + + manifest.append(new ReductionOperation< + Operation_reduce_add_linear_combination_f32_f32_f16>( + "reduce_add_linear_combination_f32_f32_f16" + )); +} + + +void initialize_reduce_add_linear_combination_f32_f32_f32(Manifest &manifest) { + + using ElementWorkspace = float; + using ElementAccumulator = float; + using ElementOutput = float; + using ElementCompute = float; + + using EpilogueOutputOp = cutlass::epilogue::thread::LinearCombination< + ElementOutput, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >; + + using ReductionOp = cutlass::reduction::thread::ReduceAdd< + ElementAccumulator, + typename EpilogueOutputOp::ElementAccumulator, + EpilogueOutputOp::kCount + >; + + using Operation_reduce_add_linear_combination_f32_f32_f32 = cutlass::reduction::device::ReduceSplitK< + cutlass::reduction::kernel::ReduceSplitK< + cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>, + EpilogueOutputOp, + ReductionOp + > + >; + + manifest.append(new ReductionOperation< + Operation_reduce_add_linear_combination_f32_f32_f32>( + "reduce_add_linear_combination_f32_f32_f32" + )); +} + +void initialize_reduce_add_linear_combination_cf32_cf32_cf32(Manifest &manifest) { + + using ElementWorkspace = cutlass::complex; + using ElementAccumulator = cutlass::complex; + using ElementOutput = cutlass::complex; + using ElementCompute = cutlass::complex; + + using EpilogueOutputOp = cutlass::epilogue::thread::LinearCombination< + ElementOutput, + 128 / cutlass::sizeof_bits::value, + ElementAccumulator, + ElementCompute + >; + + using ReductionOp = cutlass::reduction::thread::ReduceAdd< + ElementAccumulator, + typename EpilogueOutputOp::ElementAccumulator, + EpilogueOutputOp::kCount + >; + + using Operation_reduce_add_linear_combination_cf32_cf32_cf32 = cutlass::reduction::device::ReduceSplitK< + cutlass::reduction::kernel::ReduceSplitK< + cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>, + EpilogueOutputOp, + ReductionOp + > + >; + + manifest.append(new ReductionOperation< + Operation_reduce_add_linear_combination_cf32_cf32_cf32>( + "reduce_add_linear_combination_cf32_cf32_cf32" + )); +} + + +} +} diff --git a/tools/library/src/reduction/reduction_operation.h b/tools/library/src/reduction/reduction_operation.h new file mode 100644 index 000000000..88572ff68 --- /dev/null +++ b/tools/library/src/reduction/reduction_operation.h @@ -0,0 +1,282 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Defines operations for reduction operation in CUTLASS Library. +*/ + +#pragma once +#include +#include "cutlass/cutlass.h" +#include "cutlass/epilogue/thread/linear_combination.h" +#include "cutlass/reduction/thread/reduction_operators.h" +#include "cutlass/reduction/device/reduce_split_k.h" + +#include "cutlass/library/library.h" +#include "library_internal.h" +#include "cutlass/core_io.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace library { + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ReductionOperation : public Operation { +public: + using Operator = Operator_; + + using ElementWorkspace = typename Operator::ElementWorkspace; + using ElementAccumulator = typename Operator::ElementAccumulator; + using ElementOutput = typename Operator::ElementOutput; + + using ElementCompute = typename Operator::OutputOp::ElementCompute; + + using OperatorArguments = typename Operator::Arguments; + +protected: + + /// + ReductionDescription description_; + +public: + + /// Constructor + ReductionOperation(char const *name = "unknown_reduction") { + + description_.name = name; + description_.provider = Provider::kCUTLASS; + description_.kind = OperationKind::kReduction; + + description_.tile_description.threadblock_shape = make_Coord(Operator::Shape::kRow, Operator::Shape::kColumn, 1); + + description_.tile_description.math_instruction.instruction_shape = make_Coord(1, 1, 1); + description_.tile_description.math_instruction.element_accumulator = NumericTypeMap::kId; + description_.tile_description.math_instruction.opcode_class = OpcodeClassID::kSimt; + description_.tile_description.math_instruction.math_operation = MathOperationID::kAdd; + + description_.tile_description.minimum_compute_capability = 50; + description_.tile_description.maximum_compute_capability = 1024; + + description_.element_workspace = NumericTypeMap::kId; + description_.element_output = NumericTypeMap::kId; + description_.element_epilogue = NumericTypeMap::kId; + + } + + /// Returns the description of the Reduction operation + virtual OperationDescription const & description() const { + return description_; + } + + +protected: + + /// Constructs the arguments structure given the configuration and arguments + static Status construct_arguments_( + OperatorArguments &operator_args, + ReductionConfiguration const *configuration) { + + operator_args.problem_size = configuration->problem_size; + operator_args.partitions = configuration->partitions; + operator_args.partition_stride = configuration->partition_stride; + + operator_args.workspace = {nullptr, int(configuration->ldw)}; + operator_args.source = {nullptr, int(configuration->lds)}; + operator_args.destination = {nullptr, int(configuration->ldd)}; + + return Status::kSuccess; + } + + /// Constructs the arguments structure given the configuration and arguments + static Status update_arguments_( + OperatorArguments &operator_args, + ReductionArguments const *arguments) { + + if (arguments->pointer_mode == ScalarPointerMode::kHost) { + typename Operator::OutputOp::Params params( + *static_cast(arguments->alpha), + *static_cast(arguments->beta) + ); + operator_args.output = params; + } + else if (arguments->pointer_mode == ScalarPointerMode::kDevice){ + typename Operator::OutputOp::Params params( + static_cast(arguments->alpha), + static_cast(arguments->beta) + ); + operator_args.output = params; + } + else { + return Status::kErrorInvalidProblem; + } + + operator_args.workspace.reset(static_cast(const_cast(arguments->workspace))); + operator_args.source.reset(static_cast(const_cast(arguments->source))); + operator_args.destination.reset(static_cast(const_cast(arguments->destination))); + + return Status::kSuccess; + } + +public: + + /// Returns success if the operation can proceed + virtual Status can_implement( + void const *configuration_ptr, + void const *arguments_ptr) const { + + ReductionConfiguration const *configuration = + static_cast(configuration_ptr); + + ReductionArguments const *arguments = + static_cast(arguments_ptr); + + OperatorArguments args; + + Status status = construct_arguments_(args, configuration); + + if (status != Status::kSuccess) { + return status; + } + + status = update_arguments_(args, arguments); + + if (status != Status::kSuccess) { + return status; + } + + return Operator::can_implement(args); + } + + /// Gets the host-side workspace + virtual uint64_t get_host_workspace_size( + void const *configuration) const { + + return sizeof(Operator); + } + + /// Gets the device-side workspace + virtual uint64_t get_device_workspace_size( + void const *configuration_ptr) const { + + OperatorArguments args; + + Status status = construct_arguments_( + args, + static_cast(configuration_ptr)); + + if (status != Status::kSuccess) { + return 0; + } + + return Operator::get_workspace_size(args); + } + + /// Initializes the workspace + virtual Status initialize( + void const *configuration_ptr, + void *host_workspace, + void *device_workspace, + cudaStream_t stream = nullptr) const { + + OperatorArguments args; + + Status status = construct_arguments_( + args, + static_cast(configuration_ptr)); + + if (status != Status::kSuccess) { + return status; + } + + Operator *op = new (host_workspace) Operator; + //std::cout << "initialize library::Reduction" << std::endl; + //print_operator_args(args); + return op->initialize(args, device_workspace, stream); + } + + /// Runs the kernel + virtual Status run( + void const *arguments_ptr, + void *host_workspace, + void *device_workspace = nullptr, + cudaStream_t stream = nullptr) const { + + OperatorArguments args; + + Status status = update_arguments_( + args, + static_cast(arguments_ptr)); + + if (status != Status::kSuccess) { + return status; + } + + Operator *op = static_cast(host_workspace); + + status = op->update(args, device_workspace); + + if (status != Status::kSuccess) { + return status; + } + + //std::cout << "run library::Reduction" << std::endl; + //print_operator_args(args); + return op->run(stream); + } + + /// Call print_operator_args from the Reduction::initialize() + // to dump arguments passed on to cutlass operator for debugging + void print_operator_args(OperatorArguments &operator_args) const { + std::cout << "Reduction::OperatorArguments" << std::endl + << " problem_size: " + << operator_args.problem_size << std::endl + << " partitions: " + << operator_args.partitions << std::endl + << " partition_stride: " + << operator_args.partition_stride << std::endl + << " epilouge (alpha, beta): " + << operator_args.output.alpha << ", " + << operator_args.output.beta << std::endl + << " workspace (ptr, stride): " + << operator_args.workspace.data() << ", " + << operator_args.workspace.stride(0) << std::endl + << " source (ptr, stride): " + << operator_args.source.data() << ", " + << operator_args.source.stride(0) << std::endl + << " destination (ptr, stride): " + << operator_args.destination.data() << ", " + << operator_args.destination.stride(0) << std::endl; + } +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace library +} // namespace cutlass + +/////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/library/src/reference/conv2d.cu b/tools/library/src/reference/conv2d.cu new file mode 100644 index 000000000..750ebdf31 --- /dev/null +++ b/tools/library/src/reference/conv2d.cu @@ -0,0 +1,223 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief + +*/ + +#include "cutlass/cutlass.h" +#include "cutlass/library/library.h" +#include "cutlass/library/manifest.h" + +#include "conv_reference_operation.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace library { + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void initialize_conv2d_reference_operations(Manifest &manifest) { + + make_conv_all< + 2, + cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, + cutlass::half_t + >(manifest); + + make_conv_all< + 2, + cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, cutlass::layout::TensorNHWC, + float, + float + >(manifest); + + make_conv_all< + 2, + cutlass::half_t, cutlass::layout::TensorNHWC, + cutlass::half_t, cutlass::layout::TensorNHWC, + float, cutlass::layout::TensorNHWC, + float, + float + >(manifest); + + make_conv_all< + 2, + cutlass::bfloat16_t, cutlass::layout::TensorNHWC, + cutlass::bfloat16_t, cutlass::layout::TensorNHWC, + cutlass::bfloat16_t, cutlass::layout::TensorNHWC, + float, + float + >(manifest); + + make_conv_all< + 2, + cutlass::bfloat16_t, cutlass::layout::TensorNHWC, + cutlass::bfloat16_t, cutlass::layout::TensorNHWC, + float, cutlass::layout::TensorNHWC, + float, + float + >(manifest); + + make_conv_all< + 2, + cutlass::tfloat32_t, cutlass::layout::TensorNHWC, + cutlass::tfloat32_t, cutlass::layout::TensorNHWC, + cutlass::tfloat32_t, cutlass::layout::TensorNHWC, + float, + float + >(manifest); + + make_conv_all< + 2, + cutlass::tfloat32_t, cutlass::layout::TensorNHWC, + cutlass::tfloat32_t, cutlass::layout::TensorNHWC, + float, cutlass::layout::TensorNHWC, + float, + float + >(manifest); + + make_conv_all< + 2, + float, cutlass::layout::TensorNHWC, + float, cutlass::layout::TensorNHWC, + float, cutlass::layout::TensorNHWC, + float, + float + >(manifest); + + make_conv_all< + 2, + cutlass::complex, cutlass::layout::TensorNHWC, + cutlass::complex, cutlass::layout::TensorNHWC, + cutlass::complex, cutlass::layout::TensorNHWC, + cutlass::complex, + cutlass::complex + >(manifest); + + make_conv_fprop< + 2, + int8_t, cutlass::layout::TensorNHWC, + int8_t, cutlass::layout::TensorNHWC, + int32_t, cutlass::layout::TensorNHWC, + int32_t, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 2, + int8_t, cutlass::layout::TensorNHWC, + int8_t, cutlass::layout::TensorNHWC, + int8_t, cutlass::layout::TensorNHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 2, + uint8_t, cutlass::layout::TensorNHWC, + uint8_t, cutlass::layout::TensorNHWC, + uint8_t, cutlass::layout::TensorNHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 2, + uint8_t, cutlass::layout::TensorNHWC, + uint8_t, cutlass::layout::TensorNHWC, + int32_t, cutlass::layout::TensorNHWC, + int32_t, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 2, + uint8_t, cutlass::layout::TensorNHWC, + uint8_t, cutlass::layout::TensorNHWC, + int8_t, cutlass::layout::TensorNHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 2, + cutlass::int4b_t, cutlass::layout::TensorNHWC, + cutlass::int4b_t, cutlass::layout::TensorNHWC, + int32_t, cutlass::layout::TensorNHWC, + int32_t, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 2, + cutlass::int4b_t, cutlass::layout::TensorNHWC, + cutlass::int4b_t, cutlass::layout::TensorNHWC, + cutlass::int4b_t, cutlass::layout::TensorNHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 2, + cutlass::uint4b_t, cutlass::layout::TensorNHWC, + cutlass::uint4b_t, cutlass::layout::TensorNHWC, + int32_t, cutlass::layout::TensorNHWC, + int32_t, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 2, + cutlass::uint4b_t, cutlass::layout::TensorNHWC, + cutlass::uint4b_t, cutlass::layout::TensorNHWC, + cutlass::uint4b_t, cutlass::layout::TensorNHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace library +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/tools/library/src/reference/conv3d.cu b/tools/library/src/reference/conv3d.cu new file mode 100644 index 000000000..1e1544bff --- /dev/null +++ b/tools/library/src/reference/conv3d.cu @@ -0,0 +1,203 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief +*/ + +#include "cutlass/cutlass.h" +#include "cutlass/library/library.h" +#include "cutlass/library/manifest.h" + +#include "conv_reference_operation.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace library { + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void initialize_conv3d_reference_operations(Manifest &manifest) { + + make_conv_all< + 3, + cutlass::half_t, cutlass::layout::TensorNDHWC, + cutlass::half_t, cutlass::layout::TensorNDHWC, + cutlass::half_t, cutlass::layout::TensorNDHWC, + cutlass::half_t, + cutlass::half_t + >(manifest); + + make_conv_all< + 3, + cutlass::half_t, cutlass::layout::TensorNDHWC, + cutlass::half_t, cutlass::layout::TensorNDHWC, + cutlass::half_t, cutlass::layout::TensorNDHWC, + float, + float + >(manifest); + + make_conv_all< + 3, + cutlass::half_t, cutlass::layout::TensorNDHWC, + cutlass::half_t, cutlass::layout::TensorNDHWC, + float, cutlass::layout::TensorNDHWC, + float, + float + >(manifest); + + make_conv_all< + 3, + cutlass::bfloat16_t, cutlass::layout::TensorNDHWC, + cutlass::bfloat16_t, cutlass::layout::TensorNDHWC, + cutlass::bfloat16_t, cutlass::layout::TensorNDHWC, + float, + float + >(manifest); + + make_conv_all< + 3, + cutlass::bfloat16_t, cutlass::layout::TensorNDHWC, + cutlass::bfloat16_t, cutlass::layout::TensorNDHWC, + float, cutlass::layout::TensorNDHWC, + float, + float + >(manifest); + + make_conv_all< + 3, + cutlass::tfloat32_t, cutlass::layout::TensorNDHWC, + cutlass::tfloat32_t, cutlass::layout::TensorNDHWC, + cutlass::tfloat32_t, cutlass::layout::TensorNDHWC, + float, + float + >(manifest); + + make_conv_all< + 3, + cutlass::tfloat32_t, cutlass::layout::TensorNDHWC, + cutlass::tfloat32_t, cutlass::layout::TensorNDHWC, + float, cutlass::layout::TensorNDHWC, + float, + float + >(manifest); + + make_conv_all< + 3, + float, cutlass::layout::TensorNDHWC, + float, cutlass::layout::TensorNDHWC, + float, cutlass::layout::TensorNDHWC, + float, + float + >(manifest); + + make_conv_fprop< + 3, + int8_t, cutlass::layout::TensorNDHWC, + int8_t, cutlass::layout::TensorNDHWC, + int32_t, cutlass::layout::TensorNDHWC, + int32_t, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 3, + int8_t, cutlass::layout::TensorNDHWC, + int8_t, cutlass::layout::TensorNDHWC, + int8_t, cutlass::layout::TensorNDHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 3, + uint8_t, cutlass::layout::TensorNDHWC, + uint8_t, cutlass::layout::TensorNDHWC, + int32_t, cutlass::layout::TensorNDHWC, + int32_t, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 3, + uint8_t, cutlass::layout::TensorNDHWC, + uint8_t, cutlass::layout::TensorNDHWC, + int8_t, cutlass::layout::TensorNDHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 3, + cutlass::int4b_t, cutlass::layout::TensorNDHWC, + cutlass::int4b_t, cutlass::layout::TensorNDHWC, + int32_t, cutlass::layout::TensorNDHWC, + int32_t, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 3, + cutlass::int4b_t, cutlass::layout::TensorNDHWC, + cutlass::int4b_t, cutlass::layout::TensorNDHWC, + cutlass::int4b_t, cutlass::layout::TensorNDHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 3, + cutlass::uint4b_t, cutlass::layout::TensorNDHWC, + cutlass::uint4b_t, cutlass::layout::TensorNDHWC, + int32_t, cutlass::layout::TensorNDHWC, + int32_t, + int32_t, + NumericConverterClamp + >(manifest); + + make_conv_fprop< + 3, + cutlass::uint4b_t, cutlass::layout::TensorNDHWC, + cutlass::uint4b_t, cutlass::layout::TensorNDHWC, + cutlass::uint4b_t, cutlass::layout::TensorNDHWC, + float, + int32_t, + NumericConverterClamp + >(manifest); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace library +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/tools/library/src/reference/conv_reference_operation.h b/tools/library/src/reference/conv_reference_operation.h new file mode 100644 index 000000000..1e826ab29 --- /dev/null +++ b/tools/library/src/reference/conv_reference_operation.h @@ -0,0 +1,607 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Defines operations for all CONV operation kinds in CUTLASS Library +*/ + +#pragma once + +#include +#include +#include + +#include "cutlass/cutlass.h" + +#include "cutlass/library/library.h" +#include "cutlass/library/manifest.h" +#include "cutlass/library/util.h" +#include "library_internal.h" + +#include "cutlass/util/reference/host/convolution.h" +#include "cutlass/util/reference/device/convolution.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace library { + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace detail { + +template < + Provider kProvider, + conv::Operator ConvolutionalOperator, + int ConvDim, + typename ElementA_, + typename LayoutA_, + typename ElementB_, + typename LayoutB_, + typename ElementC_, + typename LayoutC_, + typename ElementCompute_, + typename ElementAccumulator_ = ElementCompute_, + typename ConvertOp_ = NumericConverter, + typename InnerProductOp_ = multiply_add +> +struct ConvReferenceDispatcher; + +/// Dispatcher for Conv2d (partially specialied for kConvDim == 2) +template < + Provider kProvider, + conv::Operator kConvolutionalOperator, + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator, + typename ConvertOp, + typename InnerProductOp +> +struct ConvReferenceDispatcher< + kProvider, + kConvolutionalOperator, + 2, + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp> { + + static Status dispatch( + void const *configuration, + ElementA *ptr_A, + ElementB *ptr_B, + ElementC *ptr_C, + ElementC *ptr_D, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr + ) { + + Conv2dConfiguration const &config = + *static_cast(configuration); + + ConvKind const conv_kind = ConvKindMap::kId; + + if (kProvider == Provider::kReferenceHost) { + + cutlass::reference::host::Conv2d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC , + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp + >( + kConvolutionalOperator, + config.problem_size, + {ptr_A, config.layout_a(conv_kind)}, + {ptr_B, config.layout_b(conv_kind)}, + {ptr_C, config.layout_c(conv_kind)}, + {ptr_D, config.layout_c(conv_kind)}, + alpha, + beta + ); + + return Status::kSuccess; + } + else if (kProvider == Provider::kReferenceDevice) { + return cutlass::reference::device::Conv2d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp + >( + kConvolutionalOperator, + config.problem_size, + {ptr_A, config.layout_a(conv_kind)}, + {ptr_B, config.layout_b(conv_kind)}, + {ptr_C, config.layout_c(conv_kind)}, + {ptr_D, config.layout_c(conv_kind)}, + alpha, + beta, + stream + ); + } + return Status::kErrorNotSupported; + } +}; + +/// Dispatcher for Conv3d (partially specialized for kConvDim == 3) +template < + Provider kProvider, + conv::Operator kConvolutionalOperator, + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator, + typename ConvertOp, + typename InnerProductOp +> +struct ConvReferenceDispatcher< + kProvider, + kConvolutionalOperator, + 3, + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp> { + + static Status dispatch( + void const *configuration, + ElementA *ptr_A, + ElementB *ptr_B, + ElementC *ptr_C, + ElementC *ptr_D, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr + ) { + + Conv3dConfiguration const &config = + *static_cast(configuration); + + ConvKind const conv_kind = ConvKindMap::kId; + + if (kProvider == Provider::kReferenceHost) { + cutlass::reference::host::Conv3d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC , + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp + >( + kConvolutionalOperator, + config.problem_size, + {ptr_A, config.layout_a(conv_kind)}, + {ptr_B, config.layout_b(conv_kind)}, + {ptr_C, config.layout_c(conv_kind)}, + {ptr_D, config.layout_c(conv_kind)}, + alpha, + beta + ); + + return Status::kSuccess; + } + else if (kProvider == Provider::kReferenceDevice) { + return cutlass::reference::device::Conv3d< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp + >( + kConvolutionalOperator, + config.problem_size, + {ptr_A, config.layout_a(conv_kind)}, + {ptr_B, config.layout_b(conv_kind)}, + {ptr_C, config.layout_c(conv_kind)}, + {ptr_D, config.layout_c(conv_kind)}, + alpha, + beta, + stream + ); + } + return Status::kErrorNotSupported; + } +}; + +} // namespace detail + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template < + Provider Provider_, + conv::Operator ConvolutionalOperator, + int ConvDim, + typename ElementA_, + typename LayoutA_, + typename ElementB_, + typename LayoutB_, + typename ElementC_, + typename LayoutC_, + typename ElementCompute_, + typename ElementAccumulator_ = ElementCompute_, + typename ConvertOp_ = NumericConverter, + typename InnerProductOp_ = multiply_add +> +class ConvReferenceOperation : public Operation { +public: + static Provider const kProvider = Provider_; + static conv::Operator const kConvolutionalOperator = ConvolutionalOperator; + static int const kConvDim = ConvDim; + + using ElementA = ElementA_; + using LayoutA = LayoutA_; + using ElementB = ElementB_; + using LayoutB = LayoutB_; + using ElementC = ElementC_; + using LayoutC = LayoutC_; + using ElementCompute = ElementCompute_; + using ElementAccumulator = ElementAccumulator_; + using ConvertOp = ConvertOp_; + using InnerProductOp = InnerProductOp_; + +protected: + + /// Storage for the name string + std::string name_; + + /// + ConvDescription description_; + +public: + + /// Constructor + ConvReferenceOperation() { + + // Basic information + description_.provider = kProvider; + description_.kind = (kConvDim == 2 ? OperationKind::kConv2d : OperationKind::kConv3d); + description_.conv_kind = ConvKindMap::kId; + description_.conv_dim = kConvDim; + + // Tensor description + description_.A = make_TensorDescription(); + description_.B = make_TensorDescription(); + description_.C = make_TensorDescription(); + + // Epilogue compute and accumulator type description + description_.element_epilogue = NumericTypeMap::kId; + + description_.tile_description.math_instruction.element_accumulator = + NumericTypeMap::kId; + + // Iterator algorithm for convolution reference + description_.iterator_algorithm = IteratorAlgorithmID::kNone; + + // Compute capability for convolution reference + description_.tile_description.minimum_compute_capability = + (kProvider == Provider::kReferenceDevice ? 50 : 0); + + description_.tile_description.maximum_compute_capability = 1024; + + // Procedural name + std::stringstream ss; + + ss << "conv" << kConvDim << "d_" << to_string(description_.conv_kind) + << "_reference_" << to_string(description_.provider) + << "_" << to_string(description_.A.element) << to_string(description_.A.layout) + << "_" << to_string(description_.B.element) << to_string(description_.B.layout) + << "_" << to_string(description_.C.element) << to_string(description_.C.layout) + << "_" << to_string(description_.tile_description.math_instruction.element_accumulator); + + name_ = ss.str(); + + description_.name = name_.c_str(); + + // Epilogue compute and accumulator type description + description_.element_epilogue = NumericTypeMap::kId; + + description_.tile_description.math_instruction.element_accumulator = + NumericTypeMap::kId; + } + + /// Returns the description of the GEMM operation + virtual OperationDescription const & description() const { + return description_; + } + + virtual Status can_implement( + void const *configuration, + void const *arguments) const { + + return Status::kSuccess; + } + + virtual uint64_t get_host_workspace_size( + void const *configuration) const { + + switch (kConvDim) { + case 2: + return sizeof(Conv2dConfiguration); + case 3: + return sizeof(Conv3dConfiguration); + default: + break; + } + + return 0; + } + + virtual uint64_t get_device_workspace_size( + void const *configuration) const { + + return 0; + } + + virtual Status initialize( + void const *configuration, + void *host_workspace, + void *device_workspace = nullptr, + cudaStream_t stream = nullptr) const { + + std::memcpy(host_workspace, configuration, get_host_workspace_size(configuration)); + + return Status::kSuccess; + } + + virtual Status run( + void const *arguments, + void *host_workspace, + void *device_workspace = nullptr, + cudaStream_t stream = nullptr) const { + + ConvArguments const &args = *static_cast(arguments); + + ElementCompute alpha; + ElementCompute beta; + + alpha = *static_cast(args.alpha); + beta = *static_cast(args.beta); + + // TODO - respect pointer mode + + // Invoke 2D or 3D convolution + return detail::ConvReferenceDispatcher< + kProvider, + kConvolutionalOperator, + kConvDim, + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp + >::dispatch( + host_workspace, + static_cast(const_cast(args.A)), + static_cast(const_cast(args.B)), + static_cast(const_cast(args.C)), + static_cast(args.D), + alpha, + beta, + stream + ); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Constructs Fprop reference operators. +template < + int kConvDim, + typename ElementA_, + typename LayoutA_, + typename ElementB_, + typename LayoutB_, + typename ElementC_, + typename LayoutC_, + typename ElementCompute_, + typename ElementAccumulator_ = ElementCompute_, + typename ConvertOp_ = NumericConverter, + typename InnerProductOp_ = multiply_add +> +void make_conv_fprop(Manifest &manifest) { + + manifest.append(new ConvReferenceOperation< + Provider::kReferenceHost, + conv::Operator::kFprop, + kConvDim, + ElementA_, LayoutA_, + ElementB_, LayoutB_, + ElementC_, LayoutC_, + ElementCompute_, + ElementAccumulator_, + ConvertOp_, + InnerProductOp_ + >); + + manifest.append(new ConvReferenceOperation< + Provider::kReferenceDevice, + conv::Operator::kFprop, + kConvDim, + ElementA_, LayoutA_, + ElementB_, LayoutB_, + ElementC_, LayoutC_, + ElementCompute_, + ElementAccumulator_, + ConvertOp_, + InnerProductOp_ + >); +} + +/// Constructs Dgrad and Wgrad reference operators. +template < + int kConvDim, + typename ElementA_, + typename LayoutA_, + typename ElementB_, + typename LayoutB_, + typename ElementC_, + typename LayoutC_, + typename ElementCompute_, + typename ElementAccumulator_ = ElementCompute_, + typename ConvertOp_ = NumericConverter, + typename InnerProductOp_ = multiply_add +> +void make_conv_backwards(Manifest &manifest) { + + manifest.append(new ConvReferenceOperation< + Provider::kReferenceHost, + conv::Operator::kDgrad, + kConvDim, + ElementA_, LayoutA_, + ElementB_, LayoutB_, + ElementC_, LayoutC_, + ElementCompute_, + ElementAccumulator_, + ConvertOp_, + InnerProductOp_ + >); + + manifest.append(new ConvReferenceOperation< + Provider::kReferenceDevice, + conv::Operator::kDgrad, + kConvDim, + ElementA_, LayoutA_, + ElementB_, LayoutB_, + ElementC_, LayoutC_, + ElementCompute_, + ElementAccumulator_, + ConvertOp_, + InnerProductOp_ + >); + + manifest.append(new ConvReferenceOperation< + Provider::kReferenceHost, + conv::Operator::kWgrad, + kConvDim, + ElementA_, LayoutA_, + ElementB_, LayoutB_, + ElementC_, LayoutC_, + ElementCompute_, + ElementAccumulator_, + ConvertOp_, + InnerProductOp_ + >); + + manifest.append(new ConvReferenceOperation< + Provider::kReferenceDevice, + conv::Operator::kWgrad, + kConvDim, + ElementA_, LayoutA_, + ElementB_, LayoutB_, + ElementC_, LayoutC_, + ElementCompute_, + ElementAccumulator_, + ConvertOp_, + InnerProductOp_ + >); +} + +/// Six operators for the price of one. +template < + int kConvDim, + typename ElementA_, + typename LayoutA_, + typename ElementB_, + typename LayoutB_, + typename ElementC_, + typename LayoutC_, + typename ElementCompute_, + typename ElementAccumulator_ = ElementCompute_, + typename ConvertOp_ = NumericConverter, + typename InnerProductOp_ = multiply_add +> +void make_conv_all(Manifest &manifest) { + + make_conv_fprop< + kConvDim, + ElementA_, LayoutA_, + ElementB_, LayoutB_, + ElementC_, LayoutC_, + ElementCompute_, + ElementAccumulator_, + ConvertOp_, + InnerProductOp_ + >(manifest); + + make_conv_backwards< + kConvDim, + ElementA_, LayoutA_, + ElementB_, LayoutB_, + ElementC_, LayoutC_, + ElementCompute_, + ElementAccumulator_, + ConvertOp_, + InnerProductOp_ + >(manifest); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace library +} // namespace cutlass + +/////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/tools/library/src/reference/initialize_reference_operations.cu b/tools/library/src/reference/initialize_reference_operations.cu index 016d91a6f..c749c2bca 100644 --- a/tools/library/src/reference/initialize_reference_operations.cu +++ b/tools/library/src/reference/initialize_reference_operations.cu @@ -37,10 +37,14 @@ namespace cutlass { namespace library { void initialize_gemm_reference_operations(Manifest &manifest); +void initialize_conv2d_reference_operations(Manifest &manifest); +void initialize_conv3d_reference_operations(Manifest &manifest); /////////////////////////////////////////////////////////////////////////////////////////////////// void initialize_reference_operations(Manifest &manifest) { + initialize_conv2d_reference_operations(manifest); + initialize_conv3d_reference_operations(manifest); initialize_gemm_reference_operations(manifest); } diff --git a/tools/library/src/util.cu b/tools/library/src/util.cu index 13fb9dfc0..b20f50542 100644 --- a/tools/library/src/util.cu +++ b/tools/library/src/util.cu @@ -50,6 +50,7 @@ Provider_enumerants[] = { {"host", "reference_host", Provider::kReferenceHost}, {"device", "reference_device", Provider::kReferenceDevice}, {"cublas", "cuBLAS", Provider::kCUBLAS}, + {"cudnn", "cuDNN", Provider::kCUDNN}, }; /// Converts a Provider enumerant to a string @@ -128,6 +129,9 @@ static struct { OperationKind_enumerants[] = { {"eq_gemm", "EqGemm", OperationKind::kEqGemm}, {"gemm", "Gemm", OperationKind::kGemm}, + {"conv2d", "Conv2d", OperationKind::kConv2d}, + {"conv3d", "Conv3d", OperationKind::kConv3d}, + {"spgemm", "SparseGemm", OperationKind::kSparseGemm}, }; /// Converts a Status enumerant to a string @@ -445,6 +449,10 @@ layout_aliases[] = { {LayoutTypeID::kTensorNCDHW, "ncdhw"}, {LayoutTypeID::kTensorNHWC, "nhwc"}, {LayoutTypeID::kTensorNDHWC, "ndhwc"}, + {LayoutTypeID::kTensorNC32HW32, "nc32hw32"}, + {LayoutTypeID::kTensorNC64HW64, "nc64hw64"}, + {LayoutTypeID::kTensorC32RSK32, "c32rsk32"}, + {LayoutTypeID::kTensorC64RSK64, "c64rsk64"}, {LayoutTypeID::kUnknown, "*"}, {LayoutTypeID::kInvalid, nullptr} @@ -474,22 +482,46 @@ LayoutTypeID from_string(std::string const &str) { /// Gets stride rank for the layout_id (static function) int get_layout_stride_rank(LayoutTypeID layout_id) { switch (layout_id) { - case LayoutTypeID::kColumnMajor: return cutlass::layout::ColumnMajor::kStrideRank; - case LayoutTypeID::kRowMajor: return cutlass::layout::RowMajor::kStrideRank; + case LayoutTypeID::kColumnMajor: + return cutlass::layout::ColumnMajor::kStrideRank; + case LayoutTypeID::kRowMajor: + return cutlass::layout::RowMajor::kStrideRank; case LayoutTypeID::kColumnMajorInterleavedK2: + return cutlass::layout::ColumnMajorInterleaved<2>::kStrideRank; case LayoutTypeID::kRowMajorInterleavedK2: + return cutlass::layout::RowMajorInterleaved<2>::kStrideRank; case LayoutTypeID::kColumnMajorInterleavedK4: + return cutlass::layout::ColumnMajorInterleaved<4>::kStrideRank; case LayoutTypeID::kRowMajorInterleavedK4: + return cutlass::layout::RowMajorInterleaved<4>::kStrideRank; case LayoutTypeID::kColumnMajorInterleavedK16: + return cutlass::layout::ColumnMajorInterleaved<16>::kStrideRank; case LayoutTypeID::kRowMajorInterleavedK16: + return cutlass::layout::RowMajorInterleaved<16>::kStrideRank; case LayoutTypeID::kColumnMajorInterleavedK32: + return cutlass::layout::ColumnMajorInterleaved<32>::kStrideRank; case LayoutTypeID::kRowMajorInterleavedK32: + return cutlass::layout::RowMajorInterleaved<32>::kStrideRank; case LayoutTypeID::kColumnMajorInterleavedK64: - case LayoutTypeID::kRowMajorInterleavedK64: return 1; + return cutlass::layout::ColumnMajorInterleaved<64>::kStrideRank; + case LayoutTypeID::kRowMajorInterleavedK64: + return cutlass::layout::RowMajorInterleaved<64>::kStrideRank; case LayoutTypeID::kTensorNCHW: - case LayoutTypeID::kTensorNHWC: return 3; - case LayoutTypeID::kTensorNDHWC: return 4; - default : throw std::runtime_error("Unsupported LayoutTypeID in LayoutType::get_stride_rank"); + return cutlass::layout::TensorNCHW::kStrideRank; + case LayoutTypeID::kTensorNHWC: + return cutlass::layout::TensorNHWC::kStrideRank; + case LayoutTypeID::kTensorNDHWC: + return cutlass::layout::TensorNDHWC::kStrideRank; + case LayoutTypeID::kTensorNC32HW32: + return cutlass::layout::TensorNCxHWx<32>::kStrideRank; + case LayoutTypeID::kTensorNC64HW64: + return cutlass::layout::TensorNCxHWx<64>::kStrideRank; + case LayoutTypeID::kTensorC32RSK32: + return cutlass::layout::TensorCxRSKx<32>::kStrideRank; + case LayoutTypeID::kTensorC64RSK64: + return cutlass::layout::TensorCxRSKx<64>::kStrideRank; + default: + throw std::runtime_error("Unsupported LayoutTypeID in LayoutType::get_stride_rank"); } } @@ -624,6 +656,136 @@ SplitKMode from_string(std::string const &str) { } ///////////////////////////////////////////////////////////////////////////////////////////////// +static struct { + char const *text; + char const *pretty; + ConvModeID enumerant; +} +ConvModeID_enumerants[] = { + {"cross", "", ConvModeID::kCrossCorrelation}, + {"conv", "", ConvModeID::kConvolution}, +}; + +/// Converts a ConvModeID enumerant to a string +char const *to_string(ConvModeID type, bool pretty) { + + for (auto const & possible : ConvModeID_enumerants) { + if (type == possible.enumerant) { + if (pretty) { + return possible.pretty; + } + else { + return possible.text; + } + } + } + + return pretty ? "Invalid" : "invalid"; +} + +/// Converts a ConvModeID enumerant from a string +template <> +ConvModeID from_string(std::string const &str) { + + for (auto const & possible : ConvModeID_enumerants) { + if ((str.compare(possible.text) == 0) || + (str.compare(possible.pretty) == 0)) { + return possible.enumerant; + } + } + + return ConvModeID::kInvalid; +} + + +static struct { + char const *text; + char const *pretty; + IteratorAlgorithmID enumerant; +} +IteratorAlgorithmID_enumerants[] = { + {"none", "", IteratorAlgorithmID::kNone}, + {"analytic", "", IteratorAlgorithmID::kAnalytic}, + {"optimized", "", IteratorAlgorithmID::kOptimized}, +}; + +/// Converts a ConvModeID enumerant to a string +char const *to_string(IteratorAlgorithmID type, bool pretty) { + + for (auto const & possible : IteratorAlgorithmID_enumerants) { + if (type == possible.enumerant) { + if (pretty) { + return possible.pretty; + } + else { + return possible.text; + } + } + } + + return pretty ? "Invalid" : "invalid"; +} + +/// Converts a ConvModeID enumerant from a string +template <> +IteratorAlgorithmID from_string(std::string const &str) { + + for (auto const & possible : IteratorAlgorithmID_enumerants) { + if ((str.compare(possible.text) == 0) || + (str.compare(possible.pretty) == 0)) { + return possible.enumerant; + } + } + + return IteratorAlgorithmID::kInvalid; +} +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static struct { + char const *text; + char const *pretty; + ConvKind enumerant; +} +ConvKind_enumerants[] = { + {"unknown", "", ConvKind::kUnknown}, + {"fprop", "", ConvKind::kFprop}, + {"dgrad", "", ConvKind::kDgrad}, + {"wgrad", "", ConvKind::kWgrad}, +}; + +/// Converts a ConvKind enumerant to a string +char const *to_string(ConvKind type, bool pretty) { + + for (auto const & possible : ConvKind_enumerants) { + if (type == possible.enumerant) { + if (pretty) { + return possible.pretty; + } + else { + return possible.text; + } + } + } + + return pretty ? "Invalid" : "invalid"; +} + + +/// Converts a ConvKind enumerant from a string +template <> +ConvKind from_string(std::string const &str) { + + for (auto const & possible : ConvKind_enumerants) { + if ((str.compare(possible.text) == 0) || + (str.compare(possible.pretty) == 0)) { + return possible.enumerant; + } + } + + return ConvKind::kInvalid; +} +/////////////////////////////////////////////////////////////////////////////////////////////////// + /// Lexical cast a string to a byte array. Returns true if cast is successful or false if invalid. bool lexical_cast(std::vector &bytes, NumericTypeID type, std::string const &str) { int size_bytes = sizeof_bits(type) / 8; @@ -1224,5 +1386,3 @@ bool cast_from_double(std::vector &bytes, NumericTypeID type, double sr } // namespace cutlass /////////////////////////////////////////////////////////////////////////////////////////////////// - - diff --git a/tools/profiler/CMakeLists.txt b/tools/profiler/CMakeLists.txt index 52baacb1a..3ac944a9f 100644 --- a/tools/profiler/CMakeLists.txt +++ b/tools/profiler/CMakeLists.txt @@ -34,9 +34,12 @@ set(CUTLASS_TOOLS_PROFILER_SOURCES src/device_allocation.cu src/device_context.cu src/cublas_helpers.cpp + src/cudnn_helpers.cpp src/problem_space.cpp src/operation_profiler.cu src/gemm_operation_profiler.cu + src/conv2d_operation_profiler.cu + src/conv3d_operation_profiler.cu src/sparse_gemm_operation_profiler.cu ) @@ -58,7 +61,7 @@ set_target_properties(cutlass_profiler PROPERTIES EXPORT_NAME profiler) target_include_directories( cutlass_profiler PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src # Source directory + ${CMAKE_CURRENT_LIST_DIR}/src ) # @@ -71,6 +74,7 @@ target_link_libraries( cutlass_lib cutlass_tools_util_includes $<$:nvidia::cublas> + $<$:nvidia::cudnn> cudart ) @@ -79,3 +83,16 @@ install( EXPORT NvidiaCutlass RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) + +set(CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_GEMM --operation=Gemm --providers=cutlass --verification-providers=cublas,device --junit-output=test_cutlass_profiler_gemm) +set(CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_CONV2D --operation=Conv2d --providers=cutlass --verification-providers=cudnn,device --junit-output=test_cutlass_profiler_conv2d) +set(CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_CONV3D --operation=Conv3d --providers=cutlass --verification-providers=cudnn,device,host --junit-output=test_cutlass_profiler_conv3d) +cutlass_add_executable_tests( + test_profiler cutlass_profiler + DEPENDEES test_all + TEST_COMMAND_OPTIONS + CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_GEMM + CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_CONV2D + CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_CONV3D + DISABLE_EXECUTABLE_INSTALL_RULE + ) diff --git a/tools/profiler/src/conv2d_operation_profiler.cu b/tools/profiler/src/conv2d_operation_profiler.cu new file mode 100644 index 000000000..4b9153571 --- /dev/null +++ b/tools/profiler/src/conv2d_operation_profiler.cu @@ -0,0 +1,1468 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Convolution 2D profiling +*/ + +#include +#include +#include +#include + +#include "cutlass/core_io.h" + +#include "conv2d_operation_profiler.h" +#include "gpu_timer.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// +using namespace cutlass::library; + +namespace cutlass { +namespace profiler { + + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Ctor +Conv2dOperationProfiler::Conv2dOperationProfiler(Options const &options): + OperationProfiler( + options, + library::OperationKind::kConv2d, + { + {ArgumentTypeID::kEnumerated, {"conv_kind"}, "Convolutional operator (fprop, dgrad, wgrad)"}, + {ArgumentTypeID::kInteger, {"n", "input_n"}, "Input N dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"h", "input_h"}, "Input H dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"w", "input_w"}, "Input W dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"c", "input_c"}, "Input C dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"k", "filter_k"}, "Filter K dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"r", "filter_r"}, "Filter R dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"s", "filter_s"}, "Filter S dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"p", "output_p"}, "Output P dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"q", "output_q"}, "Output Q dimension of the Conv2d problem space"}, + {ArgumentTypeID::kInteger, {"pad_h"}, "Padding in H direction"}, + {ArgumentTypeID::kInteger, {"pad_w"}, "Padding in W direction"}, + {ArgumentTypeID::kInteger, {"stride_h"}, "Stride in H direction"}, + {ArgumentTypeID::kInteger, {"stride_w"}, "Stride in W direction"}, + {ArgumentTypeID::kInteger, {"dilation_h"}, "Dilation in H direction"}, + {ArgumentTypeID::kInteger, {"dilation_w"}, "Dilation in W direction"}, + {ArgumentTypeID::kTensor, {"Activation"}, "Tensor storing the Activation operand"}, + {ArgumentTypeID::kTensor, {"Filter"}, "Tensor storing the Filter operand"}, + {ArgumentTypeID::kTensor, {"Output"}, "Tensor storing the Output operand"}, + {ArgumentTypeID::kEnumerated, {"conv_mode"}, "Convolution filter mode (conv, cross)"}, + {ArgumentTypeID::kEnumerated, {"iterator_algorithm", "iterator_algo"}, "Convolution iterator algorithm (analytic, optimized)"}, + {ArgumentTypeID::kScalar, {"alpha", "epilogue::alpha"}, "Epilogue scalar alpha"}, + {ArgumentTypeID::kScalar, {"beta", "epilogue::beta"}, "Epilogue scalar beta"}, + {ArgumentTypeID::kEnumerated, {"split_k_mode", "split-k-mode"}, "SplitK mode for serial or parallel reduction (serial, parallel)"}, + {ArgumentTypeID::kInteger, {"split_k_slices", "split-k-slices"}, "Number of partitions of K dimension"}, + {ArgumentTypeID::kEnumerated, {"eq_gemm_provider", "eq-gemm-provider"}, "Enable profiling equivalent gemm by the following providers (cutlass)"}, + }, + { library::Provider::kReferenceDevice, library::Provider::kReferenceHost, library::Provider::kCUDNN } + ) { + + description_ = " Conv2d operation. Output(Tensor4D) = alpha * Input(Tensor4D) * Filter(Tensor4D) + beta * Input(Tensor4D)"; + +} + +/// Destructor +Conv2dOperationProfiler::~Conv2dOperationProfiler() { + +} + + +/// Prints usage statement for the math function +void Conv2dOperationProfiler::print_usage(std::ostream &out) const { + out << "Conv2d" << "\n\n"; + + OperationProfiler::print_usage(out); +} + +/// Prints examples +void Conv2dOperationProfiler::print_examples(std::ostream &out) const { + + out << "\nExamples:\n\n" + << "Profile a particular convolution (specify all the convolution parameters):\n" + << " $ cutlass_profiler --operation=Conv2d" + " --Activation=f16:nhwc --Filter=f16:nhwc --Output=f16 --accumulator-type=f32" + " --n=32 --h=14 --w=14 --c=8 --k=64 --r=3 --s=3" + " --pad_h=1 --pad_w=1" + " --stride::h=1 --stride::w=1" + " --dilation::h=1 --dilation::w=1\n\n"; +} + +#if 0 +// used this for debugging +static std::string byte_string(std::vector const &bytes) { + std::stringstream ss; + + ss << "0x"; + + for (size_t idx = bytes.size(); idx > 0; --idx) { + ss << std::hex << std::setw(2) << std::setfill('0') << uint32_t(bytes.at(idx - 1)); + } + + return ss.str(); +} +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Total number of bytes loaded +int64_t Conv2dOperationProfiler::Conv2dProblem::bytes( + library::ConvDescription const &operation_desc) const { + + cutlass::gemm::GemmCoord mnk = eq_gemm_size(operation_desc.conv_kind); + + // Input bytes read and Output bytes written for the gemm problem + int64_t bytes_ = + int64_t(library::sizeof_bits(operation_desc.A.element) * mnk.m() / 8) * mnk.k() + + int64_t(library::sizeof_bits(operation_desc.B.element) * mnk.n() / 8) * mnk.k() + + int64_t(library::sizeof_bits(operation_desc.C.element) * mnk.m() / 8) * mnk.n(); + + // Set is_beta_zero true if beta is zero + bool is_beta_zero = std::all_of(beta.begin(), beta.end(), [](uint8_t i) { return i==0; }); + + // Output bytes read for the gemm problem for non-zero beta values + if (!is_beta_zero) { + bytes_ += int64_t(library::sizeof_bits(operation_desc.C.element) * mnk.m() / 8) * mnk.n(); + } + + return bytes_; +} + +/// Total number of flops computed +int64_t Conv2dOperationProfiler::Conv2dProblem::flops( + library::ConvDescription const &operation_desc) const { + + cutlass::gemm::GemmCoord mnk = eq_gemm_size(operation_desc.conv_kind); + + int64_t flops_mainloop_ = int64_t(mnk.m()) * mnk.n() * mnk.k() * 2; + int64_t flops_epilogue_ = int64_t(mnk.m()) * int64_t(mnk.n()) * 2; + + // Adjust mainloop flop for dgrad strided + if (operation_desc.conv_kind == library::ConvKind::kDgrad) { + flops_mainloop_ = flops_mainloop_ / (stride_h * stride_w); + } + int64_t flops_total_ = flops_mainloop_ + flops_epilogue_; + + //complex-valued support + switch (operation_desc.tile_description.math_instruction.math_operation) { + case library::MathOperationID::kMultiplyAddComplex: + flops_total_ *=4; + break; + + default: break; + } + + return flops_total_; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Extracts the problem dimensions +Status Conv2dOperationProfiler::initialize_configuration( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + library::ConvDescription const &operation_desc = + static_cast(operation->description()); + + if (!arg_as_int(problem_.n, "n", problem_space, problem)) { + // default value + problem_.n = 1; + } + + if (!arg_as_int(problem_.h, "h", problem_space, problem)) { + // default value + problem_.h = 16; + } + + if (!arg_as_int(problem_.w, "w", problem_space, problem)) { + // default value + problem_.w = 16; + } + + if (!arg_as_int(problem_.c, "c", problem_space, problem)) { + // default value + problem_.c = 64; + } + + if (!arg_as_int(problem_.k, "k", problem_space, problem)) { + // default value + problem_.k = 64; + } + + if (!arg_as_int(problem_.r, "r", problem_space, problem)) { + // default value + problem_.r = 3; + } + + if (!arg_as_int(problem_.s, "s", problem_space, problem)) { + // default value + problem_.s = 3; + } + + if (!arg_as_int(problem_.pad_h, "pad_h", problem_space, problem)) { + // default value + problem_.pad_h = 1; + } + + if (!arg_as_int(problem_.pad_w, "pad_w", problem_space, problem)) { + // default value + problem_.pad_w = 1; + } + + if (!arg_as_int(problem_.stride_h, "stride_h", problem_space, problem)) { + // default value + problem_.stride_h = 1; + } + + if (!arg_as_int(problem_.stride_w, "stride_w", problem_space, problem)) { + // default value + problem_.stride_w = 1; + } + + if (!arg_as_int(problem_.dilation_h, "dilation_h", problem_space, problem)) { + // default value + problem_.dilation_h = 1; + } + + if (!arg_as_int(problem_.dilation_w, "dilation_w", problem_space, problem)) { + // default value + problem_.dilation_w = 1; + } + + //////////////////////// Convolution output dimensions p and q //////////////////////// + // Cutlass convolutions support arbitrary output sizes and not constriant by // + // input, filter, padding, striding, dilation sizes. // + // cuDNN sets the output dimensions (p, q) using following equations: // + // // + // output = div_up(input + 2 * pad - ((filter - 1) * dilation + 1) + 1, stride) // + // where; div_up(a, b) : (a - 1)/b + 1 // + // // + // Thus, when output p and q dimensions are unspecified by the user // + // cutlass profiler sets p and q which are cuDNN compliant. // + // // + //////////////////////////////////////////////////////////////////////////////////////// + // set convolution output p + if (!arg_as_int(problem_.p, "p", problem_space, problem)) { + // default value (set using cudnn formula for output height, when p is not provided) + problem_.p = ( + problem_.h + + 2 * problem_.pad_h - + ((problem_.r - 1) * problem_.dilation_h + 1) + ) / (problem_.stride_h) + + 1; + } + + // set convolution output q + if (!arg_as_int(problem_.q, "q", problem_space, problem)) { + // default value (set using cudnn formula for output width, when q is not provided) + problem_.q = ( + problem_.w + + 2 * problem_.pad_w - + ((problem_.s - 1) * problem_.dilation_w + 1) + ) / (problem_.stride_w) + + 1; + } + ///////////////////////////////////////////////////////////////////////////////////////// + + + if (!arg_as_SplitKModeID(problem_.split_k_mode, "split_k_mode", problem_space, problem)) { + // default value + problem_.split_k_mode = library::SplitKMode::kSerial; + } + + if (!arg_as_int(problem_.split_k_slices, "split_k_slices", problem_space, problem)) { + // default value + problem_.split_k_slices = 1; + } + + if (!arg_as_ConvModeID(problem_.conv_mode, "conv_mode", problem_space, problem)) { + // default value + problem_.conv_mode = library::ConvModeID::kCrossCorrelation; + } + + if (!arg_as_ProviderID(problem_.eq_gemm_provider, "eq_gemm_provider", problem_space, problem)) { + // default value + problem_.eq_gemm_provider = library::Provider::kNone; + } + + if (!conv_kind_satisfies(operation_desc.conv_kind, "conv_kind", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!iterator_algorithm_satisfies(operation_desc.iterator_algorithm, "iterator_algorithm", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!tensor_description_satisfies(operation_desc.activation(), "Activation", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!tensor_description_satisfies(operation_desc.filter(), "Filter", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!tensor_description_satisfies(operation_desc.output(), "Output", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!arg_as_scalar( + problem_.alpha, + operation_desc.element_epilogue, + "alpha", + problem_space, + problem)) { + + if (!cast_from_double(problem_.alpha, operation_desc.element_epilogue, 1)) { + return Status::kErrorInternal; + } + } + + if (!arg_as_scalar( + problem_.beta, + operation_desc.element_epilogue, + "beta", + problem_space, + problem)) { + + if (!cast_from_double(problem_.beta, operation_desc.element_epilogue, 0)) { + return Status::kErrorInternal; + } + } + + // initialize library::Conv2dConfiguration + conv_workspace_.configuration.problem_size = conv::Conv2dProblemSize( + int(problem_.n), + int(problem_.h), + int(problem_.w), + int(problem_.c), + int(problem_.k), + int(problem_.r), + int(problem_.s), + int(problem_.p), + int(problem_.q), + int(problem_.pad_h), + int(problem_.pad_w), + int(problem_.stride_h), + int(problem_.stride_w), + int(problem_.dilation_h), + int(problem_.dilation_w), + static_cast(static_cast(problem_.conv_mode)), + int(problem_.split_k_slices), + 1 // groups + ); + + conv_workspace_.configuration.split_k_mode = static_cast(static_cast(problem_.split_k_mode)); + + conv_workspace_.configuration.layout_activations.stride() = make_Coord( + int(problem_.c), + int(problem_.w) * int(problem_.c), + int(problem_.h) * int(problem_.w) * int(problem_.c) + ); + + conv_workspace_.configuration.layout_filters.stride() = make_Coord( + int(problem_.c), + int(problem_.s) * int(problem_.c), + int(problem_.r) * int(problem_.s) * int(problem_.c) + ); + + conv_workspace_.configuration.layout_output.stride() = make_Coord( + int(problem_.k), + int(problem_.q) * int(problem_.k), + int(problem_.q) * int(problem_.p) * int(problem_.k) + ); + + + // initialize library::ConvArguments + conv_workspace_.arguments.A = nullptr; + conv_workspace_.arguments.B = nullptr; + conv_workspace_.arguments.C = nullptr; + conv_workspace_.arguments.D = nullptr; + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + // initialize reduction operation for parallel splitKMode + if(conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + if(!initialize_reduction_configuration_(options, report, device_context, operation, problem_space, problem)) { + return Status::kErrorInternal; + } + } + + initialize_result_(this->model_result_, options, operation_desc, problem_space); + + return operation->can_implement(&conv_workspace_.configuration, &conv_workspace_.arguments); +} + +/// Initializes the performance result +void Conv2dOperationProfiler::initialize_result_( + PerformanceResult &result, + Options const &options, + library::ConvDescription const &operation_desc, + ProblemSpace const &problem_space) { + + result.provider = library::Provider::kCUTLASS; + result.disposition = Disposition::kNotRun; + result.status = Status::kSuccess; + result.operation_name = operation_desc.name; + + result.arguments.resize(problem_space.rank()); + + set_argument(result, "Activation", problem_space, + std::string(library::to_string(operation_desc.activation().element)) + + ":" + library::to_string(operation_desc.activation().layout)); + + set_argument(result, "Filter", problem_space, + std::string(library::to_string(operation_desc.filter().element)) + + ":" + library::to_string(operation_desc.filter().layout)); + + set_argument(result, "Output", problem_space, + std::string(library::to_string(operation_desc.output().element)) + + ":" + library::to_string(operation_desc.output().layout)); + + set_argument(result, "conv_kind", problem_space, library::to_string(operation_desc.conv_kind)); + + set_argument(result, "iterator_algorithm", problem_space, std::string(library::to_string(operation_desc.iterator_algorithm))); + + set_argument(result, "n", problem_space, problem_.n); + set_argument(result, "h", problem_space, problem_.h); + set_argument(result, "w", problem_space, problem_.w); + set_argument(result, "c", problem_space, problem_.c); + + set_argument(result, "k", problem_space, problem_.k); + set_argument(result, "r", problem_space, problem_.r); + set_argument(result, "s", problem_space, problem_.s); + + set_argument(result, "p", problem_space, problem_.p); + set_argument(result, "q", problem_space, problem_.q); + + set_argument(result, "pad_h", problem_space, problem_.pad_h); + set_argument(result, "pad_w", problem_space, problem_.pad_w); + + set_argument(result, "stride_h", problem_space, problem_.stride_h); + set_argument(result, "stride_w", problem_space, problem_.stride_w); + + set_argument(result, "dilation_h", problem_space, problem_.dilation_h); + set_argument(result, "dilation_w", problem_space, problem_.dilation_w); + + set_argument(result, "split_k_mode", problem_space, + std::string(library::to_string(problem_.split_k_mode))); + set_argument(result, "split_k_slices", problem_space, problem_.split_k_slices); + + set_argument(result, "conv_mode", problem_space, + std::string(library::to_string(problem_.conv_mode))); + + set_argument(result, "alpha", problem_space, + library::lexical_cast(problem_.alpha, operation_desc.element_epilogue)); + + set_argument(result, "beta", problem_space, + library::lexical_cast(problem_.beta, operation_desc.element_epilogue)); + + set_argument(result, "eq_gemm_provider", problem_space, + std::string(library::to_string(problem_.eq_gemm_provider))); + + OperationProfiler::initialize_result_(result, operation_desc, problem_space); + + // Bytes of activation, filter, and output tensors + int64_t activation_bytes = int64_t(library::sizeof_bits(operation_desc.activation().element) / 8) * + conv_workspace_.configuration.problem_size.activation_size(); + + int64_t filter_bytes = int64_t(library::sizeof_bits(operation_desc.filter().element) / 8) * + conv_workspace_.configuration.problem_size.filter_size(); + + int64_t output_bytes = int64_t(library::sizeof_bits(operation_desc.output().element) / 8) * + conv_workspace_.configuration.problem_size.output_size(); + + // Bytes of activation, filter, and output tensors + result.bytes = problem_.bytes(operation_desc); + + // Theoritical flops required for the computation + result.flops = problem_.flops(operation_desc); + + // Measured runtime + result.runtime = 0; + +} + +/// Initialize reduction problem dimenstions and library::Operation +bool Conv2dOperationProfiler::initialize_reduction_configuration_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + library::ConvDescription const &conv_desc = + static_cast(operation->description()); + + library::ConvKind const &conv_kind = conv_desc.conv_kind; + + if (!cast_from_double(problem_.alpha_one, conv_desc.element_epilogue, 1)) { + return false; + } + + if (!cast_from_double(problem_.beta_zero, conv_desc.element_epilogue, 0)) { + return false; + } + + /// This chooses the appropriate stride element of the row-major C tensor. + int const & tensor_c_stride_idx = (conv_kind == library::ConvKind::kWgrad ? 2 : 0); + + /// intialize library::ReductionConfiguration + conv_workspace_.reduction_configuration.problem_size = problem_.eq_gemm_size(conv_kind).mn(); + conv_workspace_.reduction_configuration.partitions = int(problem_.split_k_slices); + conv_workspace_.reduction_configuration.partition_stride = problem_.eq_gemm_size(conv_kind).mn().product(); + conv_workspace_.reduction_configuration.ldw = conv_workspace_.configuration.layout_c(conv_kind).stride()[tensor_c_stride_idx]; + conv_workspace_.reduction_configuration.lds = conv_workspace_.configuration.layout_c(conv_kind).stride()[tensor_c_stride_idx]; + conv_workspace_.reduction_configuration.ldd = conv_workspace_.configuration.layout_c(conv_kind).stride()[tensor_c_stride_idx]; + + // find reduction operation + library::ReductionFunctionalKey reduction_key( + library::Provider::kCUTLASS, + conv_desc.tile_description.math_instruction.element_accumulator, // element workspace + conv_desc.tile_description.math_instruction.element_accumulator, // element accumulator + conv_desc.C.element, // element output + conv_desc.element_epilogue // element compute + ); + +#if 0// debug print to check which reduction instance is selected + std::cout << reduction_key << "\n"; +#endif + auto reduction_it = Singleton::get().operation_table.reduction_operations.find(reduction_key); + + if(reduction_it == Singleton::get().operation_table.reduction_operations.end()) { + + return false; + } + + // initialize reduction operation required for parallel split-k conv2d operator + reduction_op_ = reduction_it->second; + + // reduction operation found and initialized + return true; +} + + +/// Initializes workspace +Status Conv2dOperationProfiler::initialize_workspace( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + // initialize conv2d underlying operation to handle parallel reduction + library::Operation const* underlying_operation = operation; + + if(conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + if (!(underlying_operation = library::find_conv_operation_for_parallel_reduction(operation))) { + return Status::kErrorNotSupported; + } + } + + library::ConvDescription const &operation_desc = + static_cast(underlying_operation->description()); + + // Compute the number of copies of the problem to avoid L2 camping. + if (!options.profiling.workspace_count) { + int64_t bytes = problem_.bytes(operation_desc); + if (bytes < 3 * int64_t(options.device.properties.l2CacheSize)) { + conv_workspace_.problem_count = + 1 + int((3 * int64_t(options.device.properties.l2CacheSize)) / bytes); + } + else { + conv_workspace_.problem_count = 1; + } + } + else { + conv_workspace_.problem_count = options.profiling.workspace_count; + } + + + if (options.execution_mode != ExecutionMode::kDryRun) { + + conv_workspace_.A = device_context.allocate_tensor( + options, + "A", + operation_desc.A.element, + operation_desc.A.layout, + problem_.extent_a(operation_desc.conv_kind), + conv_workspace_.stride_a(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + conv_workspace_.B = device_context.allocate_tensor( + options, + "B", + operation_desc.B.element, + operation_desc.B.layout, + problem_.extent_b(operation_desc.conv_kind), + conv_workspace_.stride_b(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + conv_workspace_.C = device_context.allocate_tensor( + options, + "C", + operation_desc.C.element, + operation_desc.C.layout, + problem_.extent_c(operation_desc.conv_kind), + conv_workspace_.stride_c(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + conv_workspace_.Computed = device_context.allocate_tensor( + "D", + operation_desc.C.element, + operation_desc.C.layout, + problem_.extent_c(operation_desc.conv_kind), + conv_workspace_.stride_c(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + conv_workspace_.Reference = device_context.allocate_tensor( + "Reference", + operation_desc.C.element, + operation_desc.C.layout, + problem_.extent_c(operation_desc.conv_kind), + conv_workspace_.stride_c(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + } + + // + // Initialize the CUTLASS operation + // + Status status = Status::kSuccess; + + if (options.profiling.provider_enabled(library::Provider::kCUTLASS)) { + + if (options.execution_mode != ExecutionMode::kDryRun) { + + uint64_t workspace_size = underlying_operation->get_host_workspace_size(&conv_workspace_.configuration); + conv_workspace_.host_workspace.resize(workspace_size, 0); + + workspace_size = underlying_operation->get_device_workspace_size(&conv_workspace_.configuration); + conv_workspace_.device_workspace.reset(library::NumericTypeID::kU8, workspace_size); + + status = underlying_operation->initialize( + &conv_workspace_.configuration, + conv_workspace_.host_workspace.data(), + conv_workspace_.device_workspace.data()); + + if (status != Status::kSuccess) { + return status; + } + + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + workspace_size = reduction_op_->get_host_workspace_size(&conv_workspace_.reduction_configuration); + conv_workspace_.reduction_host_workspace.resize(workspace_size, 0); + + status = reduction_op_->initialize( + &conv_workspace_.reduction_configuration, + conv_workspace_.reduction_host_workspace.data(), + nullptr); + + if (status != Status::kSuccess) { + return status; + } + } + } + + // + // If CUTLASS is enabled, generate a result for it + // + results_.push_back(model_result_); + results_.back().provider = library::Provider::kCUTLASS; + results_.back().op_kind = library::OperationKind::kConv2d; + results_.back().disposition = Disposition::kNotRun; + + for(auto provider : verification_providers_) { + results_.back().verification_map[provider] = Disposition::kNotRun; + } + } + + return status; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Verifies CUTLASS against references +bool Conv2dOperationProfiler::verify_cutlass( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + if (!options.profiling.provider_enabled(library::Provider::kCUTLASS)) { + return true; + } + + if (options.execution_mode == ExecutionMode::kDryRun) { + return true; + } + + cudaError_t result; + + // Initialize structure containing Conv2d arguments + conv_workspace_.arguments.A = conv_workspace_.A->data(); + conv_workspace_.arguments.B = conv_workspace_.B->data(); + conv_workspace_.arguments.C = conv_workspace_.C->data(); + conv_workspace_.arguments.D = conv_workspace_.Computed->data(); + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + conv_workspace_.Computed->copy_from_device(conv_workspace_.C->data()); + + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + // update library::ConvArguments for parallel split-k reduction + conv_workspace_.arguments.D = conv_workspace_.device_workspace.data(); + conv_workspace_.arguments.alpha = problem_.alpha_one.data(); + conv_workspace_.arguments.beta = problem_.beta_zero.data(); + + /// intialize library::ReductionArguments + conv_workspace_.reduction_arguments.workspace = conv_workspace_.device_workspace.data(); + conv_workspace_.reduction_arguments.source = conv_workspace_.C->data(); + conv_workspace_.reduction_arguments.destination = conv_workspace_.Computed->data(); + conv_workspace_.reduction_arguments.alpha = problem_.alpha.data(); + conv_workspace_.reduction_arguments.beta = problem_.beta.data(); + conv_workspace_.reduction_arguments.pointer_mode = library::ScalarPointerMode::kHost; + } + + // + // Run the CUTLASS operation + // + // initialize conv2d underlying operation to handle parallel reduction + library::Operation const* underlying_operation = operation; + + if(conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + if (!(underlying_operation = library::find_conv_operation_for_parallel_reduction(operation))) { + results_.back().disposition = Disposition::kFailed; + return false; + } + } + +#if 0 + std::cout << "profiling : " << std::endl + << "conv2d : " << operation->description().name << std::endl + << "underlying conv2d : " << underlying_operation->description().name << std::endl + << "reduction : " << reduction_op_->description().name << std::endl; +#endif + + // run cutlass conv2d operation + results_.back().status = underlying_operation->run( + &conv_workspace_.arguments, + conv_workspace_.host_workspace.data(), + conv_workspace_.device_workspace.data()); + + if (results_.back().status != Status::kSuccess) { + results_.back().disposition = Disposition::kFailed; + return false; + } + + // Run parallel reduction kernel for parallel split_k_mode + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + + results_.back().status = reduction_op_->run( + &conv_workspace_.reduction_arguments, + conv_workspace_.reduction_host_workspace.data(), + nullptr); + + if (results_.back().status != Status::kSuccess) { + results_.back().disposition = Disposition::kFailed; + return false; + } + + } + + // Synchronize before running device reference + result = cudaDeviceSynchronize(); + if (result != cudaSuccess) { + results_.back().disposition = Disposition::kFailed; + return false; + } + + // CUTLASS op ran the but not yet verified against any verification provider + results_.back().disposition = Disposition::kNotVerified; + + // + // Run verification providers + // + + if (options.verification.enabled) { + +#if CUTLASS_ENABLE_CUDNN + // Run verification cudnn reference + if (options.verification.provider_enabled(library::Provider::kCUDNN)) { + + // Guard against unsupported cases + auto const & conv_desc = static_cast(operation->description()); + + Status status = cudnn_satisfies(conv_desc, conv_workspace_.configuration); + + // Initialize reference data to the source data + conv_workspace_.Reference->copy_from_device(conv_workspace_.C->data()); + + if (status == Status::kSuccess) { + // call cudnn verification if supported + verify_with_cudnn_( + options, + report, + device_context, + operation, + problem_space, + problem); + } + + else if (status == Status::kErrorInvalidProblem) { + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kInvalidProblem; + } + + else { + // set verification map for cudnn to not supported + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kNotSupported; + } + } +#endif // #if CUTLASS_ENABLE_CUDNN + + // Run verification device reference + if (options.verification.provider_enabled(library::Provider::kReferenceDevice)) { + + // Restore reference data back to initial source data + conv_workspace_.Reference->copy_from_device(conv_workspace_.C->data()); + + verify_with_device_reference_( + options, + report, + device_context, + operation, + problem_space, + problem); + } + + // Run verification host reference + if (options.verification.provider_enabled(library::Provider::kReferenceHost)) { + + // Restore reference data back to initial source data + conv_workspace_.Reference->copy_from_device(conv_workspace_.C->data()); + + verify_with_host_reference_( + options, + report, + device_context, + operation, + problem_space, + problem); + } + + // Update disposition to worst case verification outcome among all + // verification providers which are supported + bool is_any_verification_run_passed = false; + for(auto &m : results_.back().verification_map) { + if(m.second == Disposition::kFailed || m.second == Disposition::kIncorrect) { + results_.back().disposition = m.second; + return true; + } + if(!is_any_verification_run_passed && m.second == Disposition::kPassed) { + is_any_verification_run_passed = true; + } + } + + if(is_any_verification_run_passed) { + results_.back().disposition = Disposition::kPassed; + } + } + + // Return true means continue profiling + return true; +} + + +/// Verifies CUTLASS against host reference +bool Conv2dOperationProfiler::verify_with_host_reference_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + Status status; + + // + // Find host reference operation using conv2d functional description key + // + library::OperationDescription const &desc = operation->description(); + + auto &conv_desc = static_cast(desc); + + library::ConvFunctionalKey conv2d_key( + library::Provider::kReferenceHost, + conv_desc.conv_kind, + conv_desc.A.element, + conv_desc.A.layout, + conv_desc.B.element, + conv_desc.B.layout, + conv_desc.C.element, + conv_desc.C.layout, + conv_desc.tile_description.math_instruction.element_accumulator, + conv_desc.element_epilogue); + +#if 0 // debug print to check which host refererence instance is selected + std::cout << conv2d_key << "\n"; +#endif + + auto operators_it = Singleton::get().operation_table.conv2d_operations.find(conv2d_key); + + if(operators_it == Singleton::get().operation_table.conv2d_operations.end()) { + + results_.back().verification_map[library::Provider::kReferenceHost] = Disposition::kNotRun; + return true; + } + + // conv2d host reference minimum cc is 0 (CPU) and no iterator algorithm + library::ConvPreferenceKey preference_key(0, library::IteratorAlgorithmID::kNone); + auto cc_it = operators_it->second.find(preference_key); + + if(cc_it == operators_it->second.end()) { + results_.back().verification_map[library::Provider::kReferenceHost] = Disposition::kNotRun; + return true; + } + + // host refernce has only one instances in Conv2dOperationVectorMap + library::Operation const *reference_op = cc_it->second[0]; + + // + // Copy input tensors A, B, and C from device to host buffers + // + conv_workspace_.host_tensor_a.resize(conv_workspace_.A->bytes()); + conv_workspace_.host_tensor_b.resize(conv_workspace_.B->bytes()); + conv_workspace_.host_tensor_c.resize(conv_workspace_.C->bytes()); + + conv_workspace_.A->copy_to_host(conv_workspace_.host_tensor_a.data()); + conv_workspace_.B->copy_to_host(conv_workspace_.host_tensor_b.data()); + conv_workspace_.C->copy_to_host(conv_workspace_.host_tensor_c.data()); + + // + // Initialize structure containing Conv2d arguments + // + conv_workspace_.arguments.A = conv_workspace_.host_tensor_a.data(); + conv_workspace_.arguments.B = conv_workspace_.host_tensor_b.data(); + conv_workspace_.arguments.C = conv_workspace_.host_tensor_c.data(); + conv_workspace_.arguments.D = conv_workspace_.host_tensor_c.data(); + + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + // + // Intialize host reference operation + // + std::vector host_workspace_reference_op; + + uint64_t workspace_size = reference_op->get_host_workspace_size(&conv_workspace_.configuration); + host_workspace_reference_op.resize(workspace_size, 0); + + reference_op->initialize( + &conv_workspace_.configuration, + host_workspace_reference_op.data()); + + // + // Run host reference operation + // + status = reference_op->run( + &conv_workspace_.arguments, + host_workspace_reference_op.data()); + + // Handle errors + if (status != Status::kSuccess) { + results_.back().verification_map[library::Provider::kReferenceHost] = Disposition::kNotVerified; + return true; + } + + // + // Copy host reference output to device memory for equality check on device + // + conv_workspace_.Reference->copy_from_host(conv_workspace_.arguments.D); + + // + // Verify results + // + results_.back().verification_map[library::Provider::kReferenceHost] = compare_tensors( + options, + *conv_workspace_.Computed, + *conv_workspace_.Reference, + conv_workspace_.Computed->batch_stride() + ); + + // Save workspace if incorrect + if (options.verification.save_workspace == SaveWorkspace::kIncorrect && + results_.back().verification_map[library::Provider::kReferenceHost] == Disposition::kIncorrect) { + + save_workspace( + device_context, + options, + static_cast(operation->description()), + library::Provider::kCUTLASS, + library::Provider::kReferenceHost); + } + + // Return true means continue profiling + return true; +} + + +/// Verifies CUTLASS against host reference +bool Conv2dOperationProfiler::verify_with_device_reference_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + Status status; + + // + // Find device reference operation using conv2d functional description key + // + library::OperationDescription const &desc = operation->description(); + + auto &conv_desc = static_cast(desc); + + library::ConvFunctionalKey conv2d_key( + library::Provider::kReferenceDevice, + conv_desc.conv_kind, + conv_desc.A.element, + conv_desc.A.layout, + conv_desc.B.element, + conv_desc.B.layout, + conv_desc.C.element, + conv_desc.C.layout, + conv_desc.tile_description.math_instruction.element_accumulator, + conv_desc.element_epilogue); + + auto operators_it = Singleton::get().operation_table.conv2d_operations.find(conv2d_key); + + if(operators_it == Singleton::get().operation_table.conv2d_operations.end()) { + + results_.back().verification_map[library::Provider::kReferenceDevice] = Disposition::kNotRun; + + return true; + } + + // conv2d device reference minimum cc is 50 and no iterator algorithm + library::ConvPreferenceKey preference_key(50, library::IteratorAlgorithmID::kNone); + auto cc_it = operators_it->second.find(preference_key); + + if(cc_it == operators_it->second.end()) { + results_.back().verification_map[library::Provider::kReferenceDevice] = Disposition::kNotRun; + + return true; + } + + // device refernce has only one instances in Conv2dOperationVectorMap + library::Operation const *reference_op = cc_it->second[0]; + + // + // Intialize device reference operation + // + std::vector host_workspace_reference_op; + + uint64_t workspace_size = reference_op->get_host_workspace_size(&conv_workspace_.configuration); + host_workspace_reference_op.resize(workspace_size, 0); + + reference_op->initialize( + &conv_workspace_.configuration, + host_workspace_reference_op.data()); + + // Initialize structure containing Conv2d arguments + conv_workspace_.arguments.A = conv_workspace_.A->data(); + conv_workspace_.arguments.B = conv_workspace_.B->data(); + conv_workspace_.arguments.C = conv_workspace_.C->data(); + conv_workspace_.arguments.D = conv_workspace_.Reference->data(); + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + // + // Run device reference operation + // + status = reference_op->run( + &conv_workspace_.arguments, + host_workspace_reference_op.data()); + + + // Handle errors + if (status != Status::kSuccess) { + results_.back().verification_map[library::Provider::kReferenceDevice] = Disposition::kNotVerified; + return true; + } + + // + // Verify results + // + results_.back().verification_map[library::Provider::kReferenceDevice] = compare_tensors( + options, + *conv_workspace_.Computed, + *conv_workspace_.Reference, + conv_workspace_.Computed->batch_stride() + ); + + // Save workspace if incorrect + if (options.verification.save_workspace == SaveWorkspace::kIncorrect && + results_.back().verification_map[library::Provider::kReferenceDevice] == Disposition::kIncorrect) { + + save_workspace( + device_context, + options, + static_cast(operation->description()), + library::Provider::kCUTLASS, + library::Provider::kReferenceDevice); + } + + // Return true means continue profiling + return true; +} + +/// Measures performance results +bool Conv2dOperationProfiler::profile( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + + if (options.profiling.provider_enabled(library::Provider::kCUTLASS)) { + + // Initialize structure containing Conv2d arguments + conv_workspace_.arguments.A = conv_workspace_.A->data(); + conv_workspace_.arguments.B = conv_workspace_.B->data(); + conv_workspace_.arguments.C = conv_workspace_.C->data(); + conv_workspace_.arguments.D = conv_workspace_.Computed->data(); + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + // update library::ConvArguments for parallel split-k reduction + conv_workspace_.arguments.D = conv_workspace_.device_workspace.data(); + conv_workspace_.arguments.alpha = problem_.alpha_one.data(); + conv_workspace_.arguments.beta = problem_.beta_zero.data(); + + /// intialize library::ReductionArguments + conv_workspace_.reduction_arguments.workspace = conv_workspace_.device_workspace.data(); + conv_workspace_.reduction_arguments.source = conv_workspace_.C->data(); + conv_workspace_.reduction_arguments.destination = conv_workspace_.Computed->data(); + conv_workspace_.reduction_arguments.alpha = problem_.alpha.data(); + conv_workspace_.reduction_arguments.beta = problem_.beta.data(); + conv_workspace_.reduction_arguments.pointer_mode = library::ScalarPointerMode::kHost; + } + + results_.back().status = profile_cutlass_( + results_.back().runtime, + options, + operation, + &conv_workspace_.arguments, + conv_workspace_.host_workspace.data(), + conv_workspace_.device_workspace.data() + ); + } + return true; + +} + +/// Method to profile a CUTLASS Operation +Status Conv2dOperationProfiler::profile_cutlass_( + double &runtime, + Options const &options, + library::Operation const *operation, + void *arguments, + void *host_workspace, + void *device_workspace) { + + GpuTimer timer; + + // initialize conv2d underlying operation to handle parallel reduction + library::Operation const* underlying_operation = operation; + + library::ConvArguments *conv_arguments = static_cast(arguments); + + if(conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + if (!(underlying_operation = library::find_conv_operation_for_parallel_reduction(operation))) { + return Status::kErrorNotSupported; + } + } + + // + // Optional sleep to limit power consumption and thermals + // + + sleep(options.profiling.sleep_duration); + + // + // Warmup loop + // + + Status status; + + for (int iteration = 0; iteration < options.profiling.warmup_iterations; ++iteration) { + + // Setup rotating workspace + int workspace_idx = options.profiling.warmup_iterations + iteration; + int problem_idx = (workspace_idx % conv_workspace_.problem_count); + + conv_arguments->A = conv_workspace_.A->batch_data(problem_idx); + conv_arguments->B = conv_workspace_.B->batch_data(problem_idx); + conv_arguments->C = conv_workspace_.C->batch_data(problem_idx); + conv_arguments->D = conv_workspace_.Computed->batch_data(problem_idx); + + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + // update library::ConvArguments for parallel split-k reduction + conv_arguments->D = conv_workspace_.device_workspace.data(); + + /// intialize library::ReductionArguments + conv_workspace_.reduction_arguments.workspace = conv_workspace_.device_workspace.data(); + conv_workspace_.reduction_arguments.source = conv_workspace_.C->batch_data(problem_idx); + conv_workspace_.reduction_arguments.destination = conv_workspace_.Computed->batch_data(problem_idx); + } + + // Run underlying conv2d operation + status = underlying_operation->run( + arguments, + host_workspace, + device_workspace); + + // Run parallel reduction kernel for parallel split_k_mode + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + + status = reduction_op_->run( + &conv_workspace_.reduction_arguments, + conv_workspace_.reduction_host_workspace.data(), + nullptr); + } + + if (status != Status::kSuccess) { + return status; + } + } + + // + // Initialize GPU timer + // + + timer.start(); + + // + // Profiling loop + // + + int Iterations = options.profiling.iterations; + + int iteration = 0; + for (; iteration < Iterations; ++iteration) { + + // Setup rotating workspace + int problem_idx = (iteration % conv_workspace_.problem_count); + + conv_arguments->A = conv_workspace_.A->batch_data(problem_idx); + conv_arguments->B = conv_workspace_.B->batch_data(problem_idx); + conv_arguments->C = conv_workspace_.C->batch_data(problem_idx); + conv_arguments->D = conv_workspace_.Computed->batch_data(problem_idx); + + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + // update library::ConvArguments for parallel split-k reduction + conv_arguments->D = conv_workspace_.device_workspace.data(); + + /// intialize library::ReductionArguments + conv_workspace_.reduction_arguments.workspace = conv_workspace_.device_workspace.data(); + conv_workspace_.reduction_arguments.source = conv_workspace_.C->batch_data(problem_idx); + conv_workspace_.reduction_arguments.destination = conv_workspace_.Computed->batch_data(problem_idx); + } + + // Run underlying conv2d operation + status = underlying_operation->run( + arguments, + host_workspace, + device_workspace); + + // Run parallel reduction kernel for parallel split_k_mode + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + + status = reduction_op_->run( + &conv_workspace_.reduction_arguments, + conv_workspace_.reduction_host_workspace.data(), + nullptr); + } + + if (status != Status::kSuccess) { + return status; + } + } + + // + // Wait for completion + // + + timer.stop_and_wait(); + + // + // Update performance result + // + + runtime = timer.duration(iteration); + + return status; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +#if CUTLASS_ENABLE_CUDNN + +/// Verifies CUTLASS against cudnn reference +bool Conv2dOperationProfiler::verify_with_cudnn_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + auto &conv_desc = static_cast(operation->description()); + + // + // Construct cudnn operators + // + + CudnnCreate handle; + cudnnStatus_t status = handle.get_cudnn_create_status(); + + if (status != CUDNN_STATUS_SUCCESS) { + + results_.back().verification_map[library::Provider::kCUDNN] = get_cutlass_disposition(status); + return true; + } + + // + // Initialize state + // + + // Initialize structure containing Conv2d arguments + conv_workspace_.arguments.A = conv_workspace_.A->data(); + conv_workspace_.arguments.B = conv_workspace_.B->data(); + conv_workspace_.arguments.D = conv_workspace_.Reference->data(); + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + // cuDNN does not support four tensor arguments, so we copy the tensor C data into + // tensor D. + conv_workspace_.Reference->copy_from_device(conv_workspace_.C->data()); + conv_workspace_.arguments.C = conv_workspace_.arguments.D; + + try { + + // + // Construct dispatcher to cudnn operator + // + + detail::cudnnConvDispatcher conv_op( + conv_desc, + conv_workspace_.configuration, + conv_workspace_.arguments, + handle + ); + + if (conv_op.status != Status::kSuccess) { + if (conv_op.status == Status::kErrorNotSupported) { + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kNotSupported; + + } else { + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kFailed; + } + return true; + } + + + status = conv_op(handle); + + // Handle errors + if (status != CUDNN_STATUS_SUCCESS) { + + results_.back().verification_map[library::Provider::kCUDNN] = get_cutlass_disposition(status); + return true; + } + + // + // Verify results + // + + results_.back().verification_map[library::Provider::kCUDNN] = compare_tensors( + options, + *conv_workspace_.Computed, + *conv_workspace_.Reference, + conv_workspace_.Computed->batch_stride() + ); + + // Save workspace if incorrect + if (options.verification.save_workspace == SaveWorkspace::kIncorrect && + results_.back().verification_map[library::Provider::kCUDNN] == Disposition::kIncorrect) { + + save_workspace( + device_context, + options, + conv_desc, + library::Provider::kCUTLASS, + library::Provider::kCUDNN); + } + } + catch (...) { + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kFailed; + } + + // Return true means continue profiling + return true; +} + +#endif // #if CUTLASS_ENABLE_CUDNN + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace profiler +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/profiler/src/conv2d_operation_profiler.h b/tools/profiler/src/conv2d_operation_profiler.h new file mode 100644 index 000000000..40c003e1d --- /dev/null +++ b/tools/profiler/src/conv2d_operation_profiler.h @@ -0,0 +1,431 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Defines profiling functionality for convolution + +*/ + +#pragma once + +#include +#include +#include +#include +#include + +// CUTLASS Library includes +#include "cutlass/library/library.h" +#include "cutlass/library/util.h" +#include "cutlass/library/handle.h" +#include "cutlass/library/manifest.h" +#include "cutlass/library/singleton.h" + +// Profiler includes +#include "options.h" +#include "device_context.h" +#include "operation_profiler.h" +#include "performance_result.h" +#include "problem_space.h" +#include "reduction_operation_profiler.h" +#if CUTLASS_ENABLE_CUDNN +#include "cudnn_helpers.h" +#endif //#if CUTLASS_ENABLE_CUDNN +#include "debug.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace profiler { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Abstract base class for each math function +class Conv2dOperationProfiler : public OperationProfiler { +public: + + /// Problem structure obtained from problem space + struct Conv2dProblem { + + int64_t n, h, w, c, p, q, k, r, s; + int64_t pad_h, pad_w; + int64_t stride_h, stride_w; + int64_t dilation_h, dilation_w; + + std::vector alpha; + std::vector beta; + + library::SplitKMode split_k_mode; + int64_t split_k_slices; + + library::ConvModeID conv_mode; + + library::Provider eq_gemm_provider; + + // convolution with parallel interleaved reduction + // convolution epilogue (alpha, beta) = (1.0, 0.0) + // reduction epilogue (alpha, beta) = (Conv2dProblem::alpha, Conv2dProblem::beta) + std::vector alpha_one; + std::vector beta_zero; + + // + // Methods + // + + /// Total number of bytes loaded + int64_t bytes(library::ConvDescription const &operation_desc) const; + + /// Total number of flops computed + int64_t flops(library::ConvDescription const &operation_desc) const; + + void set_default_output_size() { + p = ((h + pad_h - r * dilation_h) / stride_h) + 1; + q = ((w + pad_w - s * dilation_w) / stride_w) + 1; + } + + // Returns equivalent gemm problem size for convolution + cutlass::gemm::GemmCoord eq_gemm_size(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return cutlass::gemm::GemmCoord(int(n * p * q), int(k), int(r * s * c)); + case library::ConvKind::kDgrad: return cutlass::gemm::GemmCoord(int(n * h * w), int(c), int(k * r * s)); + case library::ConvKind::kWgrad: return cutlass::gemm::GemmCoord(int(k), int(r * s * c), int(n * p * q)); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns extent for tensor A + std::vector extent_a(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return {int(n), int(h), int(w), int(c)}; + case library::ConvKind::kDgrad: return {int(n), int(p), int(q), int(k)}; + case library::ConvKind::kWgrad: return {int(n), int(p), int(q), int(k)}; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns extent for tensor B + std::vector extent_b(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return {int(k), int(r), int(s), int(c)}; + case library::ConvKind::kDgrad: return {int(k), int(r), int(s), int(c)}; + case library::ConvKind::kWgrad: return {int(n), int(h), int(w), int(c)}; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns extent for tensor C + std::vector extent_c(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return {int(n), int(p), int(q), int(k)}; + case library::ConvKind::kDgrad: return {int(n), int(h), int(w), int(c)}; + case library::ConvKind::kWgrad: return {int(k), int(r), int(s), int(c)}; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns layout for equivalent gemm matrix A + library::LayoutTypeID eq_gemm_layout_a(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return library::LayoutTypeID::kRowMajor; // TN Gemm + case library::ConvKind::kDgrad: return library::LayoutTypeID::kRowMajor; // TT Gemm + case library::ConvKind::kWgrad: return library::LayoutTypeID::kColumnMajor; // NT Gemm + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns layout for equivalent gemm matrix B + library::LayoutTypeID eq_gemm_layout_b(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return library::LayoutTypeID::kColumnMajor; // TN Gemm + case library::ConvKind::kDgrad: return library::LayoutTypeID::kRowMajor; // TT Gemm + case library::ConvKind::kWgrad: return library::LayoutTypeID::kRowMajor; // NT Gemm + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns layout for equivalent gemm matrix C + library::LayoutTypeID eq_gemm_layout_c(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + // Gemm operator assumes column-major output + case library::ConvKind::kFprop: + case library::ConvKind::kDgrad: + case library::ConvKind::kWgrad: return library::LayoutTypeID::kColumnMajor; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns leading dimenstion for equivalent gemm matrix A + int64_t eq_gemm_lda(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return eq_gemm_size(conv_kind).k(); + case library::ConvKind::kDgrad: return eq_gemm_size(conv_kind).k(); + case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).m(); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns leading dimenstion for equivalent gemm matrix B + int64_t eq_gemm_ldb(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return eq_gemm_size(conv_kind).k(); + case library::ConvKind::kDgrad: return eq_gemm_size(conv_kind).n(); + case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).n(); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns leading dimenstion for equivalent gemm matrix C + int64_t eq_gemm_ldc(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: + case library::ConvKind::kDgrad: + case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).m(); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + }; + + /// Workspace used + struct Conv2dWorkspace { + + /// Conv device allocations + DeviceAllocation *A; + DeviceAllocation *B; + DeviceAllocation *C; + DeviceAllocation *Computed; + DeviceAllocation *Reference; + + /// Library configuration and arguments for convolution operator + library::Conv2dConfiguration configuration; + library::ConvArguments arguments; + + /// Number of copies of the problem workspace which are visited sequentially during + /// profiling to avoid camping in the last level cache. + int problem_count; + + /// Buffer used for the cutlass conv2d operations' host workspace + std::vector host_workspace; + + /// Buffer used for the cutlass operations' device workspace + DeviceAllocation device_workspace; + + /// Library configuration and arguments for reduction operator + library::ReductionConfiguration reduction_configuration; + library::ReductionArguments reduction_arguments; + + /// Buffer used for the cutlass reduction operations' host workspace + std::vector reduction_host_workspace; + + /// Host data buffers for host reference operation + /// host buffer for tensor + std::vector host_tensor_a; + + /// host buffer for tensor b + std::vector host_tensor_b; + + /// host buffer for tensor c + std::vector host_tensor_c; + + + // + // Methods + // + + Conv2dWorkspace(): + A(nullptr), B(nullptr), C(nullptr), Computed(nullptr), Reference(nullptr) { } + + // Returns stride vector for tensor A + std::vector stride_a(library::ConvKind const &conv_kind) { + return { + configuration.layout_a(conv_kind).stride()[0], + configuration.layout_a(conv_kind).stride()[1], + configuration.layout_a(conv_kind).stride()[2] + }; + } + + // Returns stride vector for tensor B + std::vector stride_b(library::ConvKind const &conv_kind) { + + return { + configuration.layout_b(conv_kind).stride()[0], + configuration.layout_b(conv_kind).stride()[1], + configuration.layout_b(conv_kind).stride()[2] + }; + } + + // Returns stride vector for tensor C + std::vector stride_c(library::ConvKind const &conv_kind) { + + return { + configuration.layout_c(conv_kind).stride()[0], + configuration.layout_c(conv_kind).stride()[1], + configuration.layout_c(conv_kind).stride()[2] + }; + } + }; + +protected: + + // + // Data members + // + + /// CONV problem obtained from problem space + Conv2dProblem problem_; + + /// Device memory allocations + Conv2dWorkspace conv_workspace_; + + /// CUTLASS parallel reduction operation to follow this* conv2d operation + library::Operation const *reduction_op_; + +public: + // + // Methods + // + + /// Ctor + Conv2dOperationProfiler(Options const &options); + + /// Destructor + virtual ~Conv2dOperationProfiler(); + + /// Prints usage statement for the math function + virtual void print_usage(std::ostream &out) const; + + /// Prints examples + virtual void print_examples(std::ostream &out) const; + + /// Extracts the problem dimensions + virtual Status initialize_configuration( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Initializes workspace + virtual Status initialize_workspace( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Verifies CUTLASS against references + virtual bool verify_cutlass( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Measures performance results + virtual bool profile( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +protected: + /// Method to profile an initialized CUTLASS operation + virtual Status profile_cutlass_( + double &runtime, + Options const &options, + library::Operation const *operation, + void *arguments, + void *host_workspace, + void *device_workspace); + + + /// Initialize reduction problem dimenstions and library::Operation + bool initialize_reduction_configuration_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Initializes the performance result + void initialize_result_( + PerformanceResult &result, + Options const &options, + library::ConvDescription const &operation_desc, + ProblemSpace const &problem_space); + + /// Verifies CUTLASS against host reference + bool verify_with_host_reference_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Verifies CUTLASS against device reference + bool verify_with_device_reference_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +#if CUTLASS_ENABLE_CUDNN + + /// Verifies CUTLASS against cudnn reference + bool verify_with_cudnn_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +#endif //#if CUTLASS_ENABLE_CUDNN + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace profiler +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/profiler/src/conv3d_operation_profiler.cu b/tools/profiler/src/conv3d_operation_profiler.cu new file mode 100644 index 000000000..67f21d8f7 --- /dev/null +++ b/tools/profiler/src/conv3d_operation_profiler.cu @@ -0,0 +1,1345 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Convolution 3D profiling + +*/ + +#include +#include +#include +#include + +#include "cutlass/core_io.h" + +#include "conv3d_operation_profiler.h" +#include "gpu_timer.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// +using namespace cutlass::library; + +namespace cutlass { +namespace profiler { + + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Ctor +Conv3dOperationProfiler::Conv3dOperationProfiler(Options const &options): + OperationProfiler( + options, + library::OperationKind::kConv3d, + { + {ArgumentTypeID::kEnumerated, {"conv_kind"}, "Convolutional operator (fprop, dgrad, wgrad)"}, + {ArgumentTypeID::kInteger, {"n", "input_n"}, "Input N dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"d", "input_d"}, "Input D dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"h", "input_h"}, "Input H dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"w", "input_w"}, "Input W dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"c", "input_c"}, "Input C dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"k", "filter_k"}, "Filter K dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"t", "filter_t"}, "Filter T dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"r", "filter_r"}, "Filter R dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"s", "filter_s"}, "Filter S dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"z", "output_z"}, "Output Z dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"p", "output_p"}, "Output P dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"q", "output_q"}, "Output Q dimension of the Conv3d problem space"}, + {ArgumentTypeID::kInteger, {"pad_d"}, "Padding in D direction"}, + {ArgumentTypeID::kInteger, {"pad_h"}, "Padding in H direction"}, + {ArgumentTypeID::kInteger, {"pad_w"}, "Padding in W direction"}, + {ArgumentTypeID::kInteger, {"stride_d"}, "Stride in D direction"}, + {ArgumentTypeID::kInteger, {"stride_h"}, "Stride in H direction"}, + {ArgumentTypeID::kInteger, {"stride_w"}, "Stride in W direction"}, + {ArgumentTypeID::kInteger, {"dilation_d"}, "Dilation in D direction"}, + {ArgumentTypeID::kInteger, {"dilation_h"}, "Dilation in H direction"}, + {ArgumentTypeID::kInteger, {"dilation_w"}, "Dilation in W direction"}, + {ArgumentTypeID::kTensor, {"Activation"}, "Tensor storing the Activation operand"}, + {ArgumentTypeID::kTensor, {"Filter"}, "Tensor storing the Filter operand"}, + {ArgumentTypeID::kTensor, {"Output"}, "Tensor storing the Output operand"}, + {ArgumentTypeID::kEnumerated, {"conv_mode"}, "Convolution filter mode (conv, cross)"}, + {ArgumentTypeID::kEnumerated, {"iterator_algorithm", "iterator_algo"}, "Convolution iterator algorithm (analytic, optimized)"}, + {ArgumentTypeID::kScalar, {"alpha", "epilogue::alpha"}, "Epilogue scalar alpha"}, + {ArgumentTypeID::kScalar, {"beta", "epilogue::beta"}, "Epilogue scalar beta"}, + {ArgumentTypeID::kEnumerated, {"split_k_mode", "split-k-mode"}, "SplitK mode for serial or parallel reduction (serial, parallel)"}, + {ArgumentTypeID::kInteger, {"split_k_slices", "split-k-slices"}, "Number of partitions of K dimension"}, + {ArgumentTypeID::kEnumerated, {"eq_gemm_provider", "eq-gemm-provider"}, "Enable profiling equivalent gemm by the following providers (cutlass)"}, + }, + { library::Provider::kReferenceDevice, library::Provider::kReferenceHost, library::Provider::kCUDNN } + ) { + + description_ = " Conv3d operation. Output(Tensor5D) = alpha * Input(Tensor5D) * Filter(Tensor5D) + beta * Input(Tensor5D)"; + +} + +/// Destructor +Conv3dOperationProfiler::~Conv3dOperationProfiler() { + +} + + +/// Prints usage statement for the math function +void Conv3dOperationProfiler::print_usage(std::ostream &out) const { + out << "Conv3d" << "\n\n"; + + OperationProfiler::print_usage(out); +} + +/// Prints examples +void Conv3dOperationProfiler::print_examples(std::ostream &out) const { + + out << "\nExamples:\n\n" + << "Profile a particular convolution (specify all the convolution parameters):\n" + << " $ cutlass_profiler --operation=Conv3d" + " --Activation=f16:ndhwc --Filter=f16:ndhwc --Output=f16 --accumulator-type=f32" + " --n=32 --d=16 --h=14 --w=14 --c=8 --k=64 --t=3 --r=3 --s=3" + " --pad_d=1 --pad_h=1 --pad_w=1" + " --stride_d=1 --stride::h=1 --stride::w=1" + " --dilation_d=1 --dilation::h=1 --dilation::w=1\n\n"; +} + +#if 0 +// used this for debugging +static std::string byte_string(std::vector const &bytes) { + std::stringstream ss; + + ss << "0x"; + + for (size_t idx = bytes.size(); idx > 0; --idx) { + ss << std::hex << std::setw(2) << std::setfill('0') << uint32_t(bytes.at(idx - 1)); + } + + return ss.str(); +} +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////// + + +/// Total number of bytes loaded +int64_t Conv3dOperationProfiler::Conv3dProblem::bytes(library::ConvDescription const &operation_desc) const { + cutlass::gemm::GemmCoord mnk = eq_gemm_size(operation_desc.conv_kind); + + // Input bytes read and Output bytes written for the gemm problem + int64_t bytes_ = + int64_t(library::sizeof_bits(operation_desc.A.element) * mnk.m() / 8) * mnk.k() + + int64_t(library::sizeof_bits(operation_desc.B.element) * mnk.n() / 8) * mnk.k() + + int64_t(library::sizeof_bits(operation_desc.C.element) * mnk.m() / 8) * mnk.n(); + + // Set is_beta_zero true if beta is zero + bool is_beta_zero = std::all_of(beta.begin(), beta.end(), [](uint8_t i) { return i==0; }); + + // Output bytes read for the gemm problem for non-zero beta values + if (!is_beta_zero) { + bytes_ += int64_t(library::sizeof_bits(operation_desc.C.element) * mnk.m() / 8) * mnk.n(); + } + + return bytes_; +} + +/// Total number of flops computed +int64_t Conv3dOperationProfiler::Conv3dProblem::flops( + library::ConvDescription const &operation_desc) const { + + cutlass::gemm::GemmCoord mnk = eq_gemm_size(operation_desc.conv_kind); + + int64_t flops_mainloop_ = int64_t(mnk.m()) * mnk.n() * mnk.k() * 2; + int64_t flops_epilogue_ = int64_t(mnk.m()) * int64_t(mnk.n()) * 2; + + // Adjust mainloop flop for dgrad strided + if (operation_desc.conv_kind == library::ConvKind::kDgrad) { + flops_mainloop_ = flops_mainloop_ / ( stride_d * stride_h * stride_w); + } + + return (flops_mainloop_ + flops_epilogue_); +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Extracts the problem dimensions +Status Conv3dOperationProfiler::initialize_configuration( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + library::ConvDescription const &operation_desc = + static_cast(operation->description()); + + if (!arg_as_int(problem_.n, "n", problem_space, problem)) { + // default value + problem_.n = 1; + } + + if (!arg_as_int(problem_.d, "d", problem_space, problem)) { + // default value + problem_.d = 8; + } + + if (!arg_as_int(problem_.h, "h", problem_space, problem)) { + // default value + problem_.h = 14; + } + + if (!arg_as_int(problem_.w, "w", problem_space, problem)) { + // default value + problem_.w = 14; + } + + if (!arg_as_int(problem_.c, "c", problem_space, problem)) { + // default value + problem_.c = 32; + } + + if (!arg_as_int(problem_.k, "k", problem_space, problem)) { + // default value + problem_.k = 32; + } + + if (!arg_as_int(problem_.t, "t", problem_space, problem)) { + // default value + problem_.t = 3; + } + + if (!arg_as_int(problem_.r, "r", problem_space, problem)) { + // default value + problem_.r = 3; + } + + if (!arg_as_int(problem_.s, "s", problem_space, problem)) { + // default value + problem_.s = 3; + } + + if (!arg_as_int(problem_.pad_d, "pad_d", problem_space, problem)) { + // default value + problem_.pad_d = 1; + } + + if (!arg_as_int(problem_.pad_w, "pad_w", problem_space, problem)) { + // default value + problem_.pad_w = 1; + } + if (!arg_as_int(problem_.pad_h, "pad_h", problem_space, problem)) { + // default value + problem_.pad_h = 1; + } + + if (!arg_as_int(problem_.stride_d, "stride_d", problem_space, problem)) { + // default value + problem_.stride_d = 1; + } + + if (!arg_as_int(problem_.stride_h, "stride_h", problem_space, problem)) { + // default value + problem_.stride_h = 1; + } + + if (!arg_as_int(problem_.stride_w, "stride_w", problem_space, problem)) { + // default value + problem_.stride_w = 1; + } + + if (!arg_as_int(problem_.dilation_d, "dilation_d", problem_space, problem)) { + // default value + problem_.dilation_d = 1; + } + + if (!arg_as_int(problem_.dilation_h, "dilation_h", problem_space, problem)) { + // default value + problem_.dilation_h = 1; + } + + if (!arg_as_int(problem_.dilation_w, "dilation_w", problem_space, problem)) { + // default value + problem_.dilation_w = 1; + } + + //////////////////////// Convolution output dimensions p and q //////////////////////// + // Cutlass convolutions support arbitrary output sizes and not constriant by // + // input, filter, padding, striding, dilation sizes. // + // cuDNN sets the output dimensions (p, q) using following equations: // + // // + // output = div_up(input + 2 * pad - ((filter - 1) * dilation + 1) + 1, stride) // + // where; div_up(a, b) : (a - 1)/b + 1 // + // // + // Thus, when output p and q dimensions are unspecified by the user // + // cutlass profiler sets p and q which are cuDNN compliant. // + // // + //////////////////////////////////////////////////////////////////////////////////////// + // set convolution output z + if (!arg_as_int(problem_.z, "z", problem_space, problem)) { + // default value (set using cudnn formula for output height, when p is not provided) + problem_.z = ( + problem_.d + + 2 * problem_.pad_d - + ((problem_.t - 1) * problem_.dilation_d + 1) + ) / (problem_.stride_d) + + 1; + } + + // set convolution output p + if (!arg_as_int(problem_.p, "p", problem_space, problem)) { + // default value (set using cudnn formula for output height, when p is not provided) + problem_.p = ( + problem_.h + + 2 * problem_.pad_h - + ((problem_.r - 1) * problem_.dilation_h + 1) + ) / (problem_.stride_h) + + 1; + } + + // set convolution output q + if (!arg_as_int(problem_.q, "q", problem_space, problem)) { + // default value (set using cudnn formula for output width, when q is not provided) + problem_.q = ( + problem_.w + + 2 * problem_.pad_w - + ((problem_.s - 1) * problem_.dilation_w + 1) + ) / (problem_.stride_w) + + 1; + } + ///////////////////////////////////////////////////////////////////////////////////////// + + + if (!arg_as_SplitKModeID(problem_.split_k_mode, "split_k_mode", problem_space, problem)) { + // default value + problem_.split_k_mode = library::SplitKMode::kSerial; + } + + if (!arg_as_int(problem_.split_k_slices, "split_k_slices", problem_space, problem)) { + // default value + problem_.split_k_slices = 1; + } + + if (!arg_as_ConvModeID(problem_.conv_mode, "conv_mode", problem_space, problem)) { + // default value + problem_.conv_mode = library::ConvModeID::kCrossCorrelation; + } + + if (!arg_as_ProviderID(problem_.eq_gemm_provider, "eq_gemm_provider", problem_space, problem)) { + // default value + problem_.eq_gemm_provider = library::Provider::kNone; + } + + if (!conv_kind_satisfies(operation_desc.conv_kind, "conv_kind", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!iterator_algorithm_satisfies(operation_desc.iterator_algorithm, "iterator_algorithm", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!tensor_description_satisfies(operation_desc.activation(), "Activation", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!tensor_description_satisfies(operation_desc.filter(), "Filter", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!tensor_description_satisfies(operation_desc.output(), "Output", problem_space, problem)) { + return Status::kErrorInvalidProblem; + } + + if (!arg_as_scalar( + problem_.alpha, + operation_desc.element_epilogue, + "alpha", + problem_space, + problem)) { + + if (!cast_from_double(problem_.alpha, operation_desc.element_epilogue, 1)) { + return Status::kErrorInternal; + } + } + + if (!arg_as_scalar( + problem_.beta, + operation_desc.element_epilogue, + "beta", + problem_space, + problem)) { + + if (!cast_from_double(problem_.beta, operation_desc.element_epilogue, 0)) { + return Status::kErrorInternal; + } + } + + // initialize library::ConvConfiguration + conv_workspace_.configuration.problem_size = conv::Conv3dProblemSize( + int(problem_.n), + int(problem_.d), + int(problem_.h), + int(problem_.w), + int(problem_.c), + int(problem_.k), + int(problem_.t), + int(problem_.r), + int(problem_.s), + int(problem_.z), + int(problem_.p), + int(problem_.q), + int(problem_.pad_d), + int(problem_.pad_h), + int(problem_.pad_w), + int(problem_.stride_d), + int(problem_.stride_h), + int(problem_.stride_w), + int(problem_.dilation_d), + int(problem_.dilation_h), + int(problem_.dilation_w), + static_cast(static_cast(problem_.conv_mode)), + int(problem_.split_k_slices), + 1 // groups + ); + + conv_workspace_.configuration.split_k_mode = static_cast(static_cast(problem_.split_k_mode)); + + conv_workspace_.configuration.layout_activations.stride() = make_Coord( + int(problem_.c), + int(problem_.w) * int(problem_.c), + int(problem_.h) * int(problem_.w) * int(problem_.c), + int(problem_.d) * int(problem_.h) * int(problem_.w) * int(problem_.c) + ); + + conv_workspace_.configuration.layout_filters.stride() = make_Coord( + int(problem_.c), + int(problem_.s) * int(problem_.c), + int(problem_.r) * int(problem_.s) * int(problem_.c), + int(problem_.t) * int(problem_.r) * int(problem_.s) * int(problem_.c) + ); + + conv_workspace_.configuration.layout_output.stride() = make_Coord( + int(problem_.k), + int(problem_.q) * int(problem_.k), + int(problem_.q) * int(problem_.p) * int(problem_.k), + int(problem_.z) * int(problem_.q) * int(problem_.p) * int(problem_.k) + ); + + + // initialize library::ConvArguments + conv_workspace_.arguments.A = nullptr; + conv_workspace_.arguments.B = nullptr; + conv_workspace_.arguments.C = nullptr; + conv_workspace_.arguments.D = nullptr; + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + // initialize reduction operation for parallel splitKMode not supported for conv3d + if(conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + if(!initialize_reduction_configuration_(options, report, device_context, operation, problem_space, problem)) { + return Status::kErrorInternal; + } + } + + initialize_result_(this->model_result_, options, operation_desc, problem_space); + + return operation->can_implement(&conv_workspace_.configuration, &conv_workspace_.arguments); +} + +/// Initializes the performance result +void Conv3dOperationProfiler::initialize_result_( + PerformanceResult &result, + Options const &options, + library::ConvDescription const &operation_desc, + ProblemSpace const &problem_space) { + + result.provider = library::Provider::kCUTLASS; + result.disposition = Disposition::kNotRun; + result.status = Status::kSuccess; + result.operation_name = operation_desc.name; + + result.arguments.resize(problem_space.rank()); + + set_argument(result, "Activation", problem_space, + std::string(library::to_string(operation_desc.activation().element)) + + ":" + library::to_string(operation_desc.activation().layout)); + + set_argument(result, "Filter", problem_space, + std::string(library::to_string(operation_desc.filter().element)) + + ":" + library::to_string(operation_desc.filter().layout)); + + set_argument(result, "Output", problem_space, + std::string(library::to_string(operation_desc.output().element)) + + ":" + library::to_string(operation_desc.output().layout)); + + set_argument(result, "conv_kind", problem_space, library::to_string(operation_desc.conv_kind)); + + set_argument(result, "iterator_algorithm", problem_space, std::string(library::to_string(operation_desc.iterator_algorithm))); + + set_argument(result, "n", problem_space, problem_.n); + set_argument(result, "d", problem_space, problem_.d); + set_argument(result, "h", problem_space, problem_.h); + set_argument(result, "w", problem_space, problem_.w); + set_argument(result, "c", problem_space, problem_.c); + + set_argument(result, "k", problem_space, problem_.k); + set_argument(result, "t", problem_space, problem_.t); + set_argument(result, "r", problem_space, problem_.r); + set_argument(result, "s", problem_space, problem_.s); + + set_argument(result, "z", problem_space, problem_.z); + set_argument(result, "p", problem_space, problem_.p); + set_argument(result, "q", problem_space, problem_.q); + + set_argument(result, "pad_d", problem_space, problem_.pad_d); + set_argument(result, "pad_h", problem_space, problem_.pad_h); + set_argument(result, "pad_w", problem_space, problem_.pad_w); + + set_argument(result, "stride_d", problem_space, problem_.stride_d); + set_argument(result, "stride_h", problem_space, problem_.stride_h); + set_argument(result, "stride_w", problem_space, problem_.stride_w); + + set_argument(result, "dilation_d", problem_space, problem_.dilation_d); + set_argument(result, "dilation_h", problem_space, problem_.dilation_h); + set_argument(result, "dilation_w", problem_space, problem_.dilation_w); + + set_argument(result, "split_k_mode", problem_space, + std::string(library::to_string(problem_.split_k_mode))); + set_argument(result, "split_k_slices", problem_space, problem_.split_k_slices); + + set_argument(result, "conv_mode", problem_space, + std::string(library::to_string(problem_.conv_mode))); + + set_argument(result, "alpha", problem_space, + library::lexical_cast(problem_.alpha, operation_desc.element_epilogue)); + + set_argument(result, "beta", problem_space, + library::lexical_cast(problem_.beta, operation_desc.element_epilogue)); + + set_argument(result, "eq_gemm_provider", problem_space, + std::string(library::to_string(problem_.eq_gemm_provider))); + + OperationProfiler::initialize_result_(result, operation_desc, problem_space); + + // Bytes of activation, filter, and output tensors + result.bytes = problem_.bytes(operation_desc); + + // Theoritical flops required for the computation + result.flops = problem_.flops(operation_desc); + + // Measured runtime + result.runtime = 0; + +} + +/// Initialize reduction problem dimenstions and library::Operation +bool Conv3dOperationProfiler::initialize_reduction_configuration_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + library::ConvDescription const &conv_desc = + static_cast(operation->description()); + + library::ConvKind const &conv_kind = conv_desc.conv_kind; + + if (!cast_from_double(problem_.alpha_one, conv_desc.element_epilogue, 1)) { + return false; + } + + if (!cast_from_double(problem_.beta_zero, conv_desc.element_epilogue, 0)) { + return false; + } + + /// This chooses the appropriate stride element of the row-major C tensor. + int const & tensor_c_stride_idx = (conv_kind == library::ConvKind::kWgrad ? 3 : 0); + + /// intialize library::ReductionConfiguration + conv_workspace_.reduction_configuration.problem_size = problem_.eq_gemm_size(conv_kind).mn(); + conv_workspace_.reduction_configuration.partitions = int(problem_.split_k_slices); + conv_workspace_.reduction_configuration.partition_stride = problem_.eq_gemm_size(conv_kind).mn().product(); + conv_workspace_.reduction_configuration.ldw = conv_workspace_.configuration.layout_c(conv_kind).stride()[tensor_c_stride_idx]; + conv_workspace_.reduction_configuration.lds = conv_workspace_.configuration.layout_c(conv_kind).stride()[tensor_c_stride_idx]; + conv_workspace_.reduction_configuration.ldd = conv_workspace_.configuration.layout_c(conv_kind).stride()[tensor_c_stride_idx]; + + // find reduction operation + library::ReductionFunctionalKey reduction_key( + library::Provider::kCUTLASS, + conv_desc.tile_description.math_instruction.element_accumulator, // element workspace + conv_desc.tile_description.math_instruction.element_accumulator, // element accumulator + conv_desc.C.element, // element output + conv_desc.element_epilogue // element compute + ); + +#if 0// debug print to check which reduction instance is selected + std::cout << reduction_key << "\n"; +#endif + auto reduction_it = Singleton::get().operation_table.reduction_operations.find(reduction_key); + + if(reduction_it == Singleton::get().operation_table.reduction_operations.end()) { + + return false; + } + + // initialize reduction operation required for parallel split-k conv2d operator + reduction_op_ = reduction_it->second; + + // reduction operation found and initialized + return true; +} + + +/// Initializes workspace +Status Conv3dOperationProfiler::initialize_workspace( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + // initialize conv2d underlying operation to handle parallel reduction + library::Operation const* underlying_operation = operation; + + if(conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + if (!(underlying_operation = library::find_conv_operation_for_parallel_reduction(operation))) { + return Status::kErrorNotSupported; + } + } + + library::ConvDescription const &operation_desc = + static_cast(underlying_operation->description()); + + // Compute the number of copies of the problem to avoid L2 camping. + if (!options.profiling.workspace_count) { + int64_t bytes = problem_.bytes(operation_desc); + if (bytes < 3 * int64_t(options.device.properties.l2CacheSize)) { + conv_workspace_.problem_count = + 1 + int((3 * int64_t(options.device.properties.l2CacheSize)) / bytes); + } + else { + conv_workspace_.problem_count = 1; + } + } + else { + conv_workspace_.problem_count = options.profiling.workspace_count; + } + + + if (options.execution_mode != ExecutionMode::kDryRun) { + + conv_workspace_.A = device_context.allocate_tensor( + options, + "A", + operation_desc.A.element, + operation_desc.A.layout, + problem_.extent_a(operation_desc.conv_kind), + conv_workspace_.stride_a(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + conv_workspace_.B = device_context.allocate_tensor( + options, + "B", + operation_desc.B.element, + operation_desc.B.layout, + problem_.extent_b(operation_desc.conv_kind), + conv_workspace_.stride_b(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + conv_workspace_.C = device_context.allocate_tensor( + options, + "C", + operation_desc.C.element, + operation_desc.C.layout, + problem_.extent_c(operation_desc.conv_kind), + conv_workspace_.stride_c(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + conv_workspace_.Computed = device_context.allocate_tensor( + "D", + operation_desc.C.element, + operation_desc.C.layout, + problem_.extent_c(operation_desc.conv_kind), + conv_workspace_.stride_c(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + conv_workspace_.Reference = device_context.allocate_tensor( + "Reference", + operation_desc.C.element, + operation_desc.C.layout, + problem_.extent_c(operation_desc.conv_kind), + conv_workspace_.stride_c(operation_desc.conv_kind), + conv_workspace_.problem_count + ); + + } + + // + // Initialize the CUTLASS operation + // + Status status = Status::kSuccess; + + if (options.profiling.provider_enabled(library::Provider::kCUTLASS)) { + + if (options.execution_mode != ExecutionMode::kDryRun) { + + uint64_t workspace_size = underlying_operation->get_host_workspace_size(&conv_workspace_.configuration); + conv_workspace_.host_workspace.resize(workspace_size, 0); + + workspace_size = underlying_operation->get_device_workspace_size(&conv_workspace_.configuration); + conv_workspace_.device_workspace.reset(library::NumericTypeID::kU8, workspace_size); + + status = underlying_operation->initialize( + &conv_workspace_.configuration, + conv_workspace_.host_workspace.data(), + conv_workspace_.device_workspace.data()); + + if (status != Status::kSuccess) { + return status; + } + + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + workspace_size = reduction_op_->get_host_workspace_size(&conv_workspace_.reduction_configuration); + conv_workspace_.reduction_host_workspace.resize(workspace_size, 0); + + status = reduction_op_->initialize( + &conv_workspace_.reduction_configuration, + conv_workspace_.reduction_host_workspace.data(), + nullptr); + + if (status != Status::kSuccess) { + return status; + } + } + } + + // + // If CUTLASS is enabled, generate a result for it + // + results_.push_back(model_result_); + results_.back().provider = library::Provider::kCUTLASS; + results_.back().op_kind = library::OperationKind::kConv3d; + results_.back().disposition = Disposition::kNotRun; + + for(auto provider : verification_providers_) { + results_.back().verification_map[provider] = Disposition::kNotRun; + } + } + + return status; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Verifies CUTLASS against references +bool Conv3dOperationProfiler::verify_cutlass( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + if (!options.profiling.provider_enabled(library::Provider::kCUTLASS)) { + return true; + } + + if (options.execution_mode == ExecutionMode::kDryRun) { + return true; + } + + cudaError_t result; + + // Initialize structure containing Conv arguments + set_cutlass_operator_arguments_(); + + conv_workspace_.Computed->copy_from_device(conv_workspace_.C->data()); + + // + // Run the CUTLASS operation + // + // initialize conv2d underlying operation to handle parallel reduction + library::Operation const* underlying_operation = operation; + + if(conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + if (!(underlying_operation = library::find_conv_operation_for_parallel_reduction(operation))) { + results_.back().disposition = Disposition::kFailed; + return false; + } + } + +#if 0 + std::cout << "profiling : " << std::endl + << "conv2d : " << operation->description().name << std::endl + << "underlying conv2d : " << underlying_operation->description().name << std::endl + << "reduction : " << reduction_op_->description().name << std::endl; +#endif + + // run cutlass conv2d operation + results_.back().status = underlying_operation->run( + &conv_workspace_.arguments, + conv_workspace_.host_workspace.data(), + conv_workspace_.device_workspace.data()); + + if (results_.back().status != Status::kSuccess) { + results_.back().disposition = Disposition::kFailed; + return false; + } + + // Run parallel reduction kernel for parallel split_k_mode + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + + results_.back().status = reduction_op_->run( + &conv_workspace_.reduction_arguments, + conv_workspace_.reduction_host_workspace.data(), + nullptr); + + if (results_.back().status != Status::kSuccess) { + results_.back().disposition = Disposition::kFailed; + return false; + } + + } + + // Synchronize before running device reference + result = cudaDeviceSynchronize(); + if (result != cudaSuccess) { + results_.back().disposition = Disposition::kFailed; + return false; + } + + // CUTLASS op ran the but not yet verified against any verification provider + results_.back().disposition = Disposition::kNotVerified; + + // + // Run verification providers + // + + if (options.verification.enabled) { + +#if CUTLASS_ENABLE_CUDNN + // Run verification cudnn reference + if (options.verification.provider_enabled(library::Provider::kCUDNN)) { + + // Guard against unsupported cases + auto const & conv_desc = static_cast(operation->description()); + + Status status = cudnn_satisfies(conv_desc, conv_workspace_.configuration); + + // Initialize reference data to the source data + conv_workspace_.Reference->copy_from_device(conv_workspace_.C->data()); + + if (status == Status::kSuccess) { + // call cudnn verification if supported + verify_with_cudnn_( + options, + report, + device_context, + operation, + problem_space, + problem); + } + + else if (status == Status::kErrorInvalidProblem) { + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kInvalidProblem; + } + + else { + // set verification map for cudnn to not supported + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kNotSupported; + } + } +#endif // #if CUTLASS_ENABLE_CUDNN + + // Run verification host reference + if (options.verification.provider_enabled(library::Provider::kReferenceHost)) { + + // Restore reference data back to initial source data + conv_workspace_.Reference->copy_from_device(conv_workspace_.C->data()); + + verify_with_host_reference_( + options, + report, + device_context, + operation, + problem_space, + problem); + } + + // Update disposition to worst case verification outcome among all + // verification providers which are supported + bool is_any_verification_run_passed = false; + for(auto &m : results_.back().verification_map) { + if(m.second == Disposition::kFailed || m.second == Disposition::kIncorrect) { + results_.back().disposition = m.second; + return true; + } + if(!is_any_verification_run_passed && m.second == Disposition::kPassed) { + is_any_verification_run_passed = true; + } + } + + if(is_any_verification_run_passed) { + results_.back().disposition = Disposition::kPassed; + } + } + + // Return true means continue profiling + return true; +} + + +/// Verifies CUTLASS against host reference +bool Conv3dOperationProfiler::verify_with_host_reference_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + Status status; + + // + // Find host reference operation using conv functional description key + // + library::OperationDescription const &desc = operation->description(); + + auto &conv_desc = static_cast(desc); + + library::ConvFunctionalKey conv_key( + library::Provider::kReferenceHost, + conv_desc.conv_kind, + conv_desc.A.element, + conv_desc.A.layout, + conv_desc.B.element, + conv_desc.B.layout, + conv_desc.C.element, + conv_desc.C.layout, + conv_desc.tile_description.math_instruction.element_accumulator, + conv_desc.element_epilogue); + +#if 0 // debug print to check which host refererence instance is selected + std::cout << conv_key << "\n"; +#endif + + auto operators_it = Singleton::get().operation_table.conv3d_operations.find(conv_key); + + if(operators_it == Singleton::get().operation_table.conv3d_operations.end()) { + + results_.back().verification_map[library::Provider::kReferenceHost] = Disposition::kNotRun; + return true; + } + + // conv3d host reference minimum cc is 0 (CPU) and no iterator algorithm + library::ConvPreferenceKey preference_key(0, library::IteratorAlgorithmID::kNone); + auto cc_it = operators_it->second.find(preference_key); + + if(cc_it == operators_it->second.end()) { + results_.back().verification_map[library::Provider::kReferenceHost] = Disposition::kNotRun; + return true; + } + + // host refernce has only one instances in ConvOperationVectorMap + library::Operation const *reference_op = cc_it->second[0]; + + // + // Copy input tensors A, B, and C from device to host buffers + // + conv_workspace_.host_tensor_a.resize(conv_workspace_.A->bytes()); + conv_workspace_.host_tensor_b.resize(conv_workspace_.B->bytes()); + conv_workspace_.host_tensor_c.resize(conv_workspace_.C->bytes()); + conv_workspace_.A->copy_to_host(conv_workspace_.host_tensor_a.data()); + conv_workspace_.B->copy_to_host(conv_workspace_.host_tensor_b.data()); + conv_workspace_.C->copy_to_host(conv_workspace_.host_tensor_c.data()); + + // + // Initialize structure containing Conv3d arguments + // + conv_workspace_.arguments.A = conv_workspace_.host_tensor_a.data(); + conv_workspace_.arguments.B = conv_workspace_.host_tensor_b.data(); + conv_workspace_.arguments.C = conv_workspace_.host_tensor_c.data(); + conv_workspace_.arguments.D = conv_workspace_.host_tensor_c.data(); + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + // + // Intialize host reference operation + // + std::vector host_workspace_reference_op; + + uint64_t workspace_size = reference_op->get_host_workspace_size(&conv_workspace_.configuration); + host_workspace_reference_op.resize(workspace_size, 0); + + reference_op->initialize( + &conv_workspace_.configuration, + host_workspace_reference_op.data()); + + // + // Run host reference operation + // + status = reference_op->run( + &conv_workspace_.arguments, + host_workspace_reference_op.data()); + + // Handle errors + if (status != Status::kSuccess) { + results_.back().verification_map[library::Provider::kReferenceHost] = Disposition::kNotVerified; + return true; + } + + // + // Copy host reference output to device memory for equality check on device + // + conv_workspace_.Reference->copy_from_host(conv_workspace_.arguments.D); + + // + // Verify results + // + results_.back().verification_map[library::Provider::kReferenceHost] = compare_tensors( + options, + *conv_workspace_.Computed, + *conv_workspace_.Reference, + conv_workspace_.Computed->batch_stride() + ); + + // Save workspace if incorrect + if (options.verification.save_workspace == SaveWorkspace::kIncorrect && + results_.back().verification_map[library::Provider::kReferenceHost] == Disposition::kIncorrect) { + + save_workspace( + device_context, + options, + static_cast(operation->description()), + library::Provider::kCUTLASS, + library::Provider::kReferenceHost); + } + + // Return true means continue profiling + return true; +} + + +/// Verifies CUTLASS against host reference +bool Conv3dOperationProfiler::verify_with_device_reference_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + // TODO: verify cutlass conv3d against device reference + + // Return true means continue profiling + return true; +} + +/// Measures performance results +bool Conv3dOperationProfiler::profile( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + + if (options.profiling.provider_enabled(library::Provider::kCUTLASS)) { + + set_cutlass_operator_arguments_(); + + results_.back().status = profile_cutlass_( + results_.back().runtime, + options, + operation, + &conv_workspace_.arguments, + conv_workspace_.host_workspace.data(), + conv_workspace_.device_workspace.data() + ); + } + return true; + +} + +/// Updates the arguments structure for the CUTLASS operator based on +/// the problem index. +void Conv3dOperationProfiler::set_cutlass_operator_arguments_(int problem_idx) { + // Initialize structure containing Conv3d arguments + conv_workspace_.arguments.A = conv_workspace_.A->batch_data(problem_idx); + conv_workspace_.arguments.B = conv_workspace_.B->batch_data(problem_idx); + conv_workspace_.arguments.C = conv_workspace_.C->batch_data(problem_idx); + conv_workspace_.arguments.D = conv_workspace_.Computed->batch_data(problem_idx); + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + // update library::ConvArguments for parallel split-k reduction + conv_workspace_.arguments.D = conv_workspace_.device_workspace.data(); + conv_workspace_.arguments.alpha = problem_.alpha_one.data(); + conv_workspace_.arguments.beta = problem_.beta_zero.data(); + + /// intialize library::ReductionArguments + conv_workspace_.reduction_arguments.workspace = conv_workspace_.device_workspace.data(); + conv_workspace_.reduction_arguments.source = conv_workspace_.C->batch_data(problem_idx); + conv_workspace_.reduction_arguments.destination = conv_workspace_.Computed->batch_data(problem_idx); + conv_workspace_.reduction_arguments.alpha = problem_.alpha.data(); + conv_workspace_.reduction_arguments.beta = problem_.beta.data(); + conv_workspace_.reduction_arguments.pointer_mode = library::ScalarPointerMode::kHost; + } +} + +/// Method to profile a CUTLASS Operation +Status Conv3dOperationProfiler::profile_cutlass_( + double &runtime, + Options const &options, + library::Operation const *operation, + void *arguments, + void *host_workspace, + void *device_workspace) { + + GpuTimer timer; + + // initialize conv2d underlying operation to handle parallel reduction + library::Operation const* underlying_operation = operation; + + if(conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + if (!(underlying_operation = library::find_conv_operation_for_parallel_reduction(operation))) { + return Status::kErrorNotSupported; + } + } + + // + // Optional sleep to limit power consumption and thermals + // + + sleep(options.profiling.sleep_duration); + + // + // Warmup loop + // + + Status status; + + for (int iteration = 0; iteration < options.profiling.warmup_iterations; ++iteration) { + + // Setup rotating workspace + int workspace_idx = options.profiling.warmup_iterations + iteration; + int problem_idx = (workspace_idx % conv_workspace_.problem_count); + + set_cutlass_operator_arguments_(problem_idx); + + // Run underlying conv2d operation + status = underlying_operation->run( + arguments, + host_workspace, + device_workspace); + + // Run parallel reduction kernel for parallel split_k_mode + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + + status = reduction_op_->run( + &conv_workspace_.reduction_arguments, + conv_workspace_.reduction_host_workspace.data(), + nullptr); + } + + if (status != Status::kSuccess) { + return status; + } + } + + // + // Initialize GPU timer + // + + timer.start(); + + // + // Profiling loop + // + + int Iterations = options.profiling.iterations; + + int iteration = 0; + for (; iteration < Iterations; ++iteration) { + + // Setup rotating workspace + int problem_idx = (iteration % conv_workspace_.problem_count); + + set_cutlass_operator_arguments_(problem_idx); + + // Run underlying conv2d operation + status = underlying_operation->run( + arguments, + host_workspace, + device_workspace); + + // Run parallel reduction kernel for parallel split_k_mode + if (conv_workspace_.configuration.split_k_mode == conv::SplitKMode::kParallel) { + status = reduction_op_->run( + &conv_workspace_.reduction_arguments, + conv_workspace_.reduction_host_workspace.data(), + nullptr); + } + + if (status != Status::kSuccess) { + return status; + } + } + + // + // Wait for completion + // + + timer.stop_and_wait(); + + // + // Update performance result + // + + runtime = timer.duration(iteration); + + return status; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +#if CUTLASS_ENABLE_CUDNN + +/// Verifies CUTLASS against cudnn reference +bool Conv3dOperationProfiler::verify_with_cudnn_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + auto &conv_desc = static_cast(operation->description()); + + // + // Construct cudnn operators + // + + CudnnCreate handle; + cudnnStatus_t status = handle.get_cudnn_create_status(); + + if (status != CUDNN_STATUS_SUCCESS) { + + results_.back().verification_map[library::Provider::kCUDNN] = get_cutlass_disposition(status); + return true; + } + + // + // Initialize state + // + + // Initialize structure containing Conv2d arguments + conv_workspace_.arguments.A = conv_workspace_.A->data(); + conv_workspace_.arguments.B = conv_workspace_.B->data(); + conv_workspace_.arguments.D = conv_workspace_.Reference->data(); + conv_workspace_.arguments.alpha = problem_.alpha.data(); + conv_workspace_.arguments.beta = problem_.beta.data(); + conv_workspace_.arguments.pointer_mode = library::ScalarPointerMode::kHost; + + // cuDNN does not support four tensor arguments, so we copy the tensor C data into + // tensor D. + conv_workspace_.Reference->copy_from_device(conv_workspace_.C->data()); + conv_workspace_.arguments.C = conv_workspace_.arguments.D; + + try { + + // + // Construct dispatcher to cudnn operator + // + + detail::cudnnConvDispatcher conv_op( + conv_desc, + conv_workspace_.configuration, + conv_workspace_.arguments, + handle + ); + + if (conv_op.status != Status::kSuccess) { + if (conv_op.status == Status::kErrorNotSupported) { + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kNotSupported; + + } else { + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kFailed; + } + return true; + } + + + status = conv_op(handle); + + // Handle errors + if (status != CUDNN_STATUS_SUCCESS) { + + results_.back().verification_map[library::Provider::kCUDNN] = get_cutlass_disposition(status); + return true; + } + + // + // Verify results + // + + results_.back().verification_map[library::Provider::kCUDNN] = compare_tensors( + options, + *conv_workspace_.Computed, + *conv_workspace_.Reference + ); + + // Save workspace if incorrect + if (options.verification.save_workspace == SaveWorkspace::kIncorrect && + results_.back().verification_map[library::Provider::kCUDNN] == Disposition::kIncorrect) { + + save_workspace( + device_context, + options, + conv_desc, + library::Provider::kCUTLASS, + library::Provider::kCUDNN); + } + } + catch (...) { + results_.back().verification_map[library::Provider::kCUDNN] = Disposition::kFailed; + } + + // Return true means continue profiling + return true; + +} + +#endif // #if CUTLASS_ENABLE_CUDNN + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace profiler +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/profiler/src/conv3d_operation_profiler.h b/tools/profiler/src/conv3d_operation_profiler.h new file mode 100644 index 000000000..04c2a15e8 --- /dev/null +++ b/tools/profiler/src/conv3d_operation_profiler.h @@ -0,0 +1,441 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Defines profiling functionality for convolution + +*/ + +#pragma once + +#include +#include +#include +#include +#include + +// CUTLASS Library includes +#include "cutlass/library/library.h" +#include "cutlass/library/util.h" +#include "cutlass/library/handle.h" +#include "cutlass/library/manifest.h" +#include "cutlass/library/singleton.h" + +// Profiler includes +#include "options.h" +#include "device_context.h" +#include "operation_profiler.h" +#include "performance_result.h" +#include "problem_space.h" +#include "reduction_operation_profiler.h" +#if CUTLASS_ENABLE_CUDNN +#include "cudnn_helpers.h" +#endif //#if CUTLASS_ENABLE_CUDNN +#include "debug.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace profiler { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Abstract base class for each math function +class Conv3dOperationProfiler : public OperationProfiler { +public: + + /// Problem structure obtained from problem space + struct Conv3dProblem { + + int64_t n, d, h, w, c, z, p, q, k, t, r, s; + int64_t pad_d, pad_h, pad_w; + int64_t stride_d, stride_h, stride_w; + int64_t dilation_d, dilation_h, dilation_w; + + std::vector alpha; + std::vector beta; + + library::SplitKMode split_k_mode; + int64_t split_k_slices; + + library::ConvModeID conv_mode; + + library::Provider eq_gemm_provider; + + // convolution with parallel interleaved reduction + // convolution epilogue (alpha, beta) = (1.0, 0.0) + // reduction epilogue (alpha, beta) = (Conv3dProblem::alpha, Conv3dProblem::beta) + std::vector alpha_one; + std::vector beta_zero; + + // + // Methods + // + + /// Total number of bytes loaded + int64_t bytes(library::ConvDescription const &operation_desc) const; + + /// Total number of flops computed + int64_t flops(library::ConvDescription const &operation_desc) const; + + /// Infers output size from theinput size, padding, stride, and dilation + void set_default_output_size() { + z = ((d + pad_d - t * dilation_d) / stride_d) + 1; + p = ((h + pad_h - r * dilation_h) / stride_h) + 1; + q = ((w + pad_w - s * dilation_w) / stride_w) + 1; + } + + // Returns equivalent gemm problem size for convolution + cutlass::gemm::GemmCoord eq_gemm_size(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return cutlass::gemm::GemmCoord(int(n * z * p * q), int(k), int(t * r * s * c)); + case library::ConvKind::kDgrad: return cutlass::gemm::GemmCoord(int(n * d * h * w), int(c), int(t * r * s * k)); + case library::ConvKind::kWgrad: return cutlass::gemm::GemmCoord(int(k), int(t * r * s * c), int(n * z * p * q)); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns extent for tensor A + std::vector extent_a(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return {int(n), int(d), int(h), int(w), int(c)}; + case library::ConvKind::kDgrad: return {int(n), int(z), int(p), int(q), int(k)}; + case library::ConvKind::kWgrad: return {int(n), int(z), int(p), int(q), int(k)}; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns extent for tensor B + std::vector extent_b(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return {int(k), int(t), int(r), int(s), int(c)}; + case library::ConvKind::kDgrad: return {int(k), int(t), int(r), int(s), int(c)}; + case library::ConvKind::kWgrad: return {int(n), int(d), int(h), int(w), int(c)}; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns extent for tensor C + std::vector extent_c(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return {int(n), int(z), int(p), int(q), int(k)}; + case library::ConvKind::kDgrad: return {int(n), int(d), int(h), int(w), int(c)}; + case library::ConvKind::kWgrad: return {int(k), int(t), int(r), int(s), int(c)}; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns layout for equivalent gemm matrix A + library::LayoutTypeID eq_gemm_layout_a(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return library::LayoutTypeID::kRowMajor; // TN Gemm + case library::ConvKind::kDgrad: return library::LayoutTypeID::kRowMajor; // TT Gemm + case library::ConvKind::kWgrad: return library::LayoutTypeID::kColumnMajor; // NT Gemm + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns layout for equivalent gemm matrix B + library::LayoutTypeID eq_gemm_layout_b(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return library::LayoutTypeID::kColumnMajor; // TN Gemm + case library::ConvKind::kDgrad: return library::LayoutTypeID::kRowMajor; // TT Gemm + case library::ConvKind::kWgrad: return library::LayoutTypeID::kRowMajor; // NT Gemm + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns layout for equivalent gemm matrix C + library::LayoutTypeID eq_gemm_layout_c(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + // Gemm operator assumes column-major output + case library::ConvKind::kFprop: + case library::ConvKind::kDgrad: + case library::ConvKind::kWgrad: return library::LayoutTypeID::kColumnMajor; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns leading dimenstion for equivalent gemm matrix A + int64_t eq_gemm_lda(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return eq_gemm_size(conv_kind).k(); + case library::ConvKind::kDgrad: return eq_gemm_size(conv_kind).k(); + case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).m(); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns leading dimenstion for equivalent gemm matrix B + int64_t eq_gemm_ldb(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: return eq_gemm_size(conv_kind).k(); + case library::ConvKind::kDgrad: return eq_gemm_size(conv_kind).n(); + case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).n(); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns leading dimenstion for equivalent gemm matrix C + int64_t eq_gemm_ldc(library::ConvKind const &conv_kind) const { + + switch (conv_kind) { + case library::ConvKind::kFprop: + case library::ConvKind::kDgrad: + case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).m(); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + }; + + /// Workspace used + struct Conv2dWorkspace { + + /// Conv device allocations + DeviceAllocation *A; + DeviceAllocation *B; + DeviceAllocation *C; + DeviceAllocation *Computed; + DeviceAllocation *Reference; + + /// Library configuration and arguments for convolution operator + library::Conv3dConfiguration configuration; + library::ConvArguments arguments; + + /// Number of copies of the problem workspace which are visited sequentially during + /// profiling to avoid camping in the last level cache. + int problem_count; + + /// Buffer used for the cutlass conv2d operations' host workspace + std::vector host_workspace; + + /// Buffer used for the cutlass operations' device workspace + DeviceAllocation device_workspace; + + /// Library configuration and arguments for reduction operator + library::ReductionConfiguration reduction_configuration; + library::ReductionArguments reduction_arguments; + + /// Buffer used for the cutlass reduction operations' host workspace + std::vector reduction_host_workspace; + + /// Host data buffers for host reference operation + /// host buffer for tensor + std::vector host_tensor_a; + + /// host buffer for tensor b + std::vector host_tensor_b; + + /// host buffer for tensor c + std::vector host_tensor_c; + + + // + // Methods + // + + Conv2dWorkspace(): + A(nullptr), B(nullptr), C(nullptr), Computed(nullptr), Reference(nullptr) { } + + // Returns stride vector for tensor A + std::vector stride_a(library::ConvKind const &conv_kind) { + return { + configuration.layout_a(conv_kind).stride()[0], + configuration.layout_a(conv_kind).stride()[1], + configuration.layout_a(conv_kind).stride()[2], + configuration.layout_a(conv_kind).stride()[3] + }; + } + + // Returns stride vector for tensor B + std::vector stride_b(library::ConvKind const &conv_kind) { + + return { + configuration.layout_b(conv_kind).stride()[0], + configuration.layout_b(conv_kind).stride()[1], + configuration.layout_b(conv_kind).stride()[2], + configuration.layout_b(conv_kind).stride()[3] + }; + } + + // Returns stride vector for tensor C + std::vector stride_c(library::ConvKind const &conv_kind) { + + return { + configuration.layout_c(conv_kind).stride()[0], + configuration.layout_c(conv_kind).stride()[1], + configuration.layout_c(conv_kind).stride()[2], + configuration.layout_c(conv_kind).stride()[3] + }; + } + }; + +protected: + + // + // Data members + // + + /// CONV problem obtained from problem space + Conv3dProblem problem_; + + /// Device memory allocations + Conv2dWorkspace conv_workspace_; + + /// CUTLASS parallel reduction operation to follow this* conv2d operation + library::Operation const *reduction_op_; + +public: + // + // Methods + // + + /// Ctor + Conv3dOperationProfiler(Options const &options); + + /// Destructor + virtual ~Conv3dOperationProfiler(); + + /// Prints usage statement for the math function + virtual void print_usage(std::ostream &out) const; + + /// Prints examples + virtual void print_examples(std::ostream &out) const; + + /// Extracts the problem dimensions + virtual Status initialize_configuration( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Initializes workspace + virtual Status initialize_workspace( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Verifies CUTLASS against references + virtual bool verify_cutlass( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Measures performance results + virtual bool profile( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +protected: + + /// Updates the arguments structure for the CUTLASS operator based on + /// the problem index. + void set_cutlass_operator_arguments_(int problem_idx = 0); + + /// Method to profile an initialized CUTLASS operation + virtual Status profile_cutlass_( + double &runtime, + Options const &options, + library::Operation const *operation, + void *arguments, + void *host_workspace, + void *device_workspace); + + /// Initialize reduction problem dimenstions and library::Operation + bool initialize_reduction_configuration_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Initializes the performance result + void initialize_result_( + PerformanceResult &result, + Options const &options, + library::ConvDescription const &operation_desc, + ProblemSpace const &problem_space); + + /// Verifies CUTLASS against host reference + bool verify_with_host_reference_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Verifies CUTLASS against device reference + bool verify_with_device_reference_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +#if CUTLASS_ENABLE_CUDNN + + /// Verifies CUTLASS against cudnn reference + bool verify_with_cudnn_( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +#endif //#if CUTLASS_ENABLE_CUDNN + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace profiler +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/tools/profiler/src/cudnn_helpers.cpp b/tools/profiler/src/cudnn_helpers.cpp new file mode 100644 index 000000000..86f18095b --- /dev/null +++ b/tools/profiler/src/cudnn_helpers.cpp @@ -0,0 +1,485 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Helper functions for mapping CUTLASS concepts to cuDNN. +*/ +#if CUTLASS_ENABLE_CUDNN + +#include + +#include "cudnn_helpers.h" + +namespace cutlass { +namespace profiler { + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Converts a cuDNN status to cutlass::Status +Status get_cutlass_status(cudnnStatus_t cudnn_status) { + + if (cudnn_status == CUDNN_STATUS_SUCCESS) { + return Status::kSuccess; + } + else if (cudnn_status == CUDNN_STATUS_INVALID_VALUE) { + return Status::kErrorInvalidProblem; + } + if (cudnn_status == CUDNN_STATUS_NOT_SUPPORTED) { + return Status::kErrorNotSupported; + } + return Status::kErrorInternal; +} + +/// Converts a cuDNN status to cutlass::profiler::Disposition +Disposition get_cutlass_disposition(cudnnStatus_t cudnn_status) { + + if (cudnn_status == CUDNN_STATUS_INVALID_VALUE) { + return Disposition::kInvalidProblem; + } + else if (cudnn_status == CUDNN_STATUS_NOT_SUPPORTED) { + return Disposition::kNotSupported; + } + return Disposition::kFailed; +} + +/// Checks cudnnStatus_t converts to cutlas status and returns if Status::kSuccess o.w. throws exception +Status checkCudnnErr(cudnnStatus_t cudnn_status) { + Status cutlass_status = get_cutlass_status(cudnn_status); + if(cutlass_status != Status::kSuccess) { + throw std::runtime_error("checkCudnnErr failed"); + } + return cutlass_status; +} + +/// Maps a CUTLASS conv mode to a cuDNN cudnnConvolutionMode_t +bool get_cudnn_conv_mode(cudnnConvolutionMode_t &cudnn_conv_mode, conv::Mode conv_mode) { + switch (conv_mode) { + case conv::Mode::kCrossCorrelation: + cudnn_conv_mode = CUDNN_CROSS_CORRELATION; + return true; + case conv::Mode::kConvolution: + cudnn_conv_mode = CUDNN_CONVOLUTION; + return true; + default: break; + } + return false; +} + +/// Maps a CUTLASS tensor layout to a cuDNN cudnnTensorFormat_t +bool get_cudnn_layout(cudnnTensorFormat_t &cudnn_layout, library::LayoutTypeID layout) { + switch (layout) { + // cudnn uses the same enum for TensorNC*HW along nDim (ConvDescription::conv_dim) + case library::LayoutTypeID::kTensorNCHW: + case library::LayoutTypeID::kTensorNCDHW: + cudnn_layout = CUDNN_TENSOR_NCHW; + return true; + case library::LayoutTypeID::kTensorNHWC: + case library::LayoutTypeID::kTensorNDHWC: + cudnn_layout = CUDNN_TENSOR_NHWC; + return true; + default: break; + } + return false; +} + +/// Maps a CUTLASS numeric type to a cuDNN cudnnDataType_t +bool get_cudnn_datatype(cudnnDataType_t &cudnn_element_type, library::NumericTypeID element_type) { + switch (element_type) { + case library::NumericTypeID::kF16: + cudnn_element_type = CUDNN_DATA_HALF; + return true; + + case library::NumericTypeID::kF32: + cudnn_element_type = CUDNN_DATA_FLOAT; + return true; + + case library::NumericTypeID::kF64: + cudnn_element_type = CUDNN_DATA_DOUBLE; + return true; + + case library::NumericTypeID::kS2: + break; + + case library::NumericTypeID::kS4: + break; + + case library::NumericTypeID::kS8: + cudnn_element_type = CUDNN_DATA_INT8; + return true; + + case library::NumericTypeID::kS16: + break; + + case library::NumericTypeID::kS32: + cudnn_element_type = CUDNN_DATA_INT32; + return true; + + case library::NumericTypeID::kS64: + break; + + case library::NumericTypeID::kU2: + break; + + case library::NumericTypeID::kU4: + break; + + case library::NumericTypeID::kU8: + cudnn_element_type = CUDNN_DATA_UINT8; + return true; + + case library::NumericTypeID::kU16: + break; + + case library::NumericTypeID::kU32: + break; + + case library::NumericTypeID::kU64: + break; + + case library::NumericTypeID::kB1: + break; + + case library::NumericTypeID::kInvalid: + + default: + break; + } + + return false; +} + +/// Maps CUTLASS math OpcodeClassID and MathOperationID to cuDNN math_type +bool get_cudnn_mathtype(cudnnMathType_t &cudnn_math_type, library::ConvDescription const &conv_desc) { + + switch (conv_desc.tile_description.math_instruction.opcode_class) { + + case library::OpcodeClassID::kTensorOp: + { + cudnn_math_type = CUDNN_TENSOR_OP_MATH; + + library::MathOperationID math_op = conv_desc.tile_description.math_instruction.math_operation; + + // Allow conversion on input data type for fast math operations + if (math_op == library::MathOperationID::kMultiplyAddFastF16 || + math_op == library::MathOperationID::kMultiplyAddFastBF16) + { + cudnn_math_type = CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION; + } + + return true; + } + case library::OpcodeClassID::kSimt: + return false; + } + + return false; +} + +/// Cudnn compute type seems to be hardcoded to float (To handle a possible cudnn issue) +float cast_cudnn_compute_type_to_float(library::NumericTypeID type, void const * src) { + + switch (type) { + case library::NumericTypeID::kF16: + { + return float(*(static_cast(src))); + } + case library::NumericTypeID::kF32: + { + return float(*(static_cast(src))); + } + case library::NumericTypeID::kS32: + { + return float(*(static_cast(src))); + } + default: + throw std::runtime_error("Data type handled in cast_compute_type_to_float"); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Returns a status if cuDNN can satisfy a particular Conv2d description +Status cudnn_satisfies( + library::ConvDescription const &desc, + library::Conv2dConfiguration const &configuration) { + + auto const &a_tensor = desc.A; + auto const &b_tensor = desc.B; + auto const &c_tensor = desc.C; + auto const &math_instruction = desc.tile_description.math_instruction; + + if(a_tensor.element != b_tensor.element) { + return Status::kErrorInvalidDataType; + } + + //////////////////////// Convolution output dimensions p and q /////////////////////// + // Cutlass convolutions support arbitrary output dimensions and not constriant by // + // input, filter, padding, striding, dilation sizes. // + // cuDNN sets the output dimensions (p, q) using following equations: // + // // + // output = div_up(input + 2 * pad - ((filter - 1) * dilation + 1) + 1, stride) // + // where; div_up(a, b) : (a - 1)/b + 1 // + // // + // Before launching cudnn verification or profiling check that output p and q // + // dimensions are cuDNN compliant. // + // // + // If user sets output p and q which do not follow above constraints, cutlass conv, // + // host reference, device reference can run. However, cudnn convolution returns // + // "Invalid problem" // + // // + /////////////////////////////////////////////////////////////////////////////////////// + + // check conv output dimension p for cudnn + int cudnn_output_p = + ( + ( + configuration.problem_size.H + + 2 * configuration.problem_size.pad_h - + ((configuration.problem_size.R - 1) * + configuration.problem_size.dilation_h + 1) + ) / + (configuration.problem_size.stride_h) + + 1 + ); + + if (cudnn_output_p != configuration.problem_size.P) { + return Status::kErrorInvalidProblem; + } + + // check conv output dimension q for cudnn + int cudnn_output_q = + ( + ( + configuration.problem_size.W + + 2 * configuration.problem_size.pad_w - + ((configuration.problem_size.S - 1) * + configuration.problem_size.dilation_w + 1) + ) / + (configuration.problem_size.stride_w) + + 1 + ); + + if (cudnn_output_q != configuration.problem_size.Q) { + return Status::kErrorInvalidProblem; + } + ////////////////////////////////////////////////////////////////////////////////////// + + // conv operator with input=FP16, accumulator=FP32, output=FP32 datatype + if (a_tensor.element == library::NumericTypeID::kF16 && + b_tensor.element == library::NumericTypeID::kF16 && + math_instruction.element_accumulator == library::NumericTypeID::kF32 && + c_tensor.element == library::NumericTypeID::kF32 + ) { + + return Status::kErrorNotSupported; + } + + if (a_tensor.element == library::NumericTypeID::kBF16 || + b_tensor.element == library::NumericTypeID::kBF16 || + c_tensor.element == library::NumericTypeID::kBF16 + ) { + + return Status::kErrorNotSupported; + } + + // TF32 input not supported in cuDNN + if (a_tensor.element == library::NumericTypeID::kTF32 || + b_tensor.element == library::NumericTypeID::kTF32 || + c_tensor.element == library::NumericTypeID::kTF32 + ) { + + return Status::kErrorNotSupported; + } + + if (a_tensor.element == library::NumericTypeID::kS8 || + b_tensor.element == library::NumericTypeID::kS8 || + c_tensor.element == library::NumericTypeID::kS8 + ) { + + return Status::kErrorNotSupported; + } + + if (a_tensor.element == library::NumericTypeID::kU8 || + b_tensor.element == library::NumericTypeID::kU8 || + c_tensor.element == library::NumericTypeID::kU8 + ) { + + return Status::kErrorNotSupported; + } + + if (a_tensor.element == library::NumericTypeID::kS4 || + b_tensor.element == library::NumericTypeID::kS4 || + c_tensor.element == library::NumericTypeID::kS4 + ) { + + return Status::kErrorNotSupported; + } + + if (a_tensor.element == library::NumericTypeID::kU4 || + b_tensor.element == library::NumericTypeID::kU4 || + c_tensor.element == library::NumericTypeID::kU4 + ) { + + return Status::kErrorNotSupported; + } + + return Status::kSuccess; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Returns a status if cuDNN can satisfy a particular Conv3d description +Status cudnn_satisfies( + library::ConvDescription const &desc, + library::Conv3dConfiguration const &configuration) { + + auto const &a_tensor = desc.A; + auto const &b_tensor = desc.B; + auto const &c_tensor = desc.C; + auto const &math_instruction = desc.tile_description.math_instruction; + + if(a_tensor.element != b_tensor.element) { + return Status::kErrorInvalidDataType; + } + + //////////////////////// Convolution output dimensions p and q /////////////////////// + // Cutlass convolutions support arbitrary output dimensions and not constriant by // + // input, filter, padding, striding, dilation sizes. // + // cuDNN sets the output dimensions (p, q) using following equations: // + // // + // output = div_up(input + 2 * pad - ((filter - 1) * dilation + 1) + 1, stride) // + // where; div_up(a, b) : (a - 1)/b + 1 // + // // + // Before launching cudnn verification or profiling check that output p and q // + // dimensions are cuDNN compliant. // + // // + // If user sets output p and q which do not follow above constraints, cutlass conv, // + // host reference, device reference can run. However, cudnn convolution returns // + // "Invalid problem" // + // // + /////////////////////////////////////////////////////////////////////////////////////// + + // check conv output dimension z for cudnn + int cudnn_output_z = + ( + ( + configuration.problem_size.D + + 2 * configuration.problem_size.pad_d - + ((configuration.problem_size.T - 1) * + configuration.problem_size.dilation_d + 1) + ) / + (configuration.problem_size.stride_d) + + 1 + ); + + if (cudnn_output_z != configuration.problem_size.Z) { + return Status::kErrorInvalidProblem; + } + + // check conv output dimension p for cudnn + int cudnn_output_p = + ( + ( + configuration.problem_size.H + + 2 * configuration.problem_size.pad_h - + ((configuration.problem_size.R - 1) * + configuration.problem_size.dilation_h + 1) + ) / + (configuration.problem_size.stride_h) + + 1 + ); + + if (cudnn_output_p != configuration.problem_size.P) { + return Status::kErrorInvalidProblem; + } + + // check conv output dimension q for cudnn + int cudnn_output_q = + ( + ( + configuration.problem_size.W + + 2 * configuration.problem_size.pad_w - + ((configuration.problem_size.S - 1) * + configuration.problem_size.dilation_w + 1) + ) / + (configuration.problem_size.stride_w) + + 1 + ); + + if (cudnn_output_q != configuration.problem_size.Q) { + return Status::kErrorInvalidProblem; + } + ////////////////////////////////////////////////////////////////////////////////////// + + // conv operator with input, accumulator, output datatype of (hss) are not supported + // in cuDNN + if (a_tensor.element == library::NumericTypeID::kF16 && + b_tensor.element == library::NumericTypeID::kF16 && + math_instruction.element_accumulator == library::NumericTypeID::kF32 && + c_tensor.element == library::NumericTypeID::kF32 + ) { + + return Status::kErrorNotSupported; + } + + if (a_tensor.element == library::NumericTypeID::kBF16 || + b_tensor.element == library::NumericTypeID::kBF16 || + c_tensor.element == library::NumericTypeID::kBF16 + ) { + + return Status::kErrorNotSupported; + } + + if (a_tensor.element == library::NumericTypeID::kTF32 || + b_tensor.element == library::NumericTypeID::kTF32 || + c_tensor.element == library::NumericTypeID::kTF32 + ) { + + return Status::kErrorNotSupported; + } + + if (a_tensor.element == library::NumericTypeID::kS8 || + b_tensor.element == library::NumericTypeID::kS8 || + c_tensor.element == library::NumericTypeID::kS8 + ) { + + return Status::kErrorNotSupported; + } + + // S4 not supported in cuDNN + if (a_tensor.element == library::NumericTypeID::kS4 || + b_tensor.element == library::NumericTypeID::kS4 || + c_tensor.element == library::NumericTypeID::kS4 + ) { + + return Status::kErrorNotSupported; + } + + return Status::kSuccess; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace profiler +} // namespace cutlass + +#endif diff --git a/tools/profiler/src/cudnn_helpers.h b/tools/profiler/src/cudnn_helpers.h new file mode 100644 index 000000000..58fe4e678 --- /dev/null +++ b/tools/profiler/src/cudnn_helpers.h @@ -0,0 +1,584 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Helper functions for mapping CUTLASS concepts to cuDNN. + +*/ + +#pragma once +#if CUTLASS_ENABLE_CUDNN +#include +#include +#include +#include "cutlass/cutlass.h" +#include "cutlass/util/device_memory.h" +#include "cutlass/library/library.h" +#include "enumerated_types.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace profiler { + +///////////////////////////////////////////////////////////////////////////////////////////////// +/// Converts a cuDNN status to cutlass::Status +Status get_cutlass_status(cudnnStatus_t cudnn_status); + +/// Converts a cuDNN status to cutlass::profiler::Disposition +Disposition get_cutlass_disposition(cudnnStatus_t cudnn_status); + +/// Checks cudnnStatus_t converts to cutlas status and returns if Status::kSuccess o.w. throws exception +Status checkCudnnErr(cudnnStatus_t cudnn_status); + +/// Maps a CUTLASS conv mode to a cuDNN conv mode enumeration +bool get_cudnn_conv_mode(cudnnConvolutionMode_t &cudnn_conv_mode, conv::Mode conv_mode); + +/// Maps a CUTLASS layout type to a cuDNN data type enumeration +bool get_cudnn_layout(cudnnTensorFormat_t &cudnn_layout, library::LayoutTypeID layout); + +/// Maps a CUTLASS numeric type to a cuDNN data type enumeration +bool get_cudnn_datatype(cudnnDataType_t &cudnn_element_type, library::NumericTypeID element_type); + +/// Maps CUTLASS math OpcodeClassID and MathOperationID to cuDNN math_type +bool get_cudnn_mathtype(cudnnMathType_t &cudnn_math_type, library::ConvDescription const &conv_desc); + +/// Returns a status if cudnn can satisfy a particular Conv2d description +Status cudnn_satisfies(library::ConvDescription const &desc, library::Conv2dConfiguration const &configuration); + +/// Returns a status if cudnn can satisfy a particular Conv3d description +Status cudnn_satisfies(library::ConvDescription const &desc, library::Conv3dConfiguration const &configuration); + +/// Cudnn compute type seems to be hardcoded to float (To handle a possible cudnn issue) +float cast_cudnn_compute_type_to_float(library::NumericTypeID type, void const * src); + + +/// This is a helper class to create cudnnHandle_t automatically on CudnnCreate object creation and +/// to destroy cudnnHandle_t on CudnnCreate object destruction. +/// Additionaly, it provides implicit cast from CudnnCreate's object to cudnnHandle_t's object +class CudnnCreate { +private: + cudnnHandle_t handle; + cudnnStatus_t status; + +public: + CudnnCreate() { + status = cudnnCreate(&handle); + } + + ~CudnnCreate() { + cudnnDestroy(handle); + } + + /// Implicit cast CudnnCreate object to cudnnHandle_t + operator cudnnHandle_t() const { return handle; } + + /// returns cudnnStatus_t for handle creation + cudnnStatus_t get_cudnn_create_status() { return status; } +}; + + +namespace detail { + +/// Dispatcher to cudnn convolution operators +struct cudnnConvDispatcher { + + // + // Data members + // + //library::Conv2dConfiguration configuration; + library::ConvArguments arguments; + library::ConvKind conv_kind; + + // cudnn-specific data structures to fill cudnn API call arguments + // cudnn activation, filter, and output descriptors + cudnnTensorDescriptor_t activation_desc; + cudnnFilterDescriptor_t filter_desc; + cudnnTensorDescriptor_t output_desc; + cudnnConvolutionDescriptor_t conv_desc; + + // cudnn datatypes + cudnnDataType_t data_type_activation; + cudnnDataType_t data_type_filter; + cudnnDataType_t data_type_output; + + // cudnn layouts + cudnnTensorFormat_t layout_activation; + cudnnTensorFormat_t layout_filter; + cudnnTensorFormat_t layout_output; + + // cudnn convolution mode + cudnnConvolutionMode_t conv_mode; + + // cudnn math type (tensorop, tensorop with conversion, simt) + cudnnMathType_t math_type; + + // cudnn compute data type + cudnnDataType_t compute_type; + + // cudnn compute type seems to be hardcoded to float (to handle a possible a cudnn issue) + float alpha; + float beta; + + // cudnn workspace + size_t workspace_size_in_bytes = 0; + cutlass::device_memory::allocation workspace; + + // select cudnn's implicit gemm precomputed algorithm with tensor operations + static cudnnConvolutionFwdAlgo_t const fprop_algo = CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM; + static cudnnConvolutionBwdDataAlgo_t const dgrad_algo = CUDNN_CONVOLUTION_BWD_DATA_ALGO_1; + static cudnnConvolutionBwdFilterAlgo_t const wgrad_algo = CUDNN_CONVOLUTION_BWD_FILTER_ALGO_1; + + Status status; + + // + // Methods + // + + // TODO: unify ctor cudnnConvDispatcher for conv2d and conv3d by unifying Conv2dConfigration + + // ctor for conv2d + cudnnConvDispatcher( + library::ConvDescription const &op_desc, + library::Conv2dConfiguration configuration, + library::ConvArguments arguments_, + cudnnHandle_t handle + ): + //configuration(configuration_), + arguments(arguments_), + conv_kind(op_desc.conv_kind), + status(Status::kSuccess) { + + bool good = true; + + // Get cudnn datatype, layout, and convolution mode from library::ConvDescription + good = (good && get_cudnn_datatype(data_type_activation, op_desc.A.element)); + good = (good && get_cudnn_datatype(data_type_filter, op_desc.B.element)); + good = (good && get_cudnn_datatype(data_type_output, op_desc.C.element)); + good = (good && get_cudnn_layout(layout_activation, op_desc.A.layout)); + good = (good && get_cudnn_layout(layout_filter, op_desc.B.layout)); + good = (good && get_cudnn_layout(layout_output, op_desc.C.layout)); + good = (good && get_cudnn_conv_mode(conv_mode, configuration.problem_size.mode)); + // Get cudnn mathtype (cudnnMathType_t) + good = (good && get_cudnn_mathtype(math_type, op_desc)); + good = (good && get_cudnn_datatype( + compute_type, + op_desc.tile_description.math_instruction.element_accumulator)); + // Check cutlass Conv2d description has equivalent operator in cudnn + if (!good) { + status = Status::kErrorNotSupported; + return; + } + // cudnn compute type seems to be hardcoded to float (to handle a possible a cudnn issue) + alpha = cast_cudnn_compute_type_to_float(op_desc.element_epilogue, arguments.alpha); + beta = cast_cudnn_compute_type_to_float(op_desc.element_epilogue, arguments.beta); + + // Create convolution descriptor object + status = get_cutlass_status(cudnnCreateConvolutionDescriptor(&conv_desc)); + + // Configure convolution operator + std::vector padding {configuration.problem_size.pad_h, configuration.problem_size.pad_w}; + std::vector stride {configuration.problem_size.stride_h, configuration.problem_size.stride_w}; + std::vector dilation {configuration.problem_size.dilation_h, configuration.problem_size.dilation_w}; + + status = get_cutlass_status( + cudnnSetConvolutionNdDescriptor( + conv_desc, + op_desc.conv_dim, + padding.data(), + stride.data(), + dilation.data(), + conv_mode, + compute_type + )); + + // Set groups + status = get_cutlass_status(cudnnSetConvolutionGroupCount(conv_desc, configuration.problem_size.groups)); + + // Create activation, filter, and output descriptor objects + status = get_cutlass_status(cudnnCreateTensorDescriptor(&activation_desc)); + status = get_cutlass_status(cudnnCreateFilterDescriptor(&filter_desc)); + status = get_cutlass_status(cudnnCreateTensorDescriptor(&output_desc)); + + // Set activation, filter, and output descriptor + status = get_cutlass_status( + cudnnSetTensor4dDescriptor( + activation_desc, + layout_activation, + data_type_activation, + configuration.problem_size.N, + configuration.problem_size.C, + configuration.problem_size.H, + configuration.problem_size.W + )); + + status = get_cutlass_status( + cudnnSetFilter4dDescriptor( + filter_desc, + data_type_filter, + layout_filter, + configuration.problem_size.K, + configuration.problem_size.C, + configuration.problem_size.R, + configuration.problem_size.S + )); + + status = get_cutlass_status( + cudnnSetTensor4dDescriptor( + output_desc, + layout_output, + data_type_output, + configuration.problem_size.N, + configuration.problem_size.K, + configuration.problem_size.P, + configuration.problem_size.Q + )); + + // Set math instruction to tensor op + status = get_cutlass_status( + cudnnSetConvolutionMathType(conv_desc, math_type)); + + // Initialize workspace + switch (conv_kind) { + case library::ConvKind::kFprop: + status = get_cutlass_status( + cudnnGetConvolutionForwardWorkspaceSize( + handle, + activation_desc, + filter_desc, + conv_desc, + output_desc, + fprop_algo, + &workspace_size_in_bytes + )); break; + case library::ConvKind::kDgrad: + status = get_cutlass_status( + cudnnGetConvolutionBackwardDataWorkspaceSize( + handle, + filter_desc, + output_desc, + conv_desc, + activation_desc, + dgrad_algo, + &workspace_size_in_bytes + )); break; + case library::ConvKind::kWgrad: + status = get_cutlass_status( + cudnnGetConvolutionBackwardFilterWorkspaceSize( + handle, + activation_desc, + output_desc, + conv_desc, + filter_desc, + wgrad_algo, + &workspace_size_in_bytes + )); break; + + } + + workspace = cutlass::device_memory::allocation(workspace_size_in_bytes); + } + + + // ctor for conv3d + cudnnConvDispatcher( + library::ConvDescription const &op_desc, + library::Conv3dConfiguration configuration, + library::ConvArguments arguments_, + cudnnHandle_t handle + ): + //configuration(configuration_), + arguments(arguments_), + conv_kind(op_desc.conv_kind), + status(Status::kSuccess) { + + bool good = true; + + // Get cudnn datatype, layout, and convolution mode from library::ConvDescription + good = (good && get_cudnn_datatype(data_type_activation, op_desc.A.element)); + good = (good && get_cudnn_datatype(data_type_filter, op_desc.B.element)); + good = (good && get_cudnn_datatype(data_type_output, op_desc.C.element)); + + good = (good && get_cudnn_layout(layout_activation, op_desc.A.layout)); + good = (good && get_cudnn_layout(layout_filter, op_desc.B.layout)); + good = (good && get_cudnn_layout(layout_output, op_desc.C.layout)); + + good = (good && get_cudnn_conv_mode(conv_mode, configuration.problem_size.mode)); + + // cudnn compute type seems to be hardcoded to float (to handle a possible a cudnn issue) + alpha = cast_cudnn_compute_type_to_float(op_desc.element_epilogue, arguments.alpha); + beta = cast_cudnn_compute_type_to_float(op_desc.element_epilogue, arguments.beta); + + good = (good && get_cudnn_datatype( + compute_type, + op_desc.tile_description.math_instruction.element_accumulator)); + + // Check cutlass Conv2d description has equivalent operator in cudnn + if (!good) { + status = Status::kErrorNotSupported; + } + + // Create convolution descriptor object + status = get_cutlass_status(cudnnCreateConvolutionDescriptor(&conv_desc)); + + // Configure convolution operator + std::vector padding {configuration.problem_size.pad_d, configuration.problem_size.pad_h, configuration.problem_size.pad_w}; + std::vector stride {configuration.problem_size.stride_d, configuration.problem_size.stride_h, configuration.problem_size.stride_w}; + std::vector dilation {configuration.problem_size.dilation_d, configuration.problem_size.dilation_h, configuration.problem_size.dilation_w}; + + status = get_cutlass_status( + cudnnSetConvolutionNdDescriptor( + conv_desc, + op_desc.conv_dim, + padding.data(), + stride.data(), + dilation.data(), + conv_mode, + compute_type + )); + + // Set groups + status = get_cutlass_status(cudnnSetConvolutionGroupCount(conv_desc, configuration.problem_size.groups)); + + // Create activation, filter, and output descriptor objects + status = get_cutlass_status(cudnnCreateTensorDescriptor(&activation_desc)); + status = get_cutlass_status(cudnnCreateFilterDescriptor(&filter_desc)); + status = get_cutlass_status(cudnnCreateTensorDescriptor(&output_desc)); + + // Set activation descriptor + std::vector activation_extent { + configuration.problem_size.N, + configuration.problem_size.C, + configuration.problem_size.D, + configuration.problem_size.H, + configuration.problem_size.W + }; + + std::vector activation_stride { + configuration.layout_activations.stride()[3], + 1, + configuration.layout_activations.stride()[2], + configuration.layout_activations.stride()[1], + configuration.layout_activations.stride()[0] + }; + + status = get_cutlass_status( + cudnnSetTensorNdDescriptor( + activation_desc, + data_type_activation, + op_desc.conv_dim + 2, + activation_extent.data(), + activation_stride.data() + )); + + // Set filter descriptor + std::vector filter_extent { + configuration.problem_size.K, + configuration.problem_size.C, + configuration.problem_size.T, + configuration.problem_size.R, + configuration.problem_size.S + }; + + std::vector filter_stride { + configuration.layout_filters.stride()[3], + 1, + configuration.layout_filters.stride()[2], + configuration.layout_filters.stride()[1], + configuration.layout_filters.stride()[0] + }; + + status = get_cutlass_status( + cudnnSetFilterNdDescriptor( + filter_desc, + data_type_filter, + layout_filter, + op_desc.conv_dim + 2, + filter_extent.data() + )); + + + // Set output descriptor + std::vector output_extent { + configuration.problem_size.N, + configuration.problem_size.K, + configuration.problem_size.Z, + configuration.problem_size.P, + configuration.problem_size.Q + }; + + std::vector output_stride { + configuration.layout_output.stride()[3], + 1, + configuration.layout_output.stride()[2], + configuration.layout_output.stride()[1], + configuration.layout_output.stride()[0] + }; + + status = get_cutlass_status( + cudnnSetTensorNdDescriptor( + output_desc, + data_type_output, + op_desc.conv_dim + 2, + output_extent.data(), + output_stride.data() + )); + + // Set math instruction to tensor op + status = get_cutlass_status( + cudnnSetConvolutionMathType(conv_desc, math_type)); + + // Initialize workspace + switch (conv_kind) { + case library::ConvKind::kFprop: + status = get_cutlass_status( + cudnnGetConvolutionForwardWorkspaceSize( + handle, + activation_desc, + filter_desc, + conv_desc, + output_desc, + fprop_algo, + &workspace_size_in_bytes + )); break; + case library::ConvKind::kDgrad: + status = get_cutlass_status( + cudnnGetConvolutionBackwardDataWorkspaceSize( + handle, + filter_desc, + output_desc, + conv_desc, + activation_desc, + dgrad_algo, + &workspace_size_in_bytes + )); break; + case library::ConvKind::kWgrad: + status = get_cutlass_status( + cudnnGetConvolutionBackwardFilterWorkspaceSize( + handle, + activation_desc, + output_desc, + conv_desc, + filter_desc, + wgrad_algo, + &workspace_size_in_bytes + )); break; + + } + + workspace = cutlass::device_memory::allocation(workspace_size_in_bytes); + } + + /// Executes Conv2d operater from cudnn library + cudnnStatus_t operator()(cudnnHandle_t handle) { + + switch (conv_kind) { + case library::ConvKind::kFprop: + return cudnnConvolutionForward( + handle, + &alpha, + activation_desc, + activation(), + filter_desc, + filter(), + conv_desc, + fprop_algo, + workspace.get(), + workspace_size_in_bytes, + &beta, + output_desc, + arguments.D + ); + case library::ConvKind::kDgrad: + return cudnnConvolutionBackwardData( + handle, + &alpha, + filter_desc, + filter(), + output_desc, + output(), + conv_desc, + dgrad_algo, + workspace.get(), + workspace_size_in_bytes, + &beta, + activation_desc, + arguments.D + ); + case library::ConvKind::kWgrad: + return cudnnConvolutionBackwardFilter( + handle, + &alpha, + activation_desc, + activation(), + output_desc, + output(), + conv_desc, + wgrad_algo, + workspace.get(), + workspace_size_in_bytes, + &beta, + filter_desc, + arguments.D + ); + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns Actviation Tensor + void const * activation() const { + switch(conv_kind) { + case library::ConvKind::kFprop : return arguments.A; + case library::ConvKind::kDgrad : return arguments.C; + case library::ConvKind::kWgrad : return arguments.B; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns Filter Tensor + void const *filter() const { + switch(conv_kind) { + case library::ConvKind::kFprop : return arguments.B; + case library::ConvKind::kDgrad : return arguments.B; + case library::ConvKind::kWgrad : return arguments.C; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } + + // Returns Output Tensor + void const *output() const { + switch(conv_kind) { + case library::ConvKind::kFprop : return arguments.C; + case library::ConvKind::kDgrad : return arguments.A; + case library::ConvKind::kWgrad : return arguments.A; + default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)"); + } + } +}; + +} // namespace detail +///////////////////////////////////////////////////////////////////////////////////////////////// +#endif //#if CUTLASS_ENABLE_CUDNN +} // namespace profiler +} // namespace cutlass diff --git a/tools/profiler/src/cutlass_profiler.cu b/tools/profiler/src/cutlass_profiler.cu index 9934ff4cd..c1e33ad61 100644 --- a/tools/profiler/src/cutlass_profiler.cu +++ b/tools/profiler/src/cutlass_profiler.cu @@ -32,6 +32,8 @@ // Profiler includes #include "cutlass_profiler.h" #include "gemm_operation_profiler.h" +#include "conv2d_operation_profiler.h" +#include "conv3d_operation_profiler.h" #include "sparse_gemm_operation_profiler.h" ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -50,6 +52,10 @@ CutlassProfiler::CutlassProfiler( operation_profilers_.emplace_back(new SparseGemmOperationProfiler(options)); + operation_profilers_.emplace_back(new Conv2dOperationProfiler(options)); + + operation_profilers_.emplace_back(new Conv3dOperationProfiler(options)); + } CutlassProfiler::~CutlassProfiler() { @@ -159,6 +165,8 @@ void CutlassProfiler::print_usage_(std::ostream &out) { out << "\n\nFor details about a particular function, specify the function name with --help.\n\nExample:\n\n" << " $ cutlass_profiler --operation=Gemm --help\n\n" + << " $ cutlass_profiler --operation=Conv3d --help\n\n" + << " $ cutlass_profiler --operation=Conv2d --help\n\n" ; } diff --git a/tools/profiler/src/device_allocation.cu b/tools/profiler/src/device_allocation.cu index 777fb4d0a..247bcccf1 100644 --- a/tools/profiler/src/device_allocation.cu +++ b/tools/profiler/src/device_allocation.cu @@ -133,7 +133,18 @@ std::vector DeviceAllocation::get_packed_layout( case library::LayoutTypeID::kTensorNDHWC: stride = get_packed_layout_stride(extent); break; - + case library::LayoutTypeID::kTensorNC32HW32: + stride = get_packed_layout_stride>(extent); + break; + case library::LayoutTypeID::kTensorNC64HW64: + stride = get_packed_layout_stride>(extent); + break; + case library::LayoutTypeID::kTensorC32RSK32: + stride = get_packed_layout_stride>(extent); + break; + case library::LayoutTypeID::kTensorC64RSK64: + stride = get_packed_layout_stride>(extent); + break; default: break; } @@ -247,6 +258,18 @@ size_t DeviceAllocation::construct_layout( case library::LayoutTypeID::kTensorNDHWC: return construct_layout_(bytes, layout_id, extent, stride); + case library::LayoutTypeID::kTensorNC32HW32: + return construct_layout_>(bytes, layout_id, extent, stride); + + case library::LayoutTypeID::kTensorNC64HW64: + return construct_layout_>(bytes, layout_id, extent, stride); + + case library::LayoutTypeID::kTensorC32RSK32: + return construct_layout_>(bytes, layout_id, extent, stride); + + case library::LayoutTypeID::kTensorC64RSK64: + return construct_layout_>(bytes, layout_id, extent, stride); + default: break; } @@ -1362,6 +1385,18 @@ static void write_tensor_csv_static_type( case library::LayoutTypeID::kTensorNDHWC: write_tensor_csv_static_tensor_view(out, allocation); break; + case library::LayoutTypeID::kTensorNC32HW32: + write_tensor_csv_static_tensor_view>(out, allocation); + break; + case library::LayoutTypeID::kTensorNC64HW64: + write_tensor_csv_static_tensor_view>(out, allocation); + break; + case library::LayoutTypeID::kTensorC32RSK32: + write_tensor_csv_static_tensor_view>(out, allocation); + break; + case library::LayoutTypeID::kTensorC64RSK64: + write_tensor_csv_static_tensor_view>(out, allocation); + break; default: throw std::runtime_error("Unhandled layout"); } diff --git a/tools/profiler/src/operation_profiler.cu b/tools/profiler/src/operation_profiler.cu index 2bbf2eeb1..edd6f07ce 100644 --- a/tools/profiler/src/operation_profiler.cu +++ b/tools/profiler/src/operation_profiler.cu @@ -243,7 +243,7 @@ int OperationProfiler::profile_all( ProblemSpace::Iterator problem_it = problem_space.begin(); ProblemSpace::Iterator problem_end = problem_space.end(); - bool continue_profiling = true; + bool continue_profiling = true, internal_error = false; // For each problem in problem space for (; continue_profiling && problem_it != problem_end; ++problem_it) { @@ -302,7 +302,8 @@ int OperationProfiler::profile_all( if (status == Status::kErrorInternal) { // Stop profiling if there was an internal error - return false; + internal_error = true; + break; } else if (status != Status::kSuccess) { // If the workspace could not be initialized for any other reason, continue to @@ -322,7 +323,8 @@ int OperationProfiler::profile_all( if (status == Status::kErrorInternal) { // Stop profiling if there was an internal error - return false; + internal_error = true; + break; } else if (status != Status::kSuccess) { // If the workspace could not be initialized for any other reason, continue to @@ -336,8 +338,9 @@ int OperationProfiler::profile_all( // // B. Verify CUTLASS - if (continue_profiling) { - + + if (continue_profiling && options.profiling.provider_enabled(library::Provider::kCUTLASS)) { + continue_profiling = this->verify_cutlass( options, report, @@ -368,6 +371,7 @@ int OperationProfiler::profile_all( // // D. Profile // + if (continue_profiling && options.profiling.enabled) { continue_profiling = this->profile( @@ -392,10 +396,7 @@ int OperationProfiler::profile_all( } } - // 3. Emit report - report.close(); - - return 0; + return internal_error ? 1 : 0; } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/profiler/src/options.cu b/tools/profiler/src/options.cu index e2d3e131f..6bac57807 100644 --- a/tools/profiler/src/options.cu +++ b/tools/profiler/src/options.cu @@ -401,6 +401,7 @@ Options::Profiling::Profiling(cutlass::CommandLine const &cmdline) { else { providers.push_back(library::Provider::kCUTLASS); providers.push_back(library::Provider::kCUBLAS); + providers.push_back(library::Provider::kCUDNN); } } @@ -428,8 +429,8 @@ void Options::Profiling::print_usage(std::ostream &out) const { << " --providers= " << " List of providers to be profiled for performance. (default: '*')" << end_of_line - << " Gemm providers {cutlass*" - << "}" << end_of_line + << " Gemm providers {cutlass*, cublas*}" << end_of_line + << " Conv2d providers {cutlass*, cudnn*}" << "\n\n"; } @@ -502,6 +503,7 @@ Options::Verification::Verification(cutlass::CommandLine const &cmdline) { else { providers.push_back(library::Provider::kCUBLAS); providers.push_back(library::Provider::kReferenceDevice); + providers.push_back(library::Provider::kCUDNN); } } @@ -529,6 +531,7 @@ void Options::Verification::print_usage(std::ostream &out) const { << " --verification-providers= " << " List of providers used to verify result. (default: '*')" << end_of_line << " Gemm verification-providers {cublas*}" << end_of_line + << " Conv2d verification-providers {cudnn*, device*, host}" << "\n\n"; } @@ -570,6 +573,7 @@ Options::Report::Report(cutlass::CommandLine const &cmdline) { cmdline.get_cmd_line_argument("append", append, false); cmdline.get_cmd_line_argument("output", output_path); + cmdline.get_cmd_line_argument("junit-output", junit_output_path); if (cmdline.check_cmd_line_flag("tags")) { cmdline.get_cmd_line_argument_pairs("tags", pivot_tags); @@ -591,6 +595,9 @@ void Options::Report::print_usage(std::ostream &out) const { << " --output= " << " Path to output file for machine readable results. Operation kind and '.csv' is appended.\n\n" + << " --junit-output= " + << " Path to junit output file for result reporting. Operation kind and '.junit.xml' is appended.\n\n" + << " --report-not-run= " << " If true, reports the status of all kernels including those that" << end_of_line << " do not satisfy the given arguments.\n\n" @@ -608,6 +615,7 @@ void Options::Report::print_options(std::ostream &out, int indent) const { out << indent_str(indent) << "append: " << append << "\n" << indent_str(indent) << "output: " << output_path << "\n" + << indent_str(indent) << "junit-output: " << junit_output_path << "\n" << indent_str(indent) << "report_not_run: " << report_not_run << "\n" << indent_str(indent) << "tags:\n"; diff --git a/tools/profiler/src/options.h b/tools/profiler/src/options.h index 48463efa5..79e016997 100644 --- a/tools/profiler/src/options.h +++ b/tools/profiler/src/options.h @@ -218,6 +218,9 @@ public: /// Path to a file containing results std::string output_path; + /// Path to a file containing junit xml results + std::string junit_output_path; + /// Sequence of tags to attach to each result std::vector> pivot_tags; diff --git a/tools/profiler/src/performance_report.cpp b/tools/profiler/src/performance_report.cpp index 07a7edc95..de184eb04 100644 --- a/tools/profiler/src/performance_report.cpp +++ b/tools/profiler/src/performance_report.cpp @@ -69,11 +69,15 @@ PerformanceReport::PerformanceReport( options_(options), argument_names_(argument_names), problem_index_(0), good_(true), op_kind_(op_kind) { // Strip '.csv' if present - std::string base_path = options_.report.output_path.substr( - 0, options_.report.output_path.rfind(".csv")); - + std::string base_path = options_.report.output_path; + base_path = base_path.substr(0, base_path.rfind(".csv")); op_file_name_ = base_path + "." + to_string(op_kind_) + ".csv"; + base_path = options_.report.junit_output_path; + base_path = base_path.substr(0, base_path.rfind(".xml")); + base_path = base_path.substr(0, base_path.rfind(".junit")); + op_junit_file_name_ = base_path + "." + to_string(op_kind_) + ".junit.xml"; + // // Open output file for operation of PerformanceReport::op_kind // @@ -108,6 +112,21 @@ PerformanceReport::PerformanceReport( print_csv_header_(output_file_) << std::endl; } } + + if (!options_.report.junit_output_path.empty()) { + + junit_output_file_.open(op_junit_file_name_); + + if (!junit_output_file_.good()) { + + std::cerr << "Could not open junit output file at path '" + << options_.report.junit_output_path << "'" << std::endl; + + good_ = false; + } + + print_junit_header_(junit_output_file_); + } } void PerformanceReport::next_problem() { @@ -123,6 +142,10 @@ void PerformanceReport::append_result(PerformanceResult result) { print_result_pretty_(std::cout, result) << std::flush; } + if (junit_output_file_.is_open()) { + print_junit_result_(junit_output_file_, result); + } + if (output_file_.is_open()) { print_result_csv_(output_file_, result) << std::endl; } @@ -143,7 +166,7 @@ void PerformanceReport::append_results(PerformanceResultVector const &results) { } } -void PerformanceReport::close() { +PerformanceReport::~PerformanceReport() { // // Output results to stdout if they were not written to a file already. @@ -161,7 +184,17 @@ void PerformanceReport::close() { } } else if (output_file_.is_open() && options_.report.verbose) { - std::cout << "\n\nWrote results to '" << op_file_name_ << "'" << std::endl; + std::cout << "\nWrote results to '" << op_file_name_ << "'" << std::endl; + } + + if (output_file_.is_open()) { + output_file_.close(); + } + + if (junit_output_file_.is_open()) { + print_junit_footer_(junit_output_file_); + junit_output_file_.close(); + std::cout << "\nWrote jUnit results to '" << op_junit_file_name_ << "'" << std::endl; } } @@ -179,7 +212,8 @@ static const char *disposition_status_color(Disposition disposition) { /// Prints the result in human readable form std::ostream & PerformanceReport::print_result_pretty_( std::ostream &out, - PerformanceResult const &result) { + PerformanceResult const &result, + bool use_shell_coloring) { out << "=============================\n" << " Problem ID: " << result.problem_index << "\n"; @@ -196,14 +230,20 @@ std::ostream & PerformanceReport::print_result_pretty_( out << "\n"; } + std::string shell_color_bright = use_shell_coloring ? SHELL_COLOR_BRIGHT() : ""; + std::string shell_color_end = use_shell_coloring ? SHELL_COLOR_END() : ""; + auto _disposition_status_color = [&](Disposition d) -> const char * { + return use_shell_coloring ? disposition_status_color(d) : ""; + }; + out << "\n" - << " Provider: " << SHELL_COLOR_BRIGHT() << library::to_string(result.provider, true) << SHELL_COLOR_END() << "\n" - << " OperationKind: " << SHELL_COLOR_BRIGHT() << library::to_string(result.op_kind) << SHELL_COLOR_END() << "\n" + << " Provider: " << shell_color_bright << library::to_string(result.provider, true) << shell_color_end << "\n" + << " OperationKind: " << shell_color_bright << library::to_string(result.op_kind) << shell_color_end << "\n" << " Operation: " << result.operation_name << "\n\n" - << " Status: " << SHELL_COLOR_BRIGHT() << library::to_string(result.status, true) << SHELL_COLOR_END() << "\n" - << " Verification: " << SHELL_COLOR_BRIGHT() << (options_.verification.enabled ? "ON":"OFF") << SHELL_COLOR_END() << "\n" - << " Disposition: " << disposition_status_color(result.disposition) << to_string(result.disposition, true) << SHELL_COLOR_END() << "\n\n"; + << " Status: " << shell_color_bright << library::to_string(result.status, true) << shell_color_end << "\n" + << " Verification: " << shell_color_bright << (options_.verification.enabled ? "ON":"OFF") << shell_color_end << "\n" + << " Disposition: " << _disposition_status_color(result.disposition) << to_string(result.disposition, true) << shell_color_end << "\n\n"; // Display individual verification results for each verification-provider if (options_.verification.enabled) { @@ -263,10 +303,6 @@ std::ostream & PerformanceReport::print_csv_header_( << ",OperationKind,Operation,Disposition,Status"; for (auto const &arg_name : argument_names_) { - // Operand E is internal to the sparse kernel - if (arg_name.compare("E") == 0) - continue; - out << "," << arg_name; } @@ -327,6 +363,112 @@ std::ostream & PerformanceReport::print_result_csv_( return out; } +std::ostream & PerformanceReport::print_junit_header_(std::ostream &out) { + + out << "" << std::endl; + out << "" << std::endl; + return out; + +} + +namespace { + + std::string escape_xml_special_chars(const std::string& src) { + std::stringstream dst; + for (char ch : src) { + switch (ch) { + case '&': dst << "&"; break; + case '\'': dst << "'"; break; + case '"': dst << """; break; + case '<': dst << "<"; break; + case '>': dst << ">"; break; + default: dst << ch; break; + } + } + return dst.str(); + } + + template + std::ostream & print_junit_result_property_(std::ostream & os, const std::string & name, const T & property) { + return os << " " << std::endl; + } +} + +std::ostream & PerformanceReport::print_junit_result_(std::ostream &out, PerformanceResult const &result) { + + out << " " << "" << std::endl; + + if (failed) { + out << " " << std::endl; + } + + if (error) { + out << " " << std::endl; + } + + out << " " << std::endl; + + out << " " << std::endl; + + return out; + +} + +std::ostream & PerformanceReport::print_junit_footer_(std::ostream &out) { + + out << "" << std::endl; + return out; + +} + ///////////////////////////////////////////////////////////////////////////////////////////////// } // namespace profiler diff --git a/tools/profiler/src/performance_report.h b/tools/profiler/src/performance_report.h index 1c086e618..500510315 100644 --- a/tools/profiler/src/performance_report.h +++ b/tools/profiler/src/performance_report.h @@ -59,6 +59,12 @@ private: /// Output file containing results std::ofstream output_file_; + /// Operation file name containing junit performance report of op_kind + std::string op_junit_file_name_; + + /// Output file containing junit results + std::ofstream junit_output_file_; + /// Flag indicating the performance report is valid bool good_; @@ -74,6 +80,7 @@ private: public: PerformanceReport(Options const &options, std::vector const &argument_names, library::OperationKind const &op_kind); + ~PerformanceReport(); bool good() const { return good_; } @@ -81,8 +88,6 @@ public: void append_result(PerformanceResult result); void append_results(PerformanceResultVector const &results); - void close(); - public: /// Prints the CSV header @@ -91,10 +96,21 @@ public: /// Prints the CSV std::ostream & print_result_csv_(std::ostream &out, PerformanceResult const &result); + /// @defgroup jUnit Result Generation + /// Functions related to generation of the jUnit results + /// @{ + + std::ostream & print_junit_header_(std::ostream &out); + std::ostream & print_junit_result_(std::ostream &out, PerformanceResult const &result); + std::ostream & print_junit_footer_(std::ostream &out); + + /// @} + /// Prints the result in human readable form std::ostream & print_result_pretty_( std::ostream &out, - PerformanceResult const &result); + PerformanceResult const &result, + bool use_shell_coloring = true); }; ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/profiler/src/problem_space.cpp b/tools/profiler/src/problem_space.cpp index e69b0110e..a8c494321 100644 --- a/tools/profiler/src/problem_space.cpp +++ b/tools/profiler/src/problem_space.cpp @@ -961,6 +961,85 @@ bool arg_as_SplitKModeID( ///////////////////////////////////////////////////////////////////////////////////////////////// +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_ConvModeID( + library::ConvModeID &conv_mode, + KernelArgument::Value const *value_ptr) { + + if (value_ptr->not_null) { + if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) { + + conv_mode = library::from_string( + static_cast(value_ptr)->element); + + if (conv_mode == library::ConvModeID::kInvalid) { + throw std::runtime_error( + "arg_as_ConvModeID() - illegal cast."); + } + } + else { + + throw std::runtime_error( + "arg_as_ConvModeID() - illegal cast."); + } + return true; + } + return false; +} + +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_ConvModeID( + library::ConvModeID &conv_mode, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + size_t idx = problem_space.argument_index(name); + KernelArgument::Value const *value_ptr = problem.at(idx).get(); + + return arg_as_ConvModeID(conv_mode, value_ptr); +} + +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_ProviderID( + library::Provider &provider, + KernelArgument::Value const *value_ptr) { + + if (value_ptr->not_null) { + if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) { + + provider = library::from_string( + static_cast(value_ptr)->element); + + if (provider == library::Provider::kInvalid) { + throw std::runtime_error( + "arg_as_ProviderID() - illegal cast."); + } + } + else { + + throw std::runtime_error( + "arg_as_ProviderID() - illegal cast."); + } + return true; + } + return false; +} + +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_ProviderID( + library::Provider &provider, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + size_t idx = problem_space.argument_index(name); + KernelArgument::Value const *value_ptr = problem.at(idx).get(); + + return arg_as_ProviderID(provider, value_ptr); +} +///////////////////////////////////////////////////////////////////////////////////////////////// + /// Lexically casts an argument to a given type stored in a byte array. Returns true if not null. bool arg_as_scalar( std::vector &bytes, @@ -1049,9 +1128,94 @@ bool tensor_description_satisfies( return false; } +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Returns true if conv_kind satisfies the value +bool conv_kind_satisfies( + library::ConvKind const &conv_kind, + EnumeratedTypeArgument::EnumeratedTypeValue const *value_ptr) { + + if (value_ptr->not_null) { + library::ConvKind conv_kind_cmd_line = + library::from_string(value_ptr->element); + + if (conv_kind_cmd_line != library::ConvKind::kUnknown && + conv_kind_cmd_line != conv_kind) { + + return false; + } + } + + return true; +} + +/// Returns true if conv_kind satisfies the value +bool conv_kind_satisfies( + library::ConvKind const &conv_kind, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + size_t idx = problem_space.argument_index(name); + KernelArgument::Value const *value_ptr = problem.at(idx).get(); + + if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) { + return conv_kind_satisfies( + conv_kind, + static_cast(value_ptr)); + } + else { + throw std::runtime_error("Kernel argument mismatch"); + } + + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Returns true if a iterator algorithm satisfies the value +bool iterator_algorithm_satisfies( + library::IteratorAlgorithmID const &iterator_algorithm, + EnumeratedTypeArgument::EnumeratedTypeValue const *value_ptr) { + + if (value_ptr->not_null) { + library::IteratorAlgorithmID iterator_algorithm_cmd_line = + library::from_string(value_ptr->element); + + if (iterator_algorithm_cmd_line != library::IteratorAlgorithmID::kNone && + iterator_algorithm_cmd_line != iterator_algorithm) { + + return false; + } + } + + return true; +} + +/// Returns true if a iterator algorithm satisfies the value +bool iterator_algorithm_satisfies( + library::IteratorAlgorithmID const &iterator_algorithm, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem) { + + size_t idx = problem_space.argument_index(name); + KernelArgument::Value const *value_ptr = problem.at(idx).get(); + + if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) { + return iterator_algorithm_satisfies( + iterator_algorithm, + static_cast(value_ptr)); + } + else { + throw std::runtime_error("Kernel argument mismatch"); + } + + return false; +} + ///////////////////////////////////////////////////////////////////////////////////////////////// } // namespace profiler } // namespace cutlass ///////////////////////////////////////////////////////////////////////////////////////////////// - diff --git a/tools/profiler/src/problem_space.h b/tools/profiler/src/problem_space.h index 8a9ee4f2e..8e10dbafc 100644 --- a/tools/profiler/src/problem_space.h +++ b/tools/profiler/src/problem_space.h @@ -909,6 +909,37 @@ bool arg_as_SplitKModeID( ProblemSpace const &problem_space, ProblemSpace::Problem const &problem); +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_ConvModeID(library::ConvModeID &conv_mode, KernelArgument::Value const *value_ptr); + +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_ConvModeID( + library::ConvModeID &conv_mode, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_IteratorAlgorithmID(library::IteratorAlgorithmID &iterator_algorithm, KernelArgument::Value const *value_ptr); + +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_IteratorAlgorithmID( + library::IteratorAlgorithmID &iterator_algorithm, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_ProviderID(library::Provider &provider, KernelArgument::Value const *value_ptr); + +/// Lexically casts an argument to an int64 if it is defined. Returns true if not null. +bool arg_as_ProviderID( + library::Provider &provider, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + /// Lexically casts an argument to a given type stored in a byte array. Returns true if not null. bool arg_as_scalar( std::vector &bytes, @@ -935,10 +966,34 @@ bool tensor_description_satisfies( ProblemSpace const &problem_space, ProblemSpace::Problem const &problem); + +/// Returns true if a conv kind satisfies the value +bool conv_kind_satisfies( + library::ConvKind const &conv_kind, + EnumeratedTypeArgument::EnumeratedTypeValue const *value_ptr); + +/// Returns true if a conv kind satisfies the value +bool conv_kind_satisfies( + library::ConvKind const &conv_kind, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +/// Returns true if a iterator algorithm satisfies the value +bool iterator_algorithm_satisfies( + library::IteratorAlgorithmID const &iterator_algorithm, + EnumeratedTypeArgument::EnumeratedTypeValue const *value_ptr); + +/// Returns true if a iterator algorithm satisfies the value +bool iterator_algorithm_satisfies( + library::IteratorAlgorithmID const &iterator_algorithm, + char const *name, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + ///////////////////////////////////////////////////////////////////////////////////////////////// } // namespace profiler } // namespace cutlass //////////////////////////////////////////////////////////////////////////////////////////////// - diff --git a/tools/profiler/src/reduction_operation_profiler.h b/tools/profiler/src/reduction_operation_profiler.h new file mode 100644 index 000000000..e00dcc0b6 --- /dev/null +++ b/tools/profiler/src/reduction_operation_profiler.h @@ -0,0 +1,167 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ +/* \file + \brief Defines profiling functionality for reduction operation + +*/ + +#pragma once + +#include +#include +#include +#include +#include + +// CUTLASS Library includes +#include "cutlass/library/library.h" +#include "cutlass/library/util.h" +#include "cutlass/library/manifest.h" + +// Profiler includes +#include "options.h" +#include "device_context.h" +#include "operation_profiler.h" +#include "performance_result.h" +#include "problem_space.h" +#if CUTLASS_ENABLE_CUDNN +#include "cudnn_helpers.h" +#endif //#if CUTLASS_ENABLE_CUDNN +#include "debug.h" + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace cutlass { +namespace profiler { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Abstract base class for each math function +class ReductionOperationProfiler : public OperationProfiler { +public: + + + /// Workspace used + struct ReductionWorkspace { + + /// Conv device allocations + DeviceAllocation *Workspace; + DeviceAllocation *Source; + DeviceAllocation *Destination; + DeviceAllocation *Reference; + + /// Library configuration and arguments + library::ReductionConfiguration configuration; + library::ReductionArguments arguments; + + /// Buffer used for the cutlass operations' host workspace + std::vector host_workspace; + + /// Buffer used for the cutlass operations' device workspace + DeviceAllocation device_workspace; + + // + // Methods + // + + ReductionWorkspace(): + Workspace(nullptr), Source(nullptr), Destination(nullptr), Reference(nullptr) { } + }; + +protected: + + // + // Data members + // + + /// Reduction problem obtained from problem space + MatrixCoord problem_; + + /// Device memory allocations + ReductionWorkspace conv_workspace_; + + +public: + // + // Methods + // + + /// Ctor + ReductionOperationProfiler(Options const &options); + + /// Destructor + virtual ~ReductionOperationProfiler(); + + /// Prints usage statement for the math function + virtual void print_usage(std::ostream &out) const; + + /// Prints examples + virtual void print_examples(std::ostream &out) const; + + /// Extracts the problem dimensions + virtual Status initialize_configuration( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Initializes workspace + virtual Status initialize_workspace( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Verifies CUTLASS against references + virtual bool verify_cutlass( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + + /// Measures performance results + virtual bool profile( + Options const &options, + PerformanceReport &report, + DeviceContext &device_context, + library::Operation const *operation, + ProblemSpace const &problem_space, + ProblemSpace::Problem const &problem); + +}; + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace profiler +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/tools/profiler/src/sparse_gemm_operation_profiler.cu b/tools/profiler/src/sparse_gemm_operation_profiler.cu index 702b79bb6..7eff2062b 100644 --- a/tools/profiler/src/sparse_gemm_operation_profiler.cu +++ b/tools/profiler/src/sparse_gemm_operation_profiler.cu @@ -227,6 +227,9 @@ void SparseGemmOperationProfiler::SparseGemmProblem::initialize_result( set_argument(result, "C", problem_space, std::string(library::to_string(operation_desc.C.element)) + ":" + library::to_string(operation_desc.C.layout)); + set_argument(result, "E", problem_space, + std::string(library::to_string(operation_desc.E.element)) + ":" + library::to_string(operation_desc.E.layout)); + set_argument(result, "m", problem_space, m); set_argument(result, "n", problem_space, n); set_argument(result, "k", problem_space, k); diff --git a/tools/util/include/cutlass/util/host_reorder.h b/tools/util/include/cutlass/util/host_reorder.h index 1d12add3e..660ee0f95 100644 --- a/tools/util/include/cutlass/util/host_reorder.h +++ b/tools/util/include/cutlass/util/host_reorder.h @@ -62,6 +62,18 @@ void reorder_column(TensorRef dest, } } +template +void reorder_convK(TensorRef dest, + TensorRef src, + cutlass::gemm::GemmCoord problem_size) { + + TensorRef> mappedDest(dest.data(), dest.stride(0)); + TensorRef> mappedSrc(src.data(), src.stride(0)); + + reorder_column( + mappedDest, mappedSrc, problem_size); +} + /// This is needed for the sparse tensor core kernels. The purpose /// is to use ldmatrix to load from shared memory to the register file. template diff --git a/tools/util/include/cutlass/util/reference/device/convolution.h b/tools/util/include/cutlass/util/reference/device/convolution.h new file mode 100644 index 000000000..843b6b15b --- /dev/null +++ b/tools/util/include/cutlass/util/reference/device/convolution.h @@ -0,0 +1,1536 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief Reference implementation for convolution in device-side code. +*/ + +#pragma once + +#include "cutlass/coord.h" +#include "cutlass/functional.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/matrix_shape.h" +#include "cutlass/numeric_conversion.h" +#include "cutlass/numeric_types.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/conv3d_problem_size.h" + +namespace cutlass { +namespace reference { +namespace device { + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace kernel { + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// Conv2d device reference kernel +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Conv2d Fprop kernel - y = fprop(x, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add, + int kThreadM = 2, // shape of a thread's tile in the GEMM M dimension + int kThreadN = 4, // shape of a thread's tile in the GEMM N dimension + int kCtaShapeM = 16, // shape of a threadblock in units of threads + int kCtaShapeN = 8 // shape of a threadblock in units of threads +> +__global__ void Conv2dFprop( + conv::Conv2dProblemSize problem_size, + TensorRef tensor_x, + TensorRef tensor_w, + TensorRef tensor_y_in, + TensorRef tensor_y_out, + ElementCompute alpha, + ElementCompute beta + ) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + ElementAccumulator element_A[kThreadM]; + ElementAccumulator element_B[kThreadN]; + ElementAccumulator accum[kThreadM][kThreadN]; + + int64_t npq_start = int64_t(blockIdx.x) * kCtaShapeM * kThreadM + threadIdx.x * kThreadM; + int k_start = blockIdx.y * kCtaShapeN * kThreadN + threadIdx.y * kThreadN; + + int thread_n[kThreadM]; + int thread_p[kThreadM]; + int thread_q[kThreadM]; + + // Compute N, P, Q coordinates for each row of a thread's tile + int64_t PQ = int64_t(problem_size.P) * problem_size.Q; + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + int64_t npq = npq_start + m; + + thread_n[m] = int(npq / PQ); + + int64_t residual = npq % PQ; + thread_p[m] = int(residual / problem_size.Q); + thread_q[m] = int(residual % problem_size.Q); + } + + // Clear accumulators + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = ElementAccumulator(); + } + } + + // Compute convolution + for (int R = 0; R < problem_size.R; ++R) { + for (int S = 0; S < problem_size.S; ++S) { + for (int C = 0; C < problem_size.C; ++C) { + + // Load from activations tensor + int filter_r = R; + int filter_s = S; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_r = problem_size.R - 1 - R; + filter_s = problem_size.S - 1 - S; + } + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + int h = thread_p[m] * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h; + int w = thread_q[m] * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w; + + if (thread_n[m] < problem_size.N && h >= 0 && h < problem_size.H && w >= 0 && w < problem_size.W) { + element_A[m] = ElementAccumulator(tensor_x.at({thread_n[m], h, w, C})); + } + else { + element_A[m] = ElementAccumulator(); + } + } + + // Load from filters tensor + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + int thread_k = k_start + n; + + if (thread_k < problem_size.K) { + element_B[n] = ElementAccumulator(tensor_w.at({thread_k, R, S, C})); + } + else { + element_B[n] = ElementAccumulator(); + } + } + + // Accumulate matrix product + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = inner_product_op(element_A[m], element_B[n], accum[m][n]); + } + } + } + } + } + + // Write out the results + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + if (thread_n[m] < problem_size.N && thread_p[m] < problem_size.P && thread_q[m] < problem_size.Q) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + int thread_k = k_start + n; + if (thread_k < problem_size.K) { + + ElementCompute c_ref = ElementCompute(); + if (beta != ElementCompute()) { + c_ref = ElementCompute(tensor_y_in.at({thread_n[m], thread_p[m], thread_q[m], thread_k})); + } + + tensor_y_out.at({thread_n[m], thread_p[m], thread_q[m], thread_k}) = convert_op( + alpha * ElementCompute(accum[m][n]) + beta * c_ref); + } + } + } + } +} + +// Conv3d Fprop kernel - y = fprop(x, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add, + int kThreadM = 2, // shape of a thread's tile in the GEMM M dimension + int kThreadN = 4, // shape of a thread's tile in the GEMM N dimension + int kCtaShapeM = 16, // shape of a threadblock in units of threads + int kCtaShapeN = 8 // shape of a threadblock in units of threads +> +__global__ void Conv3dFprop( + conv::Conv3dProblemSize problem_size, + TensorRef tensor_x, + TensorRef tensor_w, + TensorRef tensor_y_in, + TensorRef tensor_y_out, + ElementCompute alpha, + ElementCompute beta + ) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + ElementAccumulator element_A[kThreadM]; + ElementAccumulator element_B[kThreadN]; + ElementAccumulator accum[kThreadM][kThreadN]; + + int64_t nzpq_start = int64_t(blockIdx.x) * kCtaShapeM * kThreadM + threadIdx.x * kThreadM; + int k_start = blockIdx.y * kCtaShapeN * kThreadN + threadIdx.y * kThreadN; + + int thread_n[kThreadM]; + int thread_z[kThreadM]; + int thread_p[kThreadM]; + int thread_q[kThreadM]; + + // Compute N, Z, P, Q coordinates for each row of a thread's tile + int64_t PQ = int64_t(problem_size.P) * problem_size.Q; + int64_t ZPQ = PQ * problem_size.Z; + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + int64_t nzpq = nzpq_start + m; + + thread_n[m] = int(nzpq / ZPQ); + + int64_t residual = nzpq % ZPQ; + thread_z[m] = int(residual / PQ); + + residual = residual % PQ; + thread_p[m] = int(residual / problem_size.Q); + thread_q[m] = int(residual % problem_size.Q); + } + + // Clear accumulators + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = ElementAccumulator(); + } + } + + // Compute convolution + for (int T = 0; T < problem_size.T; ++T) { + for (int R = 0; R < problem_size.R; ++R) { + for (int S = 0; S < problem_size.S; ++S) { + for (int C = 0; C < problem_size.C; ++C) { + + // Load from activations tensor + int filter_t = T; + int filter_r = R; + int filter_s = S; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_t = problem_size.T - 1 - R; + filter_r = problem_size.R - 1 - R; + filter_s = problem_size.S - 1 - S; + } + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + int d = thread_z[m] * problem_size.stride_d - problem_size.pad_d + filter_t * problem_size.dilation_d; + int h = thread_p[m] * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h; + int w = thread_q[m] * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w; + + if (thread_n[m] < problem_size.N && + d >= 0 && d < problem_size.D && + h >= 0 && h < problem_size.H && + w >= 0 && w < problem_size.W) { + + element_A[m] = ElementAccumulator(tensor_x.at({thread_n[m], d, h, w, C})); + } + else { + element_A[m] = ElementAccumulator(); + } + } + + // Load from filters tensor + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + int thread_k = k_start + n; + + if (thread_k < problem_size.K) { + element_B[n] = ElementAccumulator(tensor_w.at({thread_k, T, R, S, C})); + } + else { + element_B[n] = ElementAccumulator(); + } + } + + // Accumulate matrix product + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = inner_product_op(element_A[m], element_B[n], accum[m][n]); + } + } + + } // for (C) + } // for (S) + } // for (R) + } // for (T) + + // Write out the results + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + if (thread_n[m] < problem_size.N && + thread_z[m] < problem_size.Z && + thread_p[m] < problem_size.P && + thread_q[m] < problem_size.Q) { + + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + int thread_k = k_start + n; + if (thread_k < problem_size.K) { + + ElementCompute c_ref = ElementCompute(); + if (beta != ElementCompute()) { + c_ref = ElementCompute(tensor_y_in.at({thread_n[m], thread_z[m], thread_p[m], thread_q[m], thread_k})); + } + + tensor_y_out.at({thread_n[m], thread_z[m], thread_p[m], thread_q[m], thread_k}) = convert_op( + alpha * ElementCompute(accum[m][n]) + beta * c_ref); + } + } // for (n) + + } + } // for (m) +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// Conv2d dgrad kernel - dx = dgrad(dy, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add, + int kThreadM = 2, // shape of a thread's tile in the GEMM M dimension + int kThreadN = 4, // shape of a thread's tile in the GEMM N dimension + int kCtaShapeM = 16, // shape of a threadblock in units of threads + int kCtaShapeN = 8 // shape of a threadblock in units of threads +> +__global__ void Conv2dDgrad( + conv::Conv2dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_w, + TensorRef tensor_dx_in, + TensorRef tensor_dx_out, + ElementCompute alpha, + ElementCompute beta + ) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + ElementAccumulator element_A[kThreadM]; + ElementAccumulator element_B[kThreadN]; + ElementAccumulator accum[kThreadM][kThreadN]; + + int64_t nhw_start = int64_t(blockIdx.x) * kCtaShapeM * kThreadM + threadIdx.x * kThreadM; + int c_start = blockIdx.y * kCtaShapeN * kThreadN + threadIdx.y * kThreadN; + + int thread_n[kThreadM]; + int thread_h[kThreadM]; + int thread_w[kThreadM]; + + // Compute N, H, W coordinates for each row of a thread's tile + int64_t HW = int64_t(problem_size.H) * problem_size.W; + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + int64_t nhw = nhw_start + m; + + thread_n[m] = int(nhw / HW); + + int64_t residual = nhw % HW; + thread_h[m] = int(residual / problem_size.W); + thread_w[m] = int(residual % problem_size.W); + } + + // Clear accumulators + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = ElementAccumulator(); + } + } + + // Compute convolution + for (int R = 0; R < problem_size.R; ++R) { + for (int S = 0; S < problem_size.S; ++S) { + for (int K = 0; K < problem_size.K; ++K) { + + // Load from activations tensor + int filter_r = R; + int filter_s = S; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_r = problem_size.R - 1 - R; + filter_s = problem_size.S - 1 - S; + } + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + int p = thread_h[m] + problem_size.pad_h - filter_r * problem_size.dilation_h; + int q = thread_w[m] + problem_size.pad_w - filter_s * problem_size.dilation_w; + + element_A[m] = ElementAccumulator(); + + if (p >= 0 && !(p % problem_size.stride_h) && q >= 0 && !(q % problem_size.stride_w)) { + + p = p / problem_size.stride_h; + q = q / problem_size.stride_w; + + if (thread_n[m] < problem_size.N && p < problem_size.P && q < problem_size.Q) { + element_A[m] = ElementAccumulator(tensor_dy.at({thread_n[m], p, q, K})); + } + } + } + + // Load from filters tensor + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + int thread_c = c_start + n; + + if (thread_c < problem_size.C) { + element_B[n] = ElementAccumulator(tensor_w.at({K, R, S, thread_c})); + } + else { + element_B[n] = ElementAccumulator(); + } + } + + // Accumulate matrix product + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = inner_product_op(element_A[m], element_B[n], accum[m][n]); + } + } + } + } + } + + // Write out the results + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + if (thread_n[m] < problem_size.N && thread_h[m] < problem_size.H && thread_w[m] < problem_size.W) { + + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + int thread_c = c_start + n; + if (thread_c < problem_size.C) { + + ElementCompute c_ref = ElementCompute(); + if (beta != ElementCompute()) { + c_ref = ElementCompute(tensor_dx_in.at({thread_n[m], thread_h[m], thread_w[m], thread_c})); + } + + tensor_dx_out.at({thread_n[m], thread_h[m], thread_w[m], thread_c}) = convert_op( + alpha * ElementCompute(accum[m][n]) + beta * c_ref); + } + } + } + } +} + +// Conv3d dgrad kernel - dx = dgrad(dy, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add, + int kThreadM = 2, // shape of a thread's tile in the GEMM M dimension + int kThreadN = 4, // shape of a thread's tile in the GEMM N dimension + int kCtaShapeM = 16, // shape of a threadblock in units of threads + int kCtaShapeN = 8 // shape of a threadblock in units of threads +> +__global__ void Conv3dDgrad( + conv::Conv3dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_w, + TensorRef tensor_dx_in, + TensorRef tensor_dx_out, + ElementCompute alpha, + ElementCompute beta + ) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + ElementAccumulator element_A[kThreadM]; + ElementAccumulator element_B[kThreadN]; + ElementAccumulator accum[kThreadM][kThreadN]; + + int64_t ndhw_start = int64_t(blockIdx.x) * kCtaShapeM * kThreadM + threadIdx.x * kThreadM; + int c_start = blockIdx.y * kCtaShapeN * kThreadN + threadIdx.y * kThreadN; + + int thread_n[kThreadM]; + int thread_d[kThreadM]; + int thread_h[kThreadM]; + int thread_w[kThreadM]; + + // Compute N, H, W coordinates for each row of a thread's tile + int64_t HW = int64_t(problem_size.H) * problem_size.W; + int64_t DHW = HW * problem_size.D; + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + int64_t ndhw = ndhw_start + m; + + thread_n[m] = int(ndhw / DHW); + + int64_t residual = ndhw % DHW; + thread_d[m] = int(residual / HW); + + residual = residual % HW; + thread_h[m] = int(residual / problem_size.W); + thread_w[m] = int(residual % problem_size.W); + } + + // Clear accumulators + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = ElementAccumulator(); + } + } + + // Compute convolution + for (int T = 0; T < problem_size.T; ++T) { + for (int R = 0; R < problem_size.R; ++R) { + for (int S = 0; S < problem_size.S; ++S) { + for (int K = 0; K < problem_size.K; ++K) { + + // Load from activations tensor + int filter_t = T; + int filter_r = R; + int filter_s = S; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_t = problem_size.T - 1 - T; + filter_r = problem_size.R - 1 - R; + filter_s = problem_size.S - 1 - S; + } + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + int z = thread_d[m] + problem_size.pad_d - filter_t * problem_size.dilation_d; + int p = thread_h[m] + problem_size.pad_h - filter_r * problem_size.dilation_h; + int q = thread_w[m] + problem_size.pad_w - filter_s * problem_size.dilation_w; + + element_A[m] = ElementAccumulator(); + + if (z >= 0 && !(z % problem_size.stride_d) && + p >= 0 && !(p % problem_size.stride_h) && + q >= 0 && !(q % problem_size.stride_w)) { + + z = z / problem_size.stride_d; + p = p / problem_size.stride_h; + q = q / problem_size.stride_w; + + if (thread_n[m] < problem_size.N && z < problem_size.Z && p < problem_size.P && q < problem_size.Q) { + element_A[m] = ElementAccumulator(tensor_dy.at({thread_n[m], z, p, q, K})); + } + } + } + + // Load from filters tensor + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + int thread_c = c_start + n; + + if (thread_c < problem_size.C) { + element_B[n] = ElementAccumulator(tensor_w.at({K, T, R, S, thread_c})); + } + else { + element_B[n] = ElementAccumulator(); + } + } + + // Accumulate matrix product + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = inner_product_op(element_A[m], element_B[n], accum[m][n]); + } + } + + } // for (C) + } // for (S) + } // for (R) + } // for (T) + + // Write out the results + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + + if (thread_n[m] < problem_size.N && + thread_d[m] < problem_size.D && + thread_h[m] < problem_size.H && + thread_w[m] < problem_size.W) { + + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + int thread_c = c_start + n; + if (thread_c < problem_size.C) { + + ElementCompute c_ref = ElementCompute(); + if (beta != ElementCompute()) { + c_ref = ElementCompute(tensor_dx_in.at({thread_n[m], thread_d[m], thread_h[m], thread_w[m], thread_c})); + } + + tensor_dx_out.at({thread_n[m], thread_d[m], thread_h[m], thread_w[m], thread_c}) = convert_op( + alpha * ElementCompute(accum[m][n]) + beta * c_ref); + } + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// Conv2d wgrad kernel - dw = wgrad(dy, x) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add, + int kThreadM = 2, // shape of a thread's tile in the GEMM M dimension + int kThreadN = 4, // shape of a thread's tile in the GEMM N dimension + int kCtaShapeM = 8, // shape of a threadblock in units of threads + int kCtaShapeN = 16 // shape of a threadblock in units of threads +> +__global__ void Conv2dWgrad( + conv::Conv2dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_x, + TensorRef tensor_dw_in, + TensorRef tensor_dw_out, + ElementCompute alpha, + ElementCompute beta + ) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + ElementAccumulator element_A[kThreadM]; + ElementAccumulator element_B[kThreadN]; + ElementAccumulator accum[kThreadM][kThreadN]; + + int k_start = blockIdx.x * kCtaShapeM * kThreadM + threadIdx.x * kThreadM; + int64_t rsc_start = int64_t(blockIdx.y) * kCtaShapeN * kThreadN + threadIdx.y * kThreadN; + + int thread_r[kThreadN]; + int thread_s[kThreadN]; + int thread_c[kThreadN]; + + // Compute R, S, C coordinates for each row of a thread's tile + int64_t SC = int64_t(problem_size.S) * problem_size.C; + + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + + int64_t rsc = rsc_start + n; + int64_t residual = rsc % SC; + + thread_r[n] = int(rsc / SC); + thread_s[n] = int(residual / problem_size.C); + thread_c[n] = int(residual % problem_size.C); + } + + // Clear accumulators + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = ElementAccumulator(); + } + } + + // Compute convolution + for (int N = 0; N < problem_size.N; ++N) { + for (int P = 0; P < problem_size.P; ++P) { + for (int Q = 0; Q < problem_size.Q; ++Q) { + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + int thread_k = k_start + m; + + element_A[m] = ElementAccumulator(); + + if (thread_k < problem_size.K) { + element_A[m] = ElementAccumulator(tensor_dy.at({N, P, Q, thread_k})); + } + } + + // Load from filters tensor + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + + // Load from activations tensor + int filter_r = thread_r[n]; + int filter_s = thread_s[n]; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_r = problem_size.R - 1 - filter_r; + filter_s = problem_size.S - 1 - filter_s; + } + + int h = P * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h; + int w = Q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w; + + element_B[n] = ElementAccumulator(); + + if (h >= 0 && h < problem_size.H && w >= 0 && w < problem_size.W && thread_c[n] < problem_size.C) { + element_B[n] = ElementAccumulator(tensor_x.at({N, h, w, thread_c[n]})); + } + } + + // Accumulate matrix product + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = inner_product_op(element_A[m], element_B[n], accum[m][n]); + } + } + } + } + } + + // Write out the results + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + int thread_k = k_start + m; + + if (thread_k < problem_size.K) { + + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + + if (thread_r[n] < problem_size.R && thread_s[n] < problem_size.S && thread_c[n] < problem_size.C) { + + ElementCompute c_ref = ElementCompute(); + + if (beta != ElementCompute()) { + c_ref = ElementCompute(tensor_dw_in.at({thread_k, thread_r[n], thread_s[n], thread_c[n]})); + } + + tensor_dw_out.at({thread_k, thread_r[n], thread_s[n], thread_c[n]}) = convert_op( + alpha * ElementCompute(accum[m][n]) + beta * c_ref); + } + } + } + } +} + +// Conv3d wgrad kernel - dw = wgrad(dy, x) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add, + int kThreadM = 2, // shape of a thread's tile in the GEMM M dimension + int kThreadN = 4, // shape of a thread's tile in the GEMM N dimension + int kCtaShapeM = 8, // shape of a threadblock in units of threads + int kCtaShapeN = 16 // shape of a threadblock in units of threads +> +__global__ void Conv3dWgrad( + conv::Conv3dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_x, + TensorRef tensor_dw_in, + TensorRef tensor_dw_out, + ElementCompute alpha, + ElementCompute beta + ) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + ElementAccumulator element_A[kThreadM]; + ElementAccumulator element_B[kThreadN]; + ElementAccumulator accum[kThreadM][kThreadN]; + + int k_start = blockIdx.x * kCtaShapeM * kThreadM + threadIdx.x * kThreadM; + int64_t trsc_start = int64_t(blockIdx.y) * kCtaShapeN * kThreadN + threadIdx.y * kThreadN; + + int thread_t[kThreadN]; + int thread_r[kThreadN]; + int thread_s[kThreadN]; + int thread_c[kThreadN]; + + // Compute R, S, C coordinates for each row of a thread's tile + int64_t SC = int64_t(problem_size.S) * problem_size.C; + int64_t RSC = SC * problem_size.R; + + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + + int64_t trsc = trsc_start + n; + + thread_t[n] = int(trsc / RSC); + + int64_t residual = trsc % RSC; + thread_r[n] = int(residual / SC); + + residual = residual % SC; + thread_s[n] = int(residual / problem_size.C); + thread_c[n] = int(residual % problem_size.C); + } + + // Clear accumulators + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = ElementAccumulator(); + } + } + + // Compute convolution + for (int N = 0; N < problem_size.N; ++N) { + for (int Z = 0; Z < problem_size.Z; ++Z) { + for (int P = 0; P < problem_size.P; ++P) { + for (int Q = 0; Q < problem_size.Q; ++Q) { + + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + int thread_k = k_start + m; + + element_A[m] = ElementAccumulator(); + + if (thread_k < problem_size.K) { + element_A[m] = ElementAccumulator(tensor_dy.at({N, Z, P, Q, thread_k})); + } + } + + // Load from filters tensor + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + + // Load from activations tensor + int filter_t = thread_t[n]; + int filter_r = thread_r[n]; + int filter_s = thread_s[n]; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_t = problem_size.T - 1 - filter_t; + filter_r = problem_size.R - 1 - filter_r; + filter_s = problem_size.S - 1 - filter_s; + } + + int d = Z * problem_size.stride_d - problem_size.pad_w + filter_t * problem_size.dilation_d; + int h = P * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h; + int w = Q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w; + + element_B[n] = ElementAccumulator(); + + if (d >= 0 && d < problem_size.D && + h >= 0 && h < problem_size.H && + w >= 0 && w < problem_size.W && + thread_c[n] < problem_size.C) { + + element_B[n] = ElementAccumulator(tensor_x.at({N, d, h, w, thread_c[n]})); + } + } + + // Accumulate matrix product + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + accum[m][n] = inner_product_op(element_A[m], element_B[n], accum[m][n]); + } + } + + } // for (Q) + } // for (P) + } // for (Z) + } // for (N) + + // Write out the results + CUTLASS_PRAGMA_UNROLL + for (int m = 0; m < kThreadM; ++m) { + int thread_k = k_start + m; + + if (thread_k < problem_size.K) { + + CUTLASS_PRAGMA_UNROLL + for (int n = 0; n < kThreadN; ++n) { + + if (thread_t[n] < problem_size.T && + thread_r[n] < problem_size.R && + thread_s[n] < problem_size.S && + thread_c[n] < problem_size.C) { + + ElementCompute c_ref = ElementCompute(); + + if (beta != ElementCompute()) { + c_ref = ElementCompute(tensor_dw_in.at({thread_k, thread_t[n], thread_r[n], thread_s[n], thread_c[n]})); + } + + tensor_dw_out.at({thread_k, thread_t[n], thread_r[n], thread_s[n], thread_c[n]}) = convert_op( + alpha * ElementCompute(accum[m][n]) + beta * c_ref); + } + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace kernel + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Conv2d Fprop dispatcher - y = fprop(x, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +Status Conv2dFprop( + conv::Conv2dProblemSize problem_size, + TensorRef tensor_x, + TensorRef tensor_w, + TensorRef tensor_y_in, + TensorRef tensor_y_out, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr) { + + // + // Blocking factors improve performance of reference implementation + // + + int const kThreadM = 4; // shape of a thread's tile in the GEMM M dimension + int const kThreadN = 4; // shape of a thread's tile in the GEMM N dimension + int const kCtaShapeM = 16; // shape of a threadblock in units of threads + int const kCtaShapeN = 8; // shape of a threadblock in units of threads + + int64_t npq = int64_t(problem_size.N) * problem_size.P * problem_size.Q; + int64_t blocks_m = (npq + (kCtaShapeM * kThreadM) - 1) / (kCtaShapeM * kThreadM); + + dim3 block(kCtaShapeM, kCtaShapeN); + dim3 grid(uint32_t(blocks_m), (problem_size.K + (kCtaShapeN * kThreadN) - 1) / (kCtaShapeN * kThreadN)); + + kernel::Conv2dFprop< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp, + kThreadM, + kThreadN, + kCtaShapeM, + kCtaShapeN + ><<< grid, block, 0, stream >>>( + problem_size, + tensor_x, + tensor_w, + tensor_y_in, + tensor_y_out, + alpha, + beta + ); + + cudaError_t result = cudaPeekAtLastError(); + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + return Status::kSuccess; +} + +/// Conv3d Fprop dispatcher - y = fprop(x, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +Status Conv3dFprop( + conv::Conv3dProblemSize problem_size, + TensorRef tensor_x, + TensorRef tensor_w, + TensorRef tensor_y_in, + TensorRef tensor_y_out, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr) { + + // + // Blocking factors improve performance of reference implementation + // + + int const kThreadM = 4; // shape of a thread's tile in the GEMM M dimension + int const kThreadN = 4; // shape of a thread's tile in the GEMM N dimension + int const kCtaShapeM = 16; // shape of a threadblock in units of threads + int const kCtaShapeN = 8; // shape of a threadblock in units of threads + + int64_t nzpq = int64_t(problem_size.N) * problem_size.Z * problem_size.P * problem_size.Q; + int64_t blocks_m = (nzpq + (kCtaShapeM * kThreadM) - 1) / (kCtaShapeM * kThreadM); + + dim3 block(kCtaShapeM, kCtaShapeN); + dim3 grid(uint32_t(blocks_m), (problem_size.K + (kCtaShapeN * kThreadN) - 1) / (kCtaShapeN * kThreadN)); + + kernel::Conv3dFprop< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp, + kThreadM, + kThreadN, + kCtaShapeM, + kCtaShapeN + ><<< grid, block, 0, stream >>>( + problem_size, + tensor_x, + tensor_w, + tensor_y_in, + tensor_y_out, + alpha, + beta + ); + + cudaError_t result = cudaPeekAtLastError(); + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + return Status::kSuccess; +} + +/// Conv2d Dgrad dispatcher - dx = dgrad(dy, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +Status Conv2dDgrad( + conv::Conv2dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_w, + TensorRef tensor_dx_in, + TensorRef tensor_dx_out, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr) { + + // + // Blocking factors improve performance of reference implementation + // + + int const kThreadM = 2; // shape of a thread's tile in the GEMM M dimension + int const kThreadN = 4; // shape of a thread's tile in the GEMM N dimension + int const kCtaShapeM = 16; // shape of a threadblock in units of threads + int const kCtaShapeN = 8; // shape of a threadblock in units of threads + + int64_t nhw = int64_t(problem_size.N) * problem_size.H * problem_size.W; + int64_t blocks_m = (nhw + (kCtaShapeM * kThreadM) - 1) / (kCtaShapeM * kThreadM); + + dim3 block(kCtaShapeM, kCtaShapeN); + dim3 grid(uint32_t(blocks_m), (problem_size.C + (kCtaShapeN * kThreadN) - 1) / (kCtaShapeN * kThreadN)); + + kernel::Conv2dDgrad< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp, + kThreadM, + kThreadN, + kCtaShapeM, + kCtaShapeN + ><<< grid, block, 0, stream >>>( + problem_size, + tensor_dy, + tensor_w, + tensor_dx_in, + tensor_dx_out, + alpha, + beta + ); + + cudaError_t result = cudaPeekAtLastError(); + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + return Status::kSuccess; +} + +/// Conv3d Dgrad dispatcher - dx = dgrad(dy, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +Status Conv3dDgrad( + conv::Conv3dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_w, + TensorRef tensor_dx_in, + TensorRef tensor_dx_out, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr) { + + // + // Blocking factors improve performance of reference implementation + // + + int const kThreadM = 2; // shape of a thread's tile in the GEMM M dimension + int const kThreadN = 4; // shape of a thread's tile in the GEMM N dimension + int const kCtaShapeM = 16; // shape of a threadblock in units of threads + int const kCtaShapeN = 8; // shape of a threadblock in units of threads + + int64_t ndhw = int64_t(problem_size.N) * problem_size.D * problem_size.H * problem_size.W; + int64_t blocks_m = (ndhw + (kCtaShapeM * kThreadM) - 1) / (kCtaShapeM * kThreadM); + + dim3 block(kCtaShapeM, kCtaShapeN); + dim3 grid(uint32_t(blocks_m), (problem_size.C + (kCtaShapeN * kThreadN) - 1) / (kCtaShapeN * kThreadN)); + + kernel::Conv3dDgrad< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp, + kThreadM, + kThreadN, + kCtaShapeM, + kCtaShapeN + ><<< grid, block, 0, stream >>>( + problem_size, + tensor_dy, + tensor_w, + tensor_dx_in, + tensor_dx_out, + alpha, + beta + ); + + cudaError_t result = cudaPeekAtLastError(); + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + return Status::kSuccess; +} + +/// Conv2d Wgrad dispatcher - dw = wgrad(dy, x) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +Status Conv2dWgrad( + conv::Conv2dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_x, + TensorRef tensor_dw_in, + TensorRef tensor_dw_out, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr) { + + // + // Blocking factors improve performance of reference implementation + // + + int const kThreadM = 2; // shape of a thread's tile in the GEMM M dimension + int const kThreadN = 4; // shape of a thread's tile in the GEMM N dimension + int const kCtaShapeM = 8; // shape of a threadblock in units of threads + int const kCtaShapeN = 16; // shape of a threadblock in units of threads + + int64_t rsc = int64_t(problem_size.R) * problem_size.S * problem_size.C; + int64_t blocks_n = (rsc + (kCtaShapeN * kThreadN) - 1) / (kCtaShapeN * kThreadN); + + dim3 block(kCtaShapeM, kCtaShapeN); + dim3 grid((problem_size.K + (kCtaShapeM * kThreadM) - 1) / (kCtaShapeM * kThreadM), uint32_t(blocks_n)); + + kernel::Conv2dWgrad< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp, + kThreadM, + kThreadN, + kCtaShapeM, + kCtaShapeN + ><<< grid, block, 0, stream >>>( + problem_size, + tensor_dy, + tensor_x, + tensor_dw_in, + tensor_dw_out, + alpha, + beta + ); + + cudaError_t result = cudaPeekAtLastError(); + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + return Status::kSuccess; +} + +/// Conv3d Wgrad dispatcher - dw = wgrad(dy, x) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +Status Conv3dWgrad( + conv::Conv3dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_x, + TensorRef tensor_dw_in, + TensorRef tensor_dw_out, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr) { + + // + // Blocking factors improve performance of reference implementation + // + + int const kThreadM = 2; // shape of a thread's tile in the GEMM M dimension + int const kThreadN = 4; // shape of a thread's tile in the GEMM N dimension + int const kCtaShapeM = 8; // shape of a threadblock in units of threads + int const kCtaShapeN = 16; // shape of a threadblock in units of threads + + int64_t trsc = int64_t(problem_size.T) * problem_size.R * problem_size.S * problem_size.C; + int64_t blocks_n = (trsc + (kCtaShapeN * kThreadN) - 1) / (kCtaShapeN * kThreadN); + + dim3 block(kCtaShapeM, kCtaShapeN); + dim3 grid((problem_size.K + (kCtaShapeM * kThreadM) - 1) / (kCtaShapeM * kThreadM), uint32_t(blocks_n)); + + kernel::Conv3dWgrad< + ElementA, + LayoutA, + ElementB, + LayoutB, + ElementC, + LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, + InnerProductOp, + kThreadM, + kThreadN, + kCtaShapeM, + kCtaShapeN + ><<< grid, block, 0, stream >>>( + problem_size, + tensor_dy, + tensor_x, + tensor_dw_in, + tensor_dw_out, + alpha, + beta + ); + + cudaError_t result = cudaPeekAtLastError(); + if (result != cudaSuccess) { + return Status::kErrorInternal; + } + + return Status::kSuccess; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +/// Generic 2D convolution targeting Conv2dFprop, Conv2dDgrad, and Conv2dWgrad. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +Status Conv2d( + conv::Operator convolutional_operator, + conv::Conv2dProblemSize problem_size, + TensorRef tensor_A, + TensorRef tensor_B, + TensorRef tensor_C, + TensorRef tensor_D, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr) { + + switch (convolutional_operator) { + case conv::Operator::kFprop: + return Conv2dFprop< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, stream); + break; + + case conv::Operator::kDgrad: + return Conv2dDgrad< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, stream); + break; + + case conv::Operator::kWgrad: + return Conv2dWgrad< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, stream); + break; + + default: break; + } + + return Status::kErrorNotSupported; +} + +/// Generic 3D convolution targeting Conv3dFprop, Conv3dDgrad, and Conv3dWgrad. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +Status Conv3d( + conv::Operator convolutional_operator, + conv::Conv3dProblemSize problem_size, + TensorRef tensor_A, + TensorRef tensor_B, + TensorRef tensor_C, + TensorRef tensor_D, + ElementCompute alpha, + ElementCompute beta, + cudaStream_t stream = nullptr) { + + switch (convolutional_operator) { + case conv::Operator::kFprop: + return Conv3dFprop< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, stream); + + case conv::Operator::kDgrad: + return Conv3dDgrad< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, stream); + + case conv::Operator::kWgrad: + return Conv3dWgrad< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, stream); + + default: break; + } + + return Status::kErrorNotSupported; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace device +} // namespace reference +} // namespace cutlass + +//////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/tools/util/include/cutlass/util/reference/host/convolution.h b/tools/util/include/cutlass/util/reference/host/convolution.h new file mode 100644 index 000000000..48f5db81e --- /dev/null +++ b/tools/util/include/cutlass/util/reference/host/convolution.h @@ -0,0 +1,767 @@ +/*************************************************************************************************** + * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************************/ + +/*! \file + \brief Reference implementation for convolution in host-side code. +*/ + +#pragma once + +#include "cutlass/coord.h" +#include "cutlass/functional.h" +#include "cutlass/layout/tensor.h" +#include "cutlass/numeric_conversion.h" +#include "cutlass/numeric_types.h" +#include "cutlass/tensor_ref.h" +#include "cutlass/tensor_view.h" +#include "cutlass/conv/convolution.h" +#include "cutlass/conv/conv2d_problem_size.h" +#include "cutlass/conv/conv3d_problem_size.h" + +namespace cutlass { +namespace reference { +namespace host { + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// Forward propagation +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// y = conv2d(x, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +void Conv2dFprop( + conv::Conv2dProblemSize problem_size, + TensorRef tensor_x, + TensorRef tensor_w, + TensorRef tensor_y_in, + TensorRef tensor_y_out, + ElementCompute alpha, + ElementCompute beta) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + // Apply MMA and accumulate ElementAccumulator + for (int n = 0; n < problem_size.N; ++n) { + for (int p = 0; p < problem_size.P; ++p) { + for (int q = 0; q < problem_size.Q; ++q) { + for (int k = 0; k < problem_size.K; ++k) { + + ElementAccumulator acc = ElementAccumulator(); + + for (int r = 0; r < problem_size.R; ++r) { + for (int s = 0; s < problem_size.S; ++s) { + for (int c = 0; c < problem_size.C; ++c) { + + int filter_r = r; + int filter_s = s; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_r = problem_size.R - 1 - r; + filter_s = problem_size.S - 1 - s; + } + + int h = p * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h; + int w = q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w; + + if (h >= 0 && h < problem_size.H && w >= 0 && w < problem_size.W) { + + ElementA a = tensor_x.at({n, h, w, c}); + ElementB b = tensor_w.at({k, r, s, c}); + + acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc); + + } + } + } + } + + // Apply Epilogue, compute ElementCompute, convert and store ElementC + ElementC c_ref = ElementC(); + + if (beta != ElementCompute()) { + c_ref = tensor_y_in.at(cutlass::make_Coord(n, p, q, k)); + } + + tensor_y_out.at(cutlass::make_Coord(n, p, q, k)) = + convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref)); + } + } + } + } +} + +/// Depthwise-separable convolution +template , + typename InnerProductOp = multiply_add > +void Depsep_Fprop( + cutlass::TensorView tensor_A, + cutlass::TensorView tensor_B, + cutlass::TensorView tensor_C, + ElementCompute alpha, + ElementCompute beta, + cutlass::Tensor4DCoord padding, + cutlass::Coord<2> conv_stride, + cutlass::Coord<2> dilation, + cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + // Apply MMA and accumulate ElementAccumulator + for (int n = 0; n < tensor_C.extent().n(); ++n) { + for (int p = 0; p < tensor_C.extent().h(); ++p) { + for (int q = 0; q < tensor_C.extent().w(); ++q) { + for (int g = 0; g < tensor_C.extent().c(); ++g) { + ElementAccumulator acc = ElementAccumulator(); + for (int r = 0; r < tensor_B.extent().h(); ++r) { + for (int s = 0; s < tensor_B.extent().w(); ++s) { + if ((p * conv_stride[0] - padding[0] + r * dilation[0]) < tensor_A.extent().h() && + (p * conv_stride[0] - padding[0] + r * dilation[0]) >= 0 && + (q * conv_stride[1] - padding[2] + s * dilation[1]) < tensor_A.extent().w() && + (q * conv_stride[1] - padding[2] + s * dilation[1]) >= 0) { + ElementA a = tensor_A.at( + cutlass::make_Coord(n, + p * conv_stride[0] - padding[0] + r * dilation[0], + q * conv_stride[1] - padding[2] + s * dilation[1], + g)); + + ElementB b = (mode == cutlass::conv::Mode::kCrossCorrelation) + ? tensor_B.at(cutlass::make_Coord(g, r, s, 0)) + : tensor_B.at(cutlass::make_Coord( + g, tensor_B.extent().h() - r - 1, tensor_B.extent().w() - s - 1, 0)); + + acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc); + } + } + } + + // Apply Epilogue, compute ElementCompute, convert and store ElementC + ElementC c_ref = tensor_C.at(cutlass::make_Coord(n, p, q, g)); + tensor_C.at(cutlass::make_Coord(n, p, q, g)) = + convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref)); + } + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// Dgrad +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// dx = dgrad(dy, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +void Conv2dDgrad( + cutlass::conv::Conv2dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_w, + TensorRef tensor_dx_in, + TensorRef tensor_dx_out, + ElementCompute alpha, + ElementCompute beta) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + // Apply MMA and accumulate ElementAccumulator + for (int n = 0; n < problem_size.N; ++n) { + for (int h = 0; h < problem_size.H; ++h) { + for (int w = 0; w < problem_size.W; ++w) { + for (int c = 0; c < problem_size.C; ++c) { + + ElementAccumulator acc = ElementAccumulator(); + + for (int r = 0; r < problem_size.R; ++r) { + for (int s = 0; s < problem_size.S; ++s) { + for (int k = 0; k < problem_size.K; ++k) { + + int filter_r = r; + int filter_s = s; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_r = problem_size.R - 1 - r; + filter_s = problem_size.S - 1 - s; + } + + int p = h + problem_size.pad_h - filter_r * problem_size.dilation_h; + int q = w + problem_size.pad_w - filter_s * problem_size.dilation_w; + + if (p >= 0 && (p % problem_size.stride_h) == 0 && + q >= 0 && (q % problem_size.stride_w) == 0) { + + p = p / problem_size.stride_h; + q = q / problem_size.stride_w; + + if (p < problem_size.P && q < problem_size.Q) { + + ElementA a = tensor_dy.at(cutlass::make_Coord(n, p, q, k)); + ElementB b = tensor_w.at(cutlass::make_Coord(k, r, s, c)); + + acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc); + } + } + + } // for (K) + } // for (S) + } // for (R) + + // Apply Epilogue, compute ElementCompute, convert and store ElementC + ElementC c_ref = ElementC(); + + if (beta != ElementCompute()) { + c_ref = tensor_dx_in.at(cutlass::make_Coord(n, h, w, c)); + } + + tensor_dx_out.at(cutlass::make_Coord(n, h, w, c)) = + convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref)); + + } // for (C) + } // for (W) + } // for (H) + } // for (N) +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// Wgrad +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// dw = wgrad(dy, x) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +void Conv2dWgrad( + cutlass::conv::Conv2dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_x, + TensorRef tensor_dw_in, + TensorRef tensor_dw_out, + ElementCompute alpha, + ElementCompute beta) { + + InnerProductOp inner_product_op; + ConvertOp convert_op; + + // Apply MMA and accumulate ElementAccumulator + for (int k = 0; k < problem_size.K; ++k) { + for (int r = 0; r < problem_size.R; ++r) { + for (int s = 0; s < problem_size.S; ++s) { + for (int c = 0; c < problem_size.C; ++c) { + + ElementAccumulator acc = ElementAccumulator(); + + for (int n = 0; n < problem_size.N; ++n) { + for (int p = 0; p < problem_size.P; ++p) { + for (int q = 0; q < problem_size.Q; ++q) { + + cutlass::Tensor4DCoord b_coord; + + int filter_r = r; + int filter_s = s; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_r = problem_size.R - 1 - r; + filter_s = problem_size.S - 1 - s; + } + + b_coord = make_Coord( + n, + p * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h, + q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w, + c); + + if (b_coord.h() < problem_size.H && b_coord.h() >= 0 && + b_coord.w() < problem_size.W && b_coord.w() >= 0) { + + ElementAccumulator a = ElementAccumulator(tensor_dy.at(cutlass::make_Coord(n, p, q, k))); + ElementAccumulator b = ElementAccumulator(tensor_x.at(b_coord)); + acc = inner_product_op(a, b, acc); + } + } + } + } + + // Apply Epilogue, compute ElementCompute, convert and store ElementC + ElementC c_ref = ElementC(); + + if (beta != ElementCompute()) { + c_ref = tensor_dw_in.at(cutlass::make_Coord(k, r, s, c)); + } + + tensor_dw_out.at(cutlass::make_Coord(k, r, s, c)) = + convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref)); + + } // for (C) + } // for (S) + } // for (R) + } // for (K) +} + +/// Generic 2D convolution targeting Conv2dFprop, Conv2dDgrad, and Conv2dWgrad. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +void Conv2d( + conv::Operator convolutional_operator, + conv::Conv2dProblemSize problem_size, + TensorRef tensor_A, + TensorRef tensor_B, + TensorRef tensor_C, + TensorRef tensor_D, + ElementCompute alpha, + ElementCompute beta) { + + switch (convolutional_operator) { + case conv::Operator::kFprop: + Conv2dFprop< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta); + break; + + case conv::Operator::kDgrad: + Conv2dDgrad< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta); + break; + + case conv::Operator::kWgrad: + Conv2dWgrad< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta); + break; + + default: + break; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// 3D convolution +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// y = conv3d(x, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +void Conv3dFprop( + conv::Conv3dProblemSize problem_size, + TensorRef tensor_x, + TensorRef tensor_w, + TensorRef tensor_y_in, + TensorRef tensor_y_out, + ElementCompute alpha, + ElementCompute beta) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + // Apply MMA and accumulate ElementAccumulator + for (int n = 0; n < problem_size.N; ++n) { + for (int z = 0; z < problem_size.Z; ++z) { + for (int p = 0; p < problem_size.P; ++p) { + for (int q = 0; q < problem_size.Q; ++q) { + for (int k = 0; k < problem_size.K; ++k) { + + ElementAccumulator acc = ElementAccumulator(); + + for (int t = 0; t < problem_size.T; ++t) { + for (int r = 0; r < problem_size.R; ++r) { + for (int s = 0; s < problem_size.S; ++s) { + for (int c = 0; c < problem_size.C; ++c) { + + int filter_t = t; + int filter_r = r; + int filter_s = s; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_t = problem_size.T - 1 - t; + filter_r = problem_size.R - 1 - r; + filter_s = problem_size.S - 1 - s; + } + + int d = z * problem_size.stride_d - problem_size.pad_d + filter_t * problem_size.dilation_d; + int h = p * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h; + int w = q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w; + + if (d >= 0 && d < problem_size.D && + h >=0 && h < problem_size.H && + w >= 0 && w < problem_size.W) { + + ElementA a = tensor_x.at({n, d, h, w, c}); + ElementB b = tensor_w.at({k, t, r, s, c}); + + acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc); + } + } + } + } + } + + // Apply Epilogue, compute ElementCompute, convert and store ElementC + ElementC c_ref = ElementC(); + + if (beta != ElementCompute()) { + c_ref = tensor_y_in.at(cutlass::make_Coord(n, z, p, q, k)); + } + + tensor_y_out.at(cutlass::make_Coord(n, z, p, q, k)) = + convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref)); + } + } + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// Dgrad +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// dx = dgrad(dy, w) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +void Conv3dDgrad( + cutlass::conv::Conv3dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_w, + TensorRef tensor_dx_in, + TensorRef tensor_dx_out, + ElementCompute alpha, + ElementCompute beta) { + + ConvertOp convert_op; + InnerProductOp inner_product_op; + + // Apply MMA and accumulate ElementAccumulator + for (int n = 0; n < problem_size.N; ++n) { + for (int d = 0; d < problem_size.D; ++d) { + for (int h = 0; h < problem_size.H; ++h) { + for (int w = 0; w < problem_size.W; ++w) { + for (int c = 0; c < problem_size.C; ++c) { + + ElementAccumulator acc = ElementAccumulator(); + + for (int t = 0; t < problem_size.T; ++t) { + for (int r = 0; r < problem_size.R; ++r) { + for (int s = 0; s < problem_size.S; ++s) { + for (int k = 0; k < problem_size.K; ++k) { + + int filter_t = t; + int filter_r = r; + int filter_s = s; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_t = problem_size.T - 1 - t; + filter_r = problem_size.R - 1 - r; + filter_s = problem_size.S - 1 - s; + } + + int z = d + problem_size.pad_d - filter_t * problem_size.dilation_d; + int p = h + problem_size.pad_h - filter_r * problem_size.dilation_h; + int q = w + problem_size.pad_w - filter_s * problem_size.dilation_w; + + if (z >= 0 && (z % problem_size.stride_d) == 0 && + p >= 0 && (p % problem_size.stride_h) == 0 && + q >= 0 && (q % problem_size.stride_w) == 0) { + + z = z / problem_size.stride_d; + p = p / problem_size.stride_h; + q = q / problem_size.stride_w; + + if (z < problem_size.Z && p < problem_size.P && q < problem_size.Q) { + + ElementA a = tensor_dy.at(cutlass::make_Coord(n, z, p, q, k)); + ElementB b = tensor_w.at(cutlass::make_Coord(k, t, r, s, c)); + + acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc); + } + } + + } // for (K) + } // for (S) + } // for (R) + } // for (T) + + // Apply Epilogue, compute ElementCompute, convert and store ElementC + ElementC c_ref = ElementC(); + + if (beta != ElementCompute()) { + c_ref = tensor_dx_in.at(cutlass::make_Coord(n, d, h, w, c)); + } + + tensor_dx_out.at(cutlass::make_Coord(n, d, h, w, c)) = + convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref)); + + } // for (C) + } // for (W) + } // for (H) + } // for (D) + } // for (N) +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// Wgrad +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// dw = wgrad(dy, x) +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +void Conv3dWgrad( + cutlass::conv::Conv3dProblemSize problem_size, + TensorRef tensor_dy, + TensorRef tensor_x, + TensorRef tensor_dw_in, + TensorRef tensor_dw_out, + ElementCompute alpha, + ElementCompute beta) { + + InnerProductOp inner_product_op; + ConvertOp convert_op; + + // Apply MMA and accumulate ElementAccumulator + for (int k = 0; k < problem_size.K; ++k) { + for (int t = 0; t < problem_size.T; ++t) { + for (int r = 0; r < problem_size.R; ++r) { + for (int s = 0; s < problem_size.S; ++s) { + for (int c = 0; c < problem_size.C; ++c) { + + ElementAccumulator acc = ElementAccumulator(); + + for (int n = 0; n < problem_size.N; ++n) { + for (int z = 0; z < problem_size.Z; ++z) { + for (int p = 0; p < problem_size.P; ++p) { + for (int q = 0; q < problem_size.Q; ++q) { + + int filter_t = t; + int filter_r = r; + int filter_s = s; + + if (problem_size.mode == cutlass::conv::Mode::kConvolution) { + filter_t = problem_size.T - 1 - t; + filter_r = problem_size.R - 1 - r; + filter_s = problem_size.S - 1 - s; + } + + Tensor5DCoord b_coord = make_Coord( + n, + z * problem_size.stride_d - problem_size.pad_d + filter_t * problem_size.dilation_d, + p * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h, + q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w, + c); + + if (b_coord.d() < problem_size.D && b_coord.d() >= 0 && + b_coord.h() < problem_size.H && b_coord.h() >= 0 && + b_coord.w() < problem_size.W && b_coord.w() >= 0) { + + ElementAccumulator a = ElementAccumulator(tensor_dy.at(cutlass::make_Coord(n, z, p, q, k))); + ElementAccumulator b = ElementAccumulator(tensor_x.at(b_coord)); + + acc = inner_product_op(a, b, acc); + } + } + } + } + } + + // Apply Epilogue, compute ElementCompute, convert and store ElementC + ElementC c_ref = ElementC(); + + if (beta != ElementCompute()) { + c_ref = tensor_dw_in.at(cutlass::make_Coord(k, t, r, s, c)); + } + + tensor_dw_out.at(cutlass::make_Coord(k, t, r, s, c)) = + convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref)); + + } // for (C) + } // for (S) + } // for (R) + } // for (T) + } // for (K) +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Generic 3D convolution targeting Conv2dFprop, Conv2dDgrad, and Conv2dWgrad. +template < + typename ElementA, + typename LayoutA, + typename ElementB, + typename LayoutB, + typename ElementC, + typename LayoutC, + typename ElementCompute, + typename ElementAccumulator = ElementCompute, + typename ConvertOp = NumericConverter, + typename InnerProductOp = multiply_add +> +void Conv3d( + conv::Operator convolutional_operator, + conv::Conv3dProblemSize problem_size, + TensorRef tensor_A, + TensorRef tensor_B, + TensorRef tensor_C, + TensorRef tensor_D, + ElementCompute alpha, + ElementCompute beta) { + + switch (convolutional_operator) { + case conv::Operator::kFprop: + Conv3dFprop< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta); + break; + + case conv::Operator::kDgrad: + Conv3dDgrad< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta); + break; + + case conv::Operator::kWgrad: + Conv3dWgrad< + ElementA, LayoutA, + ElementB, LayoutB, + ElementC, LayoutC, + ElementCompute, + ElementAccumulator, + ConvertOp, InnerProductOp + >(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta); + break; + + default: + break; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace host +} // namespace reference +} // namespace cutlass + +///////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/tools/util/include/cutlass/util/reference/host/gemm.h b/tools/util/include/cutlass/util/reference/host/gemm.h index 98db6dcd9..6381aa306 100644 --- a/tools/util/include/cutlass/util/reference/host/gemm.h +++ b/tools/util/include/cutlass/util/reference/host/gemm.h @@ -249,6 +249,45 @@ struct Gemm +struct Gemm { + + void operator()(gemm::GemmCoord problem_size, ScalarType alpha, + TensorRef tensor_a, + TensorRef tensor_b, ScalarType beta, + TensorRef tensor_c, + ComputeType initial_accum = ComputeType(0)) { + static_assert( + LayoutA::kRank == 2 && LayoutB::kRank == 2 && LayoutC::kRank == 2, + "Tensors must be of rank 2"); + + compute_gemm>( + problem_size, alpha, tensor_a, tensor_b, beta, tensor_c, initial_accum); + } + + void operator()(gemm::GemmCoord problem_size, ScalarType alpha, + TensorRef tensor_a, + TensorRef tensor_b, ScalarType beta, + TensorRef tensor_c, + TensorRef tensor_d, + ComputeType initial_accum = ComputeType(0)) { + static_assert( + LayoutA::kRank == 2 && LayoutB::kRank == 2 && LayoutC::kRank == 2, + "Tensors must be of rank 2"); + + compute_gemm>( + problem_size, alpha, tensor_a, tensor_b, beta, tensor_c, tensor_d, initial_accum); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + /// Partial specialization for multiply-add-saturate template

    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 Z49Pg(W`Am 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�xvP$Z*FmDPfV+72voZX;fr`9Z@L)zh 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 literal 0 HcmV?d00001 diff --git a/media/images/tensor-op-permuted-smem-layout-TN-k1.png b/media/images/tensor-op-permuted-smem-layout-TN-k1.png new file mode 100644 index 0000000000000000000000000000000000000000..ea7d8b3be95b619b195858f6e5d5a24fed3301fd GIT binary patch literal 186274 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 XQ2m|$fcrfz^gGPn`RB5q0+Rj@3p}3H literal 0 HcmV?d00001 diff --git a/media/images/ldmatrix-tensorop-32x32x32.png b/media/images/ldmatrix-tensorop-32x32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..7acc9723f9585245f72702589dfdd1222f880375 GIT binary patch literal 1219789 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 z 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 @| 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�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