From e590290b917b84ba2c04c4a9320f8039afa5b454 Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Fri, 24 Jan 2025 05:57:26 +0000 Subject: [PATCH 01/91] moving all 01 introduction tutorials to inlined examples --- docs_input/notebooks/01_introduction.ipynb | 629 ++++++++++++------ .../exercises/example1_adv_slice_col.cu | 55 -- .../exercises/example1_adv_slice_row.cu | 55 -- .../exercises/example1_assignment1.cu | 127 ---- .../notebooks/exercises/example1_clone.cu | 56 -- .../notebooks/exercises/example1_init.cu | 54 -- .../notebooks/exercises/example1_permute.cu | 54 -- .../exercises/example1_simple_slice.cu | 55 -- 8 files changed, 418 insertions(+), 667 deletions(-) delete mode 100644 docs_input/notebooks/exercises/example1_adv_slice_col.cu delete mode 100644 docs_input/notebooks/exercises/example1_adv_slice_row.cu delete mode 100644 docs_input/notebooks/exercises/example1_assignment1.cu delete mode 100644 docs_input/notebooks/exercises/example1_clone.cu delete mode 100644 docs_input/notebooks/exercises/example1_init.cu delete mode 100644 docs_input/notebooks/exercises/example1_permute.cu delete mode 100644 docs_input/notebooks/exercises/example1_simple_slice.cu diff --git a/docs_input/notebooks/01_introduction.ipynb b/docs_input/notebooks/01_introduction.ipynb index 02a7708f0..a8e3ea92f 100644 --- a/docs_input/notebooks/01_introduction.ipynb +++ b/docs_input/notebooks/01_introduction.ipynb @@ -33,7 +33,7 @@ "metadata": {}, "source": [ "## Training Structure\n", - "This training contains a series of tutorials in increasing order of name that will guide you through basic and intermediate MatX features. Most tutorials will require you to open the source code, make a small change, and run it from the Jupyter notebook. As time permits, there is another notebook called `99_assignments.ipynb` that will give a series of problems to solve using MatX primitives. The assignments have verification code to make sure the answer is correct." + "This training contains a series of tutorials in increasing order of name that will guide you through basic and intermediate MatX features. Early tutorials are implemented using an in-line interpreter that allows you to run MatX code natively in the Jupyter cells. Later, more complex tutorials that are performance sensitive will require you to open source code in separate source files, and run it from the Jupyter notebook. As time permits, there is another notebook called `99_assignments.ipynb` that will give a series of problems to solve using MatX primitives. The assignments have verification code to make sure the answer is correct." ] }, { @@ -97,7 +97,9 @@ "source": [ "### 0. Library Import\n", "\n", - "During this tutorial, we will be writing our MatX code in a CUDA file (`.cu`), compiled via the CUDA Compiler, `nvcc`. If you're curious, the specific command line to build and execute code can be found [here](exercises/compile_and_run.sh).\n", + "During this tutorial, the includes and Jupyter intepreter will enable compilation, however in deployed code, MatX is most-often compiled via the CUDA Compiler, `nvcc`. If you're curious, example command line to build and execute code can be found [here](exercises/compile_and_run.sh).\n", + "\n", + "[comment]: <> (TYLER_TODO: We should elaborate)\n", "\n", "When using MatX, be sure to import the library via:\n", "\n", @@ -114,6 +116,48 @@ "Be aware that since MatX mimics a lot of functionality from the standard library, you may see common names from MatX in your current namespace. It's usually recommended to not import the entire `matx` namespace unless absolutely necessary." ] }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "//todo this should be moved to a hidden init block that runs automatically when the notebook starts\n", + "#pragma cling add_library_path(\"/usr/local/cuda/lib64\")\n", + "#pragma cling add_library_path(\"/opt/xeus/cling/lib\")\n", + "//#pragma cling add_library_path(\"/usr/Lib/gcc/x86_64-Linux-gnu/11/\")\n", + "#pragma cling add_library_path(\"/usr/lib/x86_64-linux-gnu/openblas64-openmp/\")\n", + "#pragma cling add_include_path(\"/usr/local/cuda/include\")\n", + "#pragma cling add_include_path(\"/usr/include/x86_64-linux-gnu/openblas64-openmp\")\n", + "#pragma cling add_include_path(\"/opt/xeus/cling/tools/Jupyter/kernel/MatX/include\")\n", + "#pragma cling add_include_path(\"/opt/xeus/cling/tools/Jupyter/kernel/MatX/build/_deps/cccl-src/libcudacxx/include\")\n", + "//#pragma cling load(\"libgomp\")\n", + "#pragma cling load(\"libopenblas64\")\n", + "#pragma cling load(\"libcuda\")\n", + "#pragma cling load(\"libcudart\")\n", + "#pragma cling load(\"libcurand\")\n", + "#pragma cling load(\"libcublas\")\n", + "#pragma cling load(\"libcublasLt\")\n", + "\n", + "#include \n", + "#include \n", + "\n", + "#define MATX_EN_OPENBLAS\n", + "#define MATX_EN_OPENBLAS_LAPACK\n", + "#define MATX_OPENBLAS_64BITINT\n", + "\n", + "#include \"matx.h\"" + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -121,11 +165,31 @@ "source": [ "### 1. Creation\n", "\n", - "First, we create a tensor object:\n", - "\n", - "```c++\n", - "auto t2 = make_tensor({5,4});\n", - "```\n", + "First, we create a tensor object:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "auto t2 = matx::make_tensor({5,4});" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "While you can create `tensor_t` objects directly, it us advised to used `make_tensor` instead. `tensor_t` has several template parameters that may change in the future, and using `make_tensor` avoids that ambiguity and always returns the correct tensor type. One exception to this is when a user wants to use `tensor_t` as a class member variable. In that case you need to use `tensor_t` directly, and in the constructor of your class use `make_tensor` with your `tensor_t` variable as the first argument. This will be demonstrated later.\n", "\n", @@ -145,25 +209,100 @@ "source": [ "### 2. Initialization \n", "\n", - "After allocating the tensor, we initialize the underlying data:\n", - "\n", - "```c++\n", - "t2.SetVals({ {1, 2, 3, 4},\n", - " {5, 6, 7, 8},\n", - " {9, 10, 11, 12},\n", - " {13, 14, 15, 16},\n", - " {17, 18, 19, 20}});\n", - "\n", + "After allocating the tensor, we initialize the underlying data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[5, 4], Strides:[4,1]\n", + "000000: 1 2 3 4 \n", + "000001: 5 6 7 8 \n", + "000002: 9 10 11 12 \n", + "000003: 13 14 15 16 \n", + "000004: 17 18 19 20 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x7f5e43dfec30\n" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t2.SetVals({ \n", + " {1, 2, 3, 4},\n", + " {5, 6, 7, 8},\n", + " {9, 10, 11, 12},\n", + " {13, 14, 15, 16},\n", + " {17, 18, 19, 20}\n", + " });\n", "\n", "t2.PrefetchDevice(0);\n", - "```\n", "\n", - "The tensor is initialized using a nested initializer list inside of the `SetVals` member function, specifying the values of the matrix. The initializer list is a single-nested list to match a 2D tensor shape, but this can be extended up to 4D tensors. `operator()` is also available to set and get individual values of a tensor as an alternative:\n", - "```c++\n", - " t2(0,0) = 1;\n", - " t2(0,1) = 2;\n", - " ...\n", - "```\n", + "matx::print(t2);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The tensor is initialized using a nested initializer list inside of the `SetVals` member function, specifying the values of the matrix. The initializer list is a single-nested list to match a 2D tensor shape, but this can be extended up to 4D tensors. `operator()` is also available to set and get individual values of a tensor as an alternative:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[5, 4], Strides:[4,1]\n", + "000000: 42 2 3 4 \n", + "000001: 5 6 7 8 \n", + "000002: 9 10 11 12 \n", + "000003: 13 14 117 16 \n", + "000004: 17 18 19 20 \n", + "My updates value for (3,2): 117\n" + ] + }, + { + "data": { + "text/plain": [ + "(std::basic_ostream >::__ostream_type &) @0x7f5eafc34540\n" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t2(0,0) = 42;\n", + "t2(3,2) = 117;\n", + "\n", + "matx::print(t2);\n", + "\n", + "std::cout << \"My updates value for (3,2): \" << t2(3,2) << std::endl;" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "**NOTE** The syntax above is executed on the host when written. This works for any type of memory accessible by the host, but will result in a segmentation fault if the tensor is backed by device memory.\n", "\n", @@ -177,32 +316,7 @@ "print(t2);\n", "``` \n", "\n", - "`print` is a utility function to print a tensor or operator's contents to stdout. Printing can be used with any type of operator, including ones that have no memory backing them (see upcoming generators section). If a tensor is being printed, the data backing it can reside either on the host or device, and MatX will move it before printing if needed. With no arguments `print` will print the entire contents of the tensor. However, the size of the printing can also be limited by passing a limit to each dimension. For example, `print(3,2)` would print the first 2 columns and 3 rows of the 2D tensor. The contents of the tensor printed should appear as an increasing sequence of numbers from the top to bottom rows.\n", - "\n", - "Open the file [exercises/example1_init.cu](exercises/example1_init.cu) and edit the contents where you see TODO markers." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example1_init" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:\n", - "```sh\n", - "000000: 1 2 3 4 \n", - "000001: 5 6 7 8 \n", - "000002: 9 10 11 12 \n", - "000003: 13 14 15 16 \n", - "000004: 17 18 19 20 \n", - "```" + "`print` is a utility function to print a tensor or operator's contents to stdout. Printing can be used with any type of operator, including ones that have no memory backing them (see upcoming generators section). If a tensor is being printed, the data backing it can reside either on the host or device, and MatX will move it before printing if needed. With no arguments `print` will print the entire contents of the tensor. However, the size of the printing can also be limited by passing a limit to each dimension. For example, `print(3,2)` would print the first 2 columns and 3 rows of the 2D tensor. The contents of the tensor printed should appear as an increasing sequence of numbers from the top to bottom rows." ] }, { @@ -211,40 +325,49 @@ "metadata": {}, "source": [ "### 3. Permute\n", - "The next section calls `permute` on the returned view:\n", - "\n", - "```c++\n", - "t2p = permute(t2, {1,0});\n", - "print(t2p);\n", - "```\n", - "\n", - "`permute` returns a view of the data with the dimensions swapped to match the order of the initializer list argument. In this case there are only two dimensions being permuted on a 2D tensor, so it's equivalent to a matrix transpose. However, `permute` can be used on higher-order tensors with the dimensions swapped in any particular order. Like printing, `permute` can work on any type of operator as input and not just tensors backed by memory. Observe the data and size of the tensor is now transposed when using this view:\n", - "\n", - "![Permuted/Transposed 2D Tensor](img/dli-transpose.png)\n", - "\n", - "Open the file [exercises/example1_permute.cu](exercises/example1_permute.cu) and edit the contents where you see TODO markers." + "The next section calls `permute` on the returned view:" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example1_permute" + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[4, 5], Strides:[1,4]\n", + "000000: 42 5 9 13 17 \n", + "000001: 2 6 10 14 18 \n", + "000002: 3 7 11 117 19 \n", + "000003: 4 8 12 16 20 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x7f5e43dfec30\n" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "auto t2p = permute(t2, {1,0});\n", + "print(t2p);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 1 5 9 13 17 \n", - "000001: 2 6 10 14 18 \n", - "000002: 3 7 11 15 19 \n", - "000003: 4 8 12 16 20 \n", - "```" + "`permute` returns a view of the data with the dimensions swapped to match the order of the initializer list argument. In this case there are only two dimensions being permuted on a 2D tensor, so it's equivalent to a matrix transpose. However, `permute` can be used on higher-order tensors with the dimensions swapped in any particular order. Like printing, `permute` can work on any type of operator as input and not just tensors backed by memory. Observe the data and size of the tensor is now transposed when using this view:\n", + "\n", + "![Permuted/Transposed 2D Tensor](img/dli-transpose.png)" ] }, { @@ -261,40 +384,47 @@ "metadata": {}, "source": [ "### 4. Slice\n", - "The next line takes a slice of the 2D tensor by selecting a subset of data in both dimensions:\n", - "\n", - "```c++\n", - "auto t2s = slice(t2, {1,1}, {3, 3});\n", - "```\n", - "\n", - "`t2s` is now a view of the same data, but starting at index 1 and ending at index 3 (exclusive) on both dimensions. This is equivalent to Python using `t2[1:3, 1:3]`. Since a new sliced view is returned, the new view will have dimensions `{2, 2}`.\n", - "\n", - "![2D Slice](img/dli-slice.png)\n", - "\n", - " Open the file [exercises/example1_simple_slice.cu](exercises/example1_simple_slice.cu) and edit the contents where you see TODO markers.\n", - "\n", - "\n", - "\n" + "The next line takes a slice of the 2D tensor by selecting a subset of data in both dimensions:\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example1_simple_slice" + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[2, 2], Strides:[4,1]\n", + "000000: 6 7 \n", + "000001: 10 11 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x7f5e43dfec30\n" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "auto t2s = matx::slice(t2, {1,1}, {3, 3});\n", + "\n", + "matx::print(t2s);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 6 7 \n", - "000001: 10 11 \n", - "```" + "`t2s` is now a view of the same data, but starting at index 1 and ending at index 3 (exclusive) on both dimensions. This is equivalent to Python using `t2[1:3, 1:3]`. Since a new sliced view is returned, the new view will have dimensions `{2, 2}`.\n", + "\n", + "![2D Slice](img/dli-slice.png)" ] }, { @@ -302,40 +432,50 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The next line shows a variant of `slice` that can reduce the dimension of an operator:\n", - "\n", - "```c++\n", - "auto t1 = slice<1>(t2, {0, 1}, {matxEnd, matxDropDim});\n", - "```\n", - "\n", - "Using this form of `slice` requires a template argument with the rank of the new slice. The second parameter to `slice` takes the starting index for each dimension, while the third takes the ending index. To include all values from the beginning on, a special sentinel of `matxEnd` can be used. Similarly, `matxDropDim` is used to indicate this dimension is the one being sliced (i.e. removed). In this case we are slicing the second column of the tensor and all rows, which produces a new 1D tensor containing only the second column of the original tensor. This is equivalent to `t2[:,1]` in Python. \n", - "\n", - "![Column Slice](img/dli-slice_col.png)\n", - "\n", - "Open the file [exercises/example1_adv_slice_col.cu](exercises/example1_adv_slice_col.cu) and edit the contents where you see TODO markers." + "The next line shows a variant of `slice` that can reduce the dimension of an operator:" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example1_adv_slice_col" + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_1_i32: Tensor{int32_t} Rank: 1, Sizes:[5], Strides:[4]\n", + "000000: 2 \n", + "000001: 6 \n", + "000002: 10 \n", + "000003: 14 \n", + "000004: 18 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x7f5e43dfec30\n" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "auto t1Col = matx::slice<1>(t2, {0, 1}, {matx::matxEnd, matx::matxDropDim});\n", + "\n", + "matx::print(t1Col);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 2 \n", - "000001: 6 \n", - "000002: 10 \n", - "000003: 14 \n", - "000004: 18 \n", - "```" + "Using this form of `slice` requires a template argument with the rank of the new slice. The second parameter to `slice` takes the starting index for each dimension, while the third takes the ending index. To include all values from the beginning on, a special sentinel of `matxEnd` can be used. Similarly, `matxDropDim` is used to indicate this dimension is the one being sliced (i.e. removed). In this case we are slicing the second column of the tensor and all rows, which produces a new 1D tensor containing only the second column of the original tensor. This is equivalent to `t2[:,1]` in Python. \n", + "\n", + "![Column Slice](img/dli-slice_col.png)" ] }, { @@ -343,37 +483,49 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Instead of slicing a single column, we can also slice a single row:\n", - "\n", - "```c++\n", - "auto t1 = slice<1>(t2, {1, 0}, {matxDropDim, matxEnd});\n", - "```\n", - "\n", - "![Row Slice](img/dli-slice_row.png)\n", - "\n", - "Open the file [exercises/example1_adv_slice_row.cu](exercises/example1_adv_slice_row.cu) and edit the contents where you see TODO markers.\n" + "Instead of slicing a single column, we can also slice a single row:\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example1_adv_slice_row" + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_1_i32: Tensor{int32_t} Rank: 1, Sizes:[4], Strides:[1]\n", + "000000: 5 \n", + "000001: 6 \n", + "000002: 7 \n", + "000003: 8 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x7f5e43dfec30\n" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "auto t1Row = matx::slice<1>(t2, {1, 0}, {matx::matxDropDim, matx::matxEnd});\n", + "\n", + "matx::print(t1Row);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 5 \n", - "000001: 6 \n", - "000002: 7 \n", - "000003: 8 \n", - "```" + "![Row Slice](img/dli-slice_row.png)\n", + "\n", + "\n" ] }, { @@ -385,93 +537,154 @@ "Note that since we reduced the dimension to a 1D tensor in both cases, printing a 1D tensor (vector) will appear the same in the direction the values are printed.\n", "\n", "### 5. Clone\n", - "The last line shows `clone`, which replicates a operator's dimensions into a higher-rank operator:\n", - "```c++\n", - "auto t2c = clone<2>(t1, {5, matxKeepDim});\n", - "```\n", - "\n", - "`clone` is used on a 1D tensor from the output of the previous example, and replicates the data of the `t1` vector into a 2D tensor with 5 rows where all rows match the data in `t1`. Cloning does not replicate the data in memory; instead, the same elements in `t1` are accessed repeatedly when different rows are accessed. This not only saves memory, but also benefits from the caches in the GPU by not hitting different addresses in memory for the same value. \n", - "\n", - "In this case `clone` was being used on a 1D view from a 2D tensor data set, but similar code works on taking any dimension tensor and increasing it to a higher dimension. The increase in dimensions is not restricted to one. For example, a scalar (0D tensor) can be cloned into a 4F tensor where a single value in memory would appear as a 4D tensor.\n", - "\n", - "![Permuted/Transposed 2D Tensor](img/dli-clone.png)\n", - "\n", - "Open the file [exercises/example1_clone.cu](exercises/example1_clone.cu) and edit the first TODO." + "The last line shows `clone`, which replicates a operator's dimensions into a higher-rank operator:" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example1_clone" + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[5, 4], Strides:[0,1]\n", + "000000: 5 6 7 8 \n", + "000001: 5 6 7 8 \n", + "000002: 5 6 7 8 \n", + "000003: 5 6 7 8 \n", + "000004: 5 6 7 8 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x7f5e43dfec30\n" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "auto t2c_rows = matx::clone<2>(t1Row, {5, matx::matxKeepDim});\n", + "\n", + "matx::print(t2c_rows);\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 1 2 3 4 \n", - "000001: 1 2 3 4 \n", - "000002: 1 2 3 4 \n", - "000003: 1 2 3 4 \n", - "000004: 1 2 3 4 \n", - "```" + "`clone` is used on a 1D tensor from the output of the previous example, and replicates the data of the `t1` vector into a 2D tensor with 5 rows where all rows match the data in `t1`. Cloning does not replicate the data in memory; instead, the same elements in `t1` are accessed repeatedly when different rows are accessed. This not only saves memory, but also benefits from the caches in the GPU by not hitting different addresses in memory for the same value. \n", + "\n", + "In this case `clone` was being used on a 1D view from a 2D tensor data set, but similar code works on taking any dimension tensor and increasing it to a higher dimension. The increase in dimensions is not restricted to one. For example, a scalar (0D tensor) can be cloned into a 4F tensor where a single value in memory would appear as a 4D tensor.\n", + "\n", + "![Permuted/Transposed 2D Tensor](img/dli-clone.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "By changing which dimension is cloned, we can also take the same 1D tensor across columns. Edit the last file and clones across columns instead, and print the output of the cloned view.\n", + "By changing which dimension is cloned, we can also take the same 1D tensor across columns.\n", "\n", "![Column Clone](img/dli-clone-col.png)" ] }, { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:\n", - "```sh\n", - "000000: 1 1 1 1 1 \n", - "000001: 2 2 2 2 2 \n", - "000002: 3 3 3 3 3 \n", - "000003: 4 4 4 4 4 \n", - "```" + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[4, 5], Strides:[1,0]\n", + "000000: 5 5 5 5 5 \n", + "000001: 6 6 6 6 6 \n", + "000002: 7 7 7 7 7 \n", + "000003: 8 8 8 8 8 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x7f5e43dfec30\n" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "auto t2c_columns = matx::clone<2>(t1Row, {matx::matxKeepDim, 5});\n", + "\n", + "matx::print(t2c_columns);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "As mentioned at the beginning, views do not modify the underlying data; they simply provide the metadata needed to access the elements. To show this, we will open the same [exercise](exercises/example1_clone.cu) again and modify the first value in the original 1D tensor to 10 and watch how multiple elements of the cloned view are modified." + "As mentioned at the beginning, views do not modify the underlying data; they simply provide the metadata needed to access the elements. To show this, we will modify t2(1,0), which corresponds to the first value of our 1D slice, watch how multiple elements of the cloned view are modified." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example1_clone" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:\n", - "```sh\n", - "000000: 10 2 3 4 \n", - "000001: 10 2 3 4 \n", - "000002: 10 2 3 4 \n", - "000003: 10 2 3 4 \n", - "000004: 10 2 3 4 \n", - "```" + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[5, 4], Strides:[4,1]\n", + "000000: 42 2 3 4 \n", + "000001: 10 6 7 8 \n", + "000002: 9 10 11 12 \n", + "000003: 13 14 117 16 \n", + "000004: 17 18 19 20 \n", + "tensor_1_i32: Tensor{int32_t} Rank: 1, Sizes:[4], Strides:[1]\n", + "000000: 10 \n", + "000001: 6 \n", + "000002: 7 \n", + "000003: 8 \n", + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[5, 4], Strides:[0,1]\n", + "000000: 10 6 7 8 \n", + "000001: 10 6 7 8 \n", + "000002: 10 6 7 8 \n", + "000003: 10 6 7 8 \n", + "000004: 10 6 7 8 \n", + "tensor_2_i32: Tensor{int32_t} Rank: 2, Sizes:[4, 5], Strides:[1,0]\n", + "000000: 10 10 10 10 10 \n", + "000001: 6 6 6 6 6 \n", + "000002: 7 7 7 7 7 \n", + "000003: 8 8 8 8 8 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x7f5e43dfec30\n" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t2(1,0) = 10;\n", + "matx::print(t2);\n", + "matx::print(t1Row);\n", + "matx::print(t2c_rows);\n", + "matx::print(t2c_columns);" ] }, { @@ -489,21 +702,15 @@ "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" }, "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" + "display_name": "C++17", + "language": "C++", + "name": "cling-cpp17" }, "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.5" + "codemirror_mode": "c++", + "file_extension": ".c++", + "mimetype": "text/x-c++src", + "name": "c++" } }, "nbformat": 4, diff --git a/docs_input/notebooks/exercises/example1_adv_slice_col.cu b/docs_input/notebooks/exercises/example1_adv_slice_col.cu deleted file mode 100644 index 082f8207e..000000000 --- a/docs_input/notebooks/exercises/example1_adv_slice_col.cu +++ /dev/null @@ -1,55 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto t2 = make_tensor({5, 4}); - - // Initialize the tensor linearly - t2.SetVals({{1, 2, 3, 4}, - {5, 6, 7, 8}, - {9, 10, 11, 12}, - {13, 14, 15, 16}, - {17, 18, 19, 20}}); - - // TODO: reduce tensor t2 to a 1D tensor by pulling the second column and all - // rows - auto t1 = ...; - - print(t1); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example1_adv_slice_row.cu b/docs_input/notebooks/exercises/example1_adv_slice_row.cu deleted file mode 100644 index a99e2540d..000000000 --- a/docs_input/notebooks/exercises/example1_adv_slice_row.cu +++ /dev/null @@ -1,55 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto t2 = make_tensor({5, 4}); - - // Initialize the tensor linearly - t2.SetVals({{1, 2, 3, 4}, - {5, 6, 7, 8}, - {9, 10, 11, 12}, - {13, 14, 15, 16}, - {17, 18, 19, 20}}); - - // TODO: reduce tensor t2 to a 1D tensor by pulling all columns and the - // second row - auto t1 = ...; - - print(t1); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example1_assignment1.cu b/docs_input/notebooks/exercises/example1_assignment1.cu deleted file mode 100644 index 14d923a20..000000000 --- a/docs_input/notebooks/exercises/example1_assignment1.cu +++ /dev/null @@ -1,127 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -/** - * MatX training assignment 1. This training goes through basic tensor - * operations that were learned in the 01_introduction notebook. Uncomment each - * verification block as you go to ensure your solutions are correct. - */ - -int main() { - - /**************************************************************************************************** - * Create a rank-2 tensor data object of ints with 5 rows and 4 columns called - *"t2" - *https://devtech-compute.gitlab-master-pages.nvidia.com/matx/quickstart.html#tensor-views - ****************************************************************************************************/ - - /*** End editing ***/ - - /**************************************************************************************************** - * Initialize the t2 view to a 4x5 matrix of increasing values starting at 1 - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/quickstart.html#tensor-views - ****************************************************************************************************/ - // t2 = ; - /*** End editing ***/ - - /**************************************************************************************************** - * Get a slice of the second and third rows with all columns - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/quickstart.html#slicing-and-dicing - *****************************************************************************************************/ - auto t2s = t2; - /*** End editing ***/ - - // Verify slice is correct - // for (int row = 1; row <= 2; row++) { - // for (int col = 0; col < t2.Size(1); col++) { - // if (t2(row, col) != t2s(row - 1, col)) { - // printf("Mismatch in sliced view! actual = %d, expected = %d\n", - // t2s(row - 1, col), t2(row, col)); exit(-1); - // } - // } - // } - - // print(t2s); - // printf("Slice verification passed!\n"); - - /**************************************************************************************************** - * Take the slice and clone it into a 3D tensor with new outer dimensions as - *follows: First dim: keep existing row dimension from t2s Second dim: 2 Third - *dim: keep existing col dimension from t2s - https://devtech-compute.gitlab-master-pages.nvidia.com/matx/quickstart.html#increasing-dimensionality - *****************************************************************************************************/ - auto t3c = t2s; - /*** End editing ***/ - - // Verify clone - // for (int first = 0; first < t3c.Size(0); first++) { - // for (int sec = 0; sec < t3c.Size(1); sec++) { - // for (int third = 0; third < t3c.Size(2); third++) { - // if (t3c(first, sec, third) != t2s(first, third)) { - // printf("Mismatch in cloned view! actual = %d, expected = %d\n", - // t3c(first, sec, third), t2s(first, third)); exit(-1); - // } - // } - // } - // } - - // print(t3c); - // printf("Clone verification passed!\n"); - - /**************************************************************************************************** - * Permute the two outer dimensions of the cloned tensor - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/quickstart.html#permuting - *****************************************************************************************************/ - auto t3p = t3c; - /*** End editing ***/ - - // Verify clone - // for (int first = 0; first < t3p.Size(0); first++) { - // for (int sec = 0; sec < t3p.Size(1); sec++) { - // for (int third = 0; third < t3p.Size(2); third++) { - // if (t3c(first, sec, third) != t2s(first, third)) { - // printf("Mismatch in permuted view! actual = %d, expected = %d\n", - // t3c(first, sec, third), t2s(sec, third)); exit(-1); - // } - // } - // } - // } - - // print(t3p); - // printf("Permute verification passed!\n"); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example1_clone.cu b/docs_input/notebooks/exercises/example1_clone.cu deleted file mode 100644 index 99d7cc059..000000000 --- a/docs_input/notebooks/exercises/example1_clone.cu +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto t1 = make_tensor({4}); - - // Initialize the tensor linearly - t1.SetVals({1, 2, 3, 4}); - - // TODO: Clone tensor t1 into a 2D tensor by making a new outer dimension 5. - auto t2c = ...; - - print(t2c); - - // TODO: After compiling and running the code above, modify the first element - // in t1 to be 10 on the next line. Uncomment the print line as well. t1(0) = - // ... - - // print(t2c); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example1_init.cu b/docs_input/notebooks/exercises/example1_init.cu deleted file mode 100644 index 150bdda92..000000000 --- a/docs_input/notebooks/exercises/example1_init.cu +++ /dev/null @@ -1,54 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - // TODO: Create a 2D tensor of ints called t2data with dimensions 5, 4, and - // a view of that data using the default view. - - auto t2 = ; - - // Initialize the tensor linearly - t2.SetVals({ {1, 2, 3, 4}, - {5, 6, 7, 8}, - {9, 10, 11, 12}, - {13, 14, 15, 16}, - {17, 18, 19, 20}}); - - print(t2); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example1_permute.cu b/docs_input/notebooks/exercises/example1_permute.cu deleted file mode 100644 index 00b7fb9a7..000000000 --- a/docs_input/notebooks/exercises/example1_permute.cu +++ /dev/null @@ -1,54 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto t2 = make_tensor({5, 4}); - - // Initialize the tensor linearly - t2.SetVals({{1, 2, 3, 4}, - {5, 6, 7, 8}, - {9, 10, 11, 12}, - {13, 14, 15, 16}, - {17, 18, 19, 20}}); - - // TODO: Permute the view t2 such that the two dimensions are swapped - auto t2p = ...; - - print(t2p); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example1_simple_slice.cu b/docs_input/notebooks/exercises/example1_simple_slice.cu deleted file mode 100644 index 8c8dce351..000000000 --- a/docs_input/notebooks/exercises/example1_simple_slice.cu +++ /dev/null @@ -1,55 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto t2 = make_tensor({5, 4}); - - // Initialize the tensor linearly - t2.SetVals({{1, 2, 3, 4}, - {5, 6, 7, 8}, - {9, 10, 11, 12}, - {13, 14, 15, 16}, - {17, 18, 19, 20}}); - - // TODO: Create a slide of the view t2 starting at the second element and - // ending at the third element (inclusive) in both dimensions - auto t2s = ...; - - print(t2s); - - return 0; -} From f7b6717c9a728cf37c371e79b48d80090baae211 Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Fri, 24 Jan 2025 06:59:06 +0000 Subject: [PATCH 02/91] move notebook 2 to cell execution. run is currently broken --- docs_input/notebooks/02_operators.ipynb | 772 +++++++++++------- .../exercises/example2_assignment1.cu | 158 ---- .../exercises/example2_conditional.cu | 51 -- .../notebooks/exercises/example2_eye.cu | 45 - .../notebooks/exercises/example2_hamming.cu | 47 -- .../notebooks/exercises/example2_init.cu | 53 -- .../exercises/example2_mixed_rank.cu | 55 -- .../exercises/example2_multiple_ops.cu | 54 -- .../notebooks/exercises/example2_rand.cu | 47 -- .../notebooks/exercises/example2_scalar.cu | 56 -- .../exercises/example2_tensor_add.cu | 57 -- .../exercises/example2_tensor_div.cu | 45 - .../notebooks/exercises/example2_viz.cu | 47 -- 13 files changed, 456 insertions(+), 1031 deletions(-) delete mode 100644 docs_input/notebooks/exercises/example2_assignment1.cu delete mode 100644 docs_input/notebooks/exercises/example2_conditional.cu delete mode 100644 docs_input/notebooks/exercises/example2_eye.cu delete mode 100644 docs_input/notebooks/exercises/example2_hamming.cu delete mode 100644 docs_input/notebooks/exercises/example2_init.cu delete mode 100644 docs_input/notebooks/exercises/example2_mixed_rank.cu delete mode 100644 docs_input/notebooks/exercises/example2_multiple_ops.cu delete mode 100644 docs_input/notebooks/exercises/example2_rand.cu delete mode 100644 docs_input/notebooks/exercises/example2_scalar.cu delete mode 100644 docs_input/notebooks/exercises/example2_tensor_add.cu delete mode 100644 docs_input/notebooks/exercises/example2_tensor_div.cu delete mode 100644 docs_input/notebooks/exercises/example2_viz.cu diff --git a/docs_input/notebooks/02_operators.ipynb b/docs_input/notebooks/02_operators.ipynb index 1c085dfd4..222a782e7 100644 --- a/docs_input/notebooks/02_operators.ipynb +++ b/docs_input/notebooks/02_operators.ipynb @@ -35,56 +35,125 @@ "The last topic in this exercise will cover MatX generators. MatX generators are an operator that can dynamically generate data from a formula without storing the interim values. For example, the values an identity matrix or a Hamming window can both be generated on-the-fly only by knowing the index of the value. Generators typically only take a Shape as input since their output is generated without input data." ] }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "//todo this should be moved to a hidden init block that runs automatically when the notebook starts\n", + "#pragma cling add_library_path(\"/usr/local/cuda/lib64\")\n", + "#pragma cling add_library_path(\"/opt/xeus/cling/lib\")\n", + "//#pragma cling add_library_path(\"/usr/Lib/gcc/x86_64-Linux-gnu/11/\")\n", + "#pragma cling add_library_path(\"/usr/lib/x86_64-linux-gnu/openblas64-openmp/\")\n", + "#pragma cling add_include_path(\"/usr/local/cuda/include\")\n", + "#pragma cling add_include_path(\"/usr/include/x86_64-linux-gnu/openblas64-openmp\")\n", + "#pragma cling add_include_path(\"/opt/xeus/cling/tools/Jupyter/kernel/MatX/include\")\n", + "#pragma cling add_include_path(\"/opt/xeus/cling/tools/Jupyter/kernel/MatX/build/_deps/cccl-src/libcudacxx/include\")\n", + "//#pragma cling load(\"libgomp\")\n", + "#pragma cling load(\"libopenblas64\")\n", + "#pragma cling load(\"libcuda\")\n", + "#pragma cling load(\"libcudart\")\n", + "#pragma cling load(\"libcurand\")\n", + "#pragma cling load(\"libcublas\")\n", + "#pragma cling load(\"libcublasLt\")\n", + "\n", + "#include \n", + "#include \n", + "\n", + "#define MATX_EN_OPENBLAS\n", + "#define MATX_EN_OPENBLAS_LAPACK\n", + "#define MATX_OPENBLAS_64BITINT\n", + "\n", + "#include \"matx.h\"" + ] + }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Initialization\n", - "As in the previous example, we need to declare tensors and initialize the data:\n", - "\n", - "```c++\n", - " auto A = make_tensor({2, 3});\n", - " auto B = make_tensor({2, 3});\n", - " auto C = make_tensor({2, 3});\n", - " auto V = make_tensor({3});\n", - "``` \n", - "\n", - "We create a single tensor Shape type that's used in multiple tensor types so that we don't have to repeat the size. After this code is executed, four data objects are created, and managed memory is allocated to account for the shape and type of each tensor. Next, the input tensor Views (`A` and `V`) are initiailized with an increasing data pattern:\n", - "\n", - "```c++\n", - " A.SetVals({ {1, 2, 3},\n", - " {4, 5, 6}});\n", - " \n", - " V.SetVals({7, 8, 9});\n", - "``` \n", - "\n", - "Open the file [exercises/example2_init.cu](exercises/example2_init.cu) and edit the contents where you see TODO markers." + "As in the previous example, we need to declare tensors and initialize the data:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "!./exercises/compile_and_run.sh example2_init" + "auto A = matx::make_tensor({2, 3});\n", + "auto B = matx::make_tensor({2, 3});\n", + "auto C = matx::make_tensor({2, 3});\n", + "auto V = matx::make_tensor({3});\n", + "auto E = matx::make_tensor({8,8});\n", + "auto H = matx::make_tensor({10});" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 1.0000 2.0000 3.0000 \n", - "000001: 4.0000 5.0000 6.0000 \n", + "After this code is executed, four data objects are created, and managed memory is allocated to account for the shape and type of each tensor. Next, the input tensor Views (`A` and `V`) are initiailized with an increasing data pattern:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[2, 3], Strides:[3,1]\n", + "000000: 1.0000e+00 2.0000e+00 3.0000e+00 \n", + "000001: 4.0000e+00 5.0000e+00 6.0000e+00 \n", + "tensor_1_f32: Tensor{float} Rank: 1, Sizes:[3], Strides:[1]\n", + "000000: 7.0000e+00 \n", + "000001: 8.0000e+00 \n", + "000002: 9.0000e+00 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A.SetVals({ {1, 2, 3},\n", + " {4, 5, 6}\n", + " });\n", + " \n", + "V.SetVals({7, 8, 9});\n", "\n", - "000000: 7.0000 \n", - "000001: 8.0000 \n", - "000002: 9.0000 \n", - "```" + "matx::print(A);\n", + "matx::print(V);" ] }, { @@ -93,39 +162,50 @@ "metadata": {}, "source": [ "## Element-wise Scalar Addition\n", - "For the first operator example, we add a scalar onto a tensor and assign it to another tensor. This can be thought of as tensor addition with the second tensor equal to a tensor of equal size with all ones. To make the separation of operators from executors explicit, we first create the operator `op` by using MatX's lazy assignment operator `=`. The statement on the right hand side can be read as \"Add the number 5 to operator A, and assign the result to tensor B\". Instantiating variable `op` generates a CUDA kernel that can then be executed with the `run()` method:\n", - "\n", - "```c++\n", - "auto op = (B = A + 5);\n", - "op.run();\n", - "```\n", - "The `run()` function takes an optional CUDA stream to launch the work in. Since no argument was specified here, the default stream is used.\n", - "\n", - "Open the file [exercises/example2_scalar.cu](exercises/example2_scalar.cu) and edit the contents where you see TODO markers." + "For the first operator example, we add a scalar onto a tensor and assign it to another tensor. This can be thought of as tensor addition with the second tensor equal to a tensor of equal size with all ones. To make the separation of operators from executors explicit, we first create the operator `op` by using MatX's lazy assignment operator `=`. The statement on the right hand side can be read as \"Add the number 5 to operator A, and assign the result to tensor B\". Instantiating variable `op` generates a CUDA kernel that can then be executed with the `run()` method:\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[2, 3], Strides:[3,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "Operator{float} Rank: 2, Sizes:[2, 3]\n", + "000000: 6.0000e+00 7.0000e+00 8.0000e+00 \n", + "000001: 9.0000e+00 1.0000e+01 1.1000e+01 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "!./exercises/compile_and_run.sh example2_scalar" + "auto op = (B = A + 5);\n", + "op.run();\n", + "matx::print(B);\n", + "\n", + "matx::print((B = A + 5)); ///\\todo remove after run is fixed" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 1.0000 2.0000 3.0000 \n", - "000001: 4.0000 5.0000 6.0000 \n", - "\n", - "000000: 2.0000 3.0000 4.0000 \n", - "000001: 5.0000 6.0000 7.0000 \n", - "```" + "The `run()` function takes an optional executor to determine what accelerator is used to perform the operation. When no argument is specified, the default executor is the CUDA default stream." ] }, { @@ -134,46 +214,49 @@ "metadata": {}, "source": [ "## Element-wise Tensor Addition\n", - "The next section adds two tensors together element-wise. Just like with a scalar, the `+` operator works on two tensors. Instead of creating a separate operator variable, this example shows how to create and execute an operator in a single line:\n", - "\n", - "```c++\n", - "A.SetVals({ {1, 2, 3},\n", - " {4, 5, 6}});\n", - "\n", - "B.SetVals({ {7, 8, 9},\n", - " {10, 11, 12}});\n", - "\n", - "(C = A + B).run();\n", - "```\n", - "\n", - "Open the file [exercises/example2_tensor_add.cu](exercises/example2_tensor_add.cu) and edit the contents where you see TODO markers." + "The next section adds two tensors together element-wise. Just like with a scalar, the `+` operator works on two tensors. Instead of creating a separate operator variable, this example shows how to create and execute an operator in a single line:\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example2_tensor_add" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[2, 3], Strides:[3,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "Operator{float} Rank: 2, Sizes:[2, 3]\n", + "000000: 8.0000e+00 1.0000e+01 1.2000e+01 \n", + "000001: 1.4000e+01 1.6000e+01 1.8000e+01 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "Expected output:\n", - "```sh\n", - "000000: 1.0000 2.0000 3.0000 \n", - "000001: 4.0000 5.0000 6.0000 \n", + "A.SetVals({ {1, 2, 3},\n", + " {4, 5, 6}});\n", + "\n", + "B.SetVals({ {7, 8, 9},\n", + " {10, 11, 12}});\n", + "\n", + "(C = A + B).run();\n", "\n", - "000000: 7.0000 8.0000 9.0000 \n", - "000001: 10.0000 11.0000 12.0000 \n", + "matx::print(C);\n", "\n", - "000000: 8.0000 10.0000 12.0000 \n", - "000001: 14.0000 16.0000 18.0000 \n", - "```" + "matx::print(C = A + B); ///\\todo remove after run is fixed" ] }, { @@ -182,39 +265,53 @@ "metadata": {}, "source": [ "## Element-wise Tensor Division\n", - "The division operator `/` can also be used on two tensors. In this example we reuse the `C` tensor from the last example and divide each element by 2:\n", - "\n", - "```c++\n", - " C.SetVals({ {7, 8, 9},\n", - " {10, 11, 12}});\n", - "\n", - " (C = C / 2).run(); \n", - "```\n", - "\n", - "With division, the usual C semantics apply - if the tensor type is an integral type, the results are rounded down. If the type is floating point, floating point division is performed. In this case we are using `float` types, so floating point division will occur.\n", - "\n", - "Open the file [exercises/example2_tensor_div.cu](exercises/example2_tensor_div.cu) and edit the contents where you see TODO markers." + "The division operator `/` can also be used on two tensors, or any scalar type that is compatible with the tensor's data. In this example we reuse the `C` tensor from the last example and divide each element by 2:\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example2_tensor_div" + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[2, 3], Strides:[3,1]\n", + "000000: 7.0000e+00 8.0000e+00 9.0000e+00 \n", + "000001: 1.0000e+01 1.1000e+01 1.2000e+01 \n", + "Operator{float} Rank: 2, Sizes:[2, 3]\n", + "000000: 3.5000e+00 4.0000e+00 4.5000e+00 \n", + "000001: 5.0000e+00 5.5000e+00 6.0000e+00 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "C.SetVals({ {7, 8, 9},\n", + " {10, 11, 12}});\n", + "\n", + "(C = C / 2).run(); \n", + "\n", + "matx::print(C);\n", + "\n", + "matx::print(C = C / 2); ///\\todo remove after run is fixed" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 3.5000 4.0000 4.5000 \n", - "000001: 5.0000 5.5000 6.0000 \n", - "```" + "With division, the usual C semantics apply - if the tensor type is an integral type, the results are rounded down. If the type is floating point, floating point division is performed. In this case we are using `float` types, so floating point division will occur." ] }, { @@ -223,95 +320,57 @@ "metadata": {}, "source": [ "## Broadcasted Tensor Addition\n", - "Binary operators can be used on tensors of different ranks. In this section, we add a 1D tensor `M` onto a 2D tensor `C`. Unlike previous examples, the result is stored in the same tensor `C`, which is safe since the operation is element-wise and each thread runs independent of others. When operating on tensors of different ranks, the outer dimensions of both tensors must match. The tensor with the lower rank will be broadcasted on the higher dimensions when the operation is executing.\n", - "\n", - "```c++\n", - " A.SetVals({ {1, 2, 3},\n", - " {4, 5, 6}});\n", - " \n", - " V.SetVals({7, 8, 9});\n", - "\n", - " (C = C + M).run();\n", - "```\n", - "\n", - "The result of the operation will be `M` repeatedly added to all rows of `C`.\n", - "\n", - "Open the file [exercises/example2_mixed_rank.cu](exercises/example2_mixed_rank.cu) and edit the contents where you see TODO markers." + "Binary operators can be used on tensors of different ranks. In this section, we add a 1D tensor `V` onto a 2D tensor `C`. Unlike previous examples, the result is stored in the same tensor `C`, which is safe since the operation is element-wise and each thread runs independent of others. When operating on tensors of different ranks, the outer dimensions of both tensors must match. The tensor with the lower rank will be broadcasted on the higher dimensions when the operation is executing." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example2_mixed_rank" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", + "execution_count": 7, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[2, 3], Strides:[3,1]\n", + "000000: 1.0000e+00 2.0000e+00 3.0000e+00 \n", + "000001: 4.0000e+00 5.0000e+00 6.0000e+00 \n", + "Operator{float} Rank: 2, Sizes:[2, 3]\n", + "000000: 8.0000e+00 1.0000e+01 1.2000e+01 \n", + "000001: 1.1000e+01 1.3000e+01 1.5000e+01 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "Expected output:\n", - "```sh\n", - "000000: 8.0000 10.0000 12.0000 \n", - "000001: 11.0000 13.0000 15.0000 \n", - "```" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Multiple Operators\n", - "Multiple operators can be combined in a single expression. The syntax is similar to using a high-level language like MATLAB where the order of operations is followed, and the final result is stored into the tensor on the left hand side of the lazy assignment operator `=`. Unlike most C++ libraries that use operator overloading for runtime expression parsing, MatX uses templates to parse the entire expression at compile-time. This removes all unnecessary interim loads and stores that would normally occur with the runtime approach. In this example, we combined 4 operators (three `+` and one `/`) in a single expression:\n", "\n", - "```c++\n", - " A.SetVals({ {1, 2, 3},\n", - " {4, 5, 6}});\n", - " \n", - " V.SetVals({7, 8, 9});\n", + "C.SetVals({ {1, 2, 3},\n", + " {4, 5, 6}});\n", "\n", - " (C = (A + A + 1) / 2 + V).run();\n", - "```\n", + "V.SetVals({7, 8, 9});\n", "\n", - "Open the file [exercises/example2_multiple_ops.cu](exercises/example2_multiple_ops.cu) and edit the contents where you see TODO markers." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example2_multiple_ops" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:\n", - "```sh\n", - "000000: 8.5000 10.5000 12.5000 \n", - "000001: 11.5000 13.5000 15.5000\n", - "```" + "(C = C + V).run();\n", + "\n", + "matx::print(C);\n", + "\n", + "matx::print(C = C + V); ///\\todo remove after run is fixed" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "## Conditionals\n", - "Conditional statements operators are also available to take an action based on the value of an operator or tensor view. These actions can be anything from changing the computation to choosing where to store the data. In this example, we set the output of A based on whether the value in C is greater than 3. Note that `IFELSE` is an operator, and has the same `run()` method to execute the work as a standard expression.\n", "\n", - "```c++\n", - " IFELSE(C > 3, A = 1, A = 0).run();\n", - "```" + "The result of the operation will be `V` repeatedly added to all rows of `C`." ] }, { @@ -319,16 +378,49 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Open the file [exercises/example2_conditional.cu](exercises/example2_conditional.cu) and edit the contents where you see TODO markers." + "## Multiple Operators\n", + "Multiple operators can be combined in a single expression. The syntax is similar to using a high-level language like MATLAB where the order of operations is followed, and the final result is stored into the tensor on the left hand side of the lazy assignment operator `=`. Unlike most C++ libraries that use operator overloading for runtime expression parsing, MatX uses templates to parse the entire expression at compile-time. This removes all unnecessary interim loads and stores that would normally occur with the runtime approach. In this example, we combined 4 operators (three `+` and one `/`) in a single expression:" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[2, 3], Strides:[3,1]\n", + "000000: 8.0000e+00 1.0000e+01 1.2000e+01 \n", + "000001: 1.1000e+01 1.3000e+01 1.5000e+01 \n", + "Operator{float} Rank: 2, Sizes:[2, 3]\n", + "000000: 8.5000e+00 1.0500e+01 1.2500e+01 \n", + "000001: 1.1500e+01 1.3500e+01 1.5500e+01 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "!./exercises/compile_and_run.sh example2_conditional" + "A.SetVals({ {1, 2, 3},\n", + " {4, 5, 6}});\n", + "\n", + "V.SetVals({7, 8, 9});\n", + "\n", + "(C = (A + A + 1) / 2 + V).run();\n", + "\n", + "matx::print(C);\n", + "\n", + "matx::print((C = (A + A + 1) / 2 + V)); ///\\todo remove after run is fixed" ] }, { @@ -336,58 +428,54 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 0 0 0\n", - "000001: 1 1 1\n", - "```" + "## Conditionals\n", + "Conditional statements operators are also available to take an action based on the value of an operator or tensor view. These actions can be anything from changing the computation to choosing where to store the data. In this example, we set the output of A based on whether the value in C is greater than 3. Note that `IFELSE` is an operator, and has the same `run()` method to execute the work as a standard expression.\n" ] }, { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[2, 3], Strides:[3,1]\n", + "000000: 1.0000e+00 2.0000e+00 3.0000e+00 \n", + "000001: 4.0000e+00 5.0000e+00 6.0000e+00 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "### Random Operator\n", - "The ``random`` operator provides a way to generate random numbers using various distrubtions. Random values can be useful for many applications, including generating noise in signal processing or initializing data for testing. In this example we take an existing tensor view (`A`) and populate it with random values from a normal distribution. Before setting the random values, we set all elements of `A` to zero to show the values change after randomizing.\n", + "A.SetVals({ {1, 2, 3},\n", + " {4, 5, 6}});\n", "\n", - "```c++\n", - "(A = 0).run()\n", - "(A = random({4, 4}, NORMAL)).run();\n", - "```\n", + "C.SetVals({ {1, 2, 3},\n", + " {4, 5, 6}});\n", "\n", - "Open the file [exercises/example2_rand.cu](exercises/example2_rand.cu) and edit the contents where you see TODO markers." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example2_rand" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:\n", - "```sh\n", - "000000: -0.9247 -0.4253 -2.6438 0.1452\n", - "000001: -0.1209 -0.5797 -0.6229 -0.3284\n", - "000002: -1.0745 -0.3631 -1.6711 2.2655\n", - "000003: 0.3117 -0.1842 1.2866 1.1820\n", - "```" + "matx::IFELSE(C > 3, A = 1, A = 0).run();\n", + "matx::print(A);\n", + "\n", + "\n", + "///\\todo currently broken, doesn't work with print for some reason" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "In this example we store the current random values from `randTensor` into `A`. Instead of storing the random values in `A`, `randTensor` can be used directly in operator equations, and each time it's used a different set of random values is generated." + "\n" ] }, { @@ -395,23 +483,47 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Generators\n", - "Next, we introduce the concept of a generator by creating the identity matrix, scaling the values by `5`, and storing it in a tensor. MatX contains an `eye` operator for generating an identity matrix. Each time an element in the generator is accessed, `eye` simply returns a `1` for values in the diagonal, and `0` otherwise. Said differently, if the index for each rank is equal, the value is set to `1`. Since the goal is to have a diagonal matrix of fives, we multiply the generator by the scalar `5`. Since `eye` is a generator, the multiply and the identity matrix can be evaluated without storing any values. Since we're interested in seeing the results, we execute the operator and store it in the tensor `B`:\n", - "\n", - "```c++\n", - "(B = eye({8, 8}) * 5).run();\n", - "```\n", - "\n", - "Open the file [exercises/example2_eye.cu](exercises/example2_eye.cu) and edit the contents where you see TODO markers." + "### Random Operator\n", + "The ``random`` operator provides a way to generate random numbers using various distrubtions. Random values can be useful for many applications, including generating noise in signal processing or initializing data for testing. In this example we take an existing tensor view (`A`) and populate it with random values from a normal distribution. Before setting the random values, we set all elements of `A` to zero to show the values change after randomizing.\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example2_eye" + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[2, 3], Strides:[3,1]\n", + "000000: 1.0000e+00 2.0000e+00 3.0000e+00 \n", + "000001: 4.0000e+00 5.0000e+00 6.0000e+00 \n", + "Operator{float} Rank: 2, Sizes:[2, 3]\n", + "000000: 4.2150e-41 4.2150e-41 4.2150e-41 \n", + "000001: 4.2150e-41 4.2150e-41 4.2150e-41 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(A = 0).run();\n", + "\n", + "(A = matx::random({2, 3}, matx::NORMAL)).run();\n", + "\n", + "matx::print(A);\n", + "\n", + "//broken output?\n", + "matx::print(matx::random({2, 3}, matx::NORMAL)); ///\\todo remove after run is fixed broken anyways with no memory backing" ] }, { @@ -419,17 +531,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "000000: 5.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000\n", - "000001: 0.0000 5.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000\n", - "000002: 0.0000 0.0000 5.0000 0.0000 0.0000 0.0000 0.0000 0.0000\n", - "000003: 0.0000 0.0000 0.0000 5.0000 0.0000 0.0000 0.0000 0.0000\n", - "000004: 0.0000 0.0000 0.0000 0.0000 5.0000 0.0000 0.0000 0.0000\n", - "000005: 0.0000 0.0000 0.0000 0.0000 0.0000 5.0000 0.0000 0.0000\n", - "000006: 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 5.0000 0.0000\n", - "000007: 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 5.0000\n", - "```" + "In this example we store the current random values from `randTensor` into `A`. Instead of storing the random values in `A`, `randTensor` can be used directly in operator equations, and each time it's used a different set of random values is generated." ] }, { @@ -437,41 +539,57 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "While `eye` is a fairly simple generator for creating ones on the diagonal, more complex generators exist for performing operations like windowing, or creating a linearly-spaced range of values. Below we use the `hamming_x` function to generate a Hamming window using the formula: $$ 0.5 * (1 - cos(\\frac{2{\\pi}n}{N})) $$ where `n` is the sample number and `N` is the total number of samples. Since an array of sizes is passed into the generator, these two variables are computed at runtime and the size of the shape is used as the size of the Hamming window. Like the name implies, the `_x` on `hanning` generates the window across the `x` axis, but there are versions for all four possible axes. Other window functions use the same nomenclature:\n", - "\n", - "```c++\n", - "(B = hamming_x(B.Shape())).run();\n", - "```\n", - "Open the file [exercises/example2_hamming.cu](exercises/example2_hamming.cu) and edit the contents where you see TODO markers." + "# Generators\n", + "Next, we introduce the concept of a generator by creating the identity matrix, scaling the values by `5`, and storing it in a tensor. MatX contains an `eye` operator for generating an identity matrix. Each time an element in the generator is accessed, `eye` simply returns a `1` for values in the diagonal, and `0` otherwise. Said differently, if the index for each rank is equal, the value is set to `1`. Since the goal is to have a diagonal matrix of fives, we multiply the generator by the scalar `5`. Since `eye` is a generator, the multiply and the identity matrix can be evaluated without storing any values. Since we're interested in seeing the results, we execute the operator and store it in the tensor `B`:\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example2_hamming" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:\n", - "```sh\n", - "000000: 0.0800\n", - "000001: 0.1876\n", - "000002: 0.4601\n", - "000003: 0.7700\n", - "000004: 0.9723\n", - "000005: 0.9723\n", - "000006: 0.7700\n", - "000007: 0.4601\n", - "000008: 0.1876\n", - "000009: 0.0800\n", - "```" + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[8, 8], Strides:[8,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000002: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000003: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000004: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000005: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000006: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000007: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "Operator{int32_t} Rank: 2, Sizes:[8, 8]\n", + "000000: 5 0 0 0 0 0 0 0 \n", + "000001: 0 5 0 0 0 0 0 0 \n", + "000002: 0 0 5 0 0 0 0 0 \n", + "000003: 0 0 0 5 0 0 0 0 \n", + "000004: 0 0 0 0 5 0 0 0 \n", + "000005: 0 0 0 0 0 5 0 0 \n", + "000006: 0 0 0 0 0 0 5 0 \n", + "000007: 0 0 0 0 0 0 0 5 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "(E = matx::eye({8, 8}) * 5).run();\n", + "\n", + "matx::print(E); \n", + "\n", + "matx::print(matx::eye({8, 8}) * 5); ///\\todo remove after run is fixed" ] }, { @@ -479,31 +597,62 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Visualizing Data\n", - "MatX uses PyBind and Plotly as a visualization backend of tensor views. Basic plots are supported, such as line, bar, scatter, and contour. Using the Hamming window data from the previous example, we can visualize what the window looks like:\n", - "\n", - "```c++\n", - "viz::line(B, \"Hamming Window\", \"Sample\", \"Amplitude\", \"hamming.html\");\n", - "```\n", - "\n", - "Visualizations in MatX are under the `matx::viz` nested namespace. The string parameters above give the plot a title, X axis name, and Y axis name, respectively. The last parameter is an optional filename to output the plot to. If the code was running natively in this notebook the plot would appear here, but since this is a compiled program, we output to a separate html file that you can open in your file tree. Note that since this is a standard Plotly plot, all the functionality such as zooming and panning are present." + "While `eye` is a fairly simple generator for creating ones on the diagonal, more complex generators exist for performing operations like windowing, or creating a linearly-spaced range of values. Below we use the `hamming` function to generate a Hamming window using the formula: $$ 0.5 * (1 - cos(\\frac{2{\\pi}n}{N})) $$ where `n` is the sample number and `N` is the total number of samples. Since an array of sizes is passed into the generator, these two variables are computed at runtime and the size of the shape is used as the size of the Hamming window. Like the name implies, the `_x` on `hanning` generates the window across the `x` axis, but there are versions for all four possible axes. Other window functions use the same nomenclature:\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example2_viz\n", - "\n", - "# Display plot\n", - "from IPython.display import IFrame\n", - "IFrame(src='./hamming.html', width=700, height=600)" + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor_1_f32: Tensor{float} Rank: 1, Sizes:[10], Strides:[1]\n", + "000000: 0.0000e+00 \n", + "000001: 0.0000e+00 \n", + "000002: 0.0000e+00 \n", + "000003: 0.0000e+00 \n", + "000004: 0.0000e+00 \n", + "000005: 0.0000e+00 \n", + "000006: 0.0000e+00 \n", + "000007: 0.0000e+00 \n", + "000008: 0.0000e+00 \n", + "000009: 0.0000e+00 \n", + "Operator{float} Rank: 1, Sizes:[10]\n", + "000000: 8.0000e-02 \n", + "000001: 1.8762e-01 \n", + "000002: 4.6012e-01 \n", + "000003: 7.7000e-01 \n", + "000004: 9.7226e-01 \n", + "000005: 9.7226e-01 \n", + "000006: 7.7000e-01 \n", + "000007: 4.6012e-01 \n", + "000008: 1.8762e-01 \n", + "000009: 8.0000e-02 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x757f1fdfec30\n" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(H = matx::hamming<0>(H.Shape())).run();\n", + "\n", + "matx::print(H);\n", + "\n", + "matx::print(matx::hamming<0>(H.Shape())); ///\\todo remove after run is fixed" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -514,25 +663,16 @@ } ], "metadata": { - "interpreter": { - "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" - }, "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" + "display_name": "C++17", + "language": "C++", + "name": "cling-cpp17" }, "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" + "codemirror_mode": "c++", + "file_extension": ".c++", + "mimetype": "text/x-c++src", + "name": "c++" } }, "nbformat": 4, diff --git a/docs_input/notebooks/exercises/example2_assignment1.cu b/docs_input/notebooks/exercises/example2_assignment1.cu deleted file mode 100644 index 69d2f3e65..000000000 --- a/docs_input/notebooks/exercises/example2_assignment1.cu +++ /dev/null @@ -1,158 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -/** - * MatX training assignment 2. This training goes through tensor operations that - * were learned in the 02_operators notebook. Uncomment each verification block - * as you go to ensure your solutions are correct. - */ - -int main() { - auto A = make_tensor({2, 3}); - auto B = make_tensor({2, 3}); - auto V = make_tensor({3}); - - cudaExecutor exec{}; - - /**************************************************************************************************** - * Initialize tensor A with increasing values from 0.5 to 3.0 in steps of 0.4, - *and tensor V from -1 to -3 in steps of -1. - ****************************************************************************************************/ - - /*** End editing ***/ - - // Verify init is correct - float step = 0.5; - for (int row = 0; row < A.Size(0); row++) { - for (int col = 0; col < A.Size(1); col++) { - if (A(row, col) != step) { - printf("Mismatch in A init view! actual = %f, expected = %f\n", - A(row, col), step); - exit(-1); - } - step += 0.5; - } - } - - for (int col = 0; col < V.Size(0); col++) { - if (V(col) != (-1 + col * -1)) { - printf("Mismatch in A init view! actual = %f, expected = %f\n", V(col), - (float)(-1 + col * -1)); - exit(-1); - } - } - - print(A); - print(V); - printf("Init verification passed!\n"); - - /**************************************************************************************************** - * Add 5.0 to all elements of A and store the results back in A - ****************************************************************************************************/ - - /*** End editing ***/ - - exec.sync(); - - step = 0.5; - for (int row = 0; row < A.Size(0); row++) { - for (int col = 0; col < A.Size(1); col++) { - if (A(row, col) != (5.0 + step)) { - printf("Mismatch in A sum view! actual = %f, expected = %f\n", - A(row, col), 5.0 + step); - exit(-1); - } - step += 0.5; - } - } - - print(A); - printf("Sum verification passed!\n"); - - /**************************************************************************************************** - * Clone V to match the dimensions of A, and subtract V from A. The results - * should be stored in A - * - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/quickstart.html#increasing-dimensionality - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/api/tensorview.html#_CPPv4I0_iEN4matx12tensor_tE - * - ****************************************************************************************************/ - /// auto tvs = ; - /*** End editing. ***/ - - // exec.sync(); - - // step = 0.5; - // for (int row = 0; row < A.Size(0); row++) { - // for (int col = 0; col < A.Size(1); col++) { - // if (A(row, col) != (5.0 + step - tvs(row, col))) { - // printf("Mismatch in A sub view! actual = %f, expected = %f\n", A(row, - // col), 5.0 + step - tvs(row, col)); exit(-1); - // } - // step += 0.5; - // } - // } - - // print(A); - // print(tvs); - // printf("Clone verification passed!\n"); - - /**************************************************************************************************** - * Raise the matrix A to the power of 2 and multiply the output by two. Next, - * subtract the vector V from each row. Store the result in tensor B. - * - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/api/tensorops.html#_CPPv4N4matx3powE2Op2Op - ****************************************************************************************************/ - - /*** End editing ***/ - - exec.sync(); - - for (int row = 0; row < B.Size(0); row++) { - for (int col = 0; col < B.Size(1); col++) { - if (B(row, col) != powf(A(row, col), 2) * 2 - V(col)) { - printf("Mismatch in B init view! actual = %f, expected = %f\n", - B(row, col), powf(A(row, col), 2) * 2 - V(col)); - exit(-1); - } - } - } - - print(B); - printf("Mixed verification passed!\n"); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example2_conditional.cu b/docs_input/notebooks/exercises/example2_conditional.cu deleted file mode 100644 index 30107902d..000000000 --- a/docs_input/notebooks/exercises/example2_conditional.cu +++ /dev/null @@ -1,51 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto A = make_tensor({2, 3}); - auto C = make_tensor({2, 3}); - - C.SetVals({ {1, 2, 3}, - {4, 5, 6}}); - - - // TODO: Conditionally assign elements of A the value of 1 if the same element in C is > 3, or 0 otherwise - - - print(A); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example2_eye.cu b/docs_input/notebooks/exercises/example2_eye.cu deleted file mode 100644 index 77fe96a2d..000000000 --- a/docs_input/notebooks/exercises/example2_eye.cu +++ /dev/null @@ -1,45 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto B = make_tensor({8, 8}); - - // TODO: Set tensor B such that it forms an identity matrix - - print(B); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example2_hamming.cu b/docs_input/notebooks/exercises/example2_hamming.cu deleted file mode 100644 index 574760a41..000000000 --- a/docs_input/notebooks/exercises/example2_hamming.cu +++ /dev/null @@ -1,47 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto B = make_tensor({10}); - - // TODO: Set tensor B such that it forms a Hamming window - - - print(B); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example2_init.cu b/docs_input/notebooks/exercises/example2_init.cu deleted file mode 100644 index 2e693abdc..000000000 --- a/docs_input/notebooks/exercises/example2_init.cu +++ /dev/null @@ -1,53 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto A = make_tensor({2, 3}); - auto B = make_tensor({2, 3}); - auto C = make_tensor({2, 3}); - auto V = make_tensor({3}); - - // TODO: Initialize the A tensor to contain values increasing from 1 to 6, and - // V from 7 to 9. - A = {}; - V = {}; - - print(A); - printf("\n"); - print(V); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example2_mixed_rank.cu b/docs_input/notebooks/exercises/example2_mixed_rank.cu deleted file mode 100644 index 660f59870..000000000 --- a/docs_input/notebooks/exercises/example2_mixed_rank.cu +++ /dev/null @@ -1,55 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto A = make_tensor({2, 3}); - auto B = make_tensor({2, 3}); - auto C = make_tensor({2, 3}); - auto V = make_tensor({3}); - - C.SetVals({ {1, 2, 3}, - {4, 5, 6}}); - - V.SetVals({7, 8, 9}); - - // TODO: Add vector V to matrix C using rank expansion. Store result in C - - - print(C); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example2_multiple_ops.cu b/docs_input/notebooks/exercises/example2_multiple_ops.cu deleted file mode 100644 index 84048b489..000000000 --- a/docs_input/notebooks/exercises/example2_multiple_ops.cu +++ /dev/null @@ -1,54 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto A = make_tensor({2, 3}); - auto B = make_tensor({2, 3}); - auto C = make_tensor({2, 3}); - auto V = make_tensor({3}); - - A.SetVals({ {1, 2, 3}, - {4, 5, 6}}); - - V.SetVals({7, 8, 9}); - - // TODO: Add A to itself plus 1, divide the result by 2, and add vector V. - - - print(C); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example2_rand.cu b/docs_input/notebooks/exercises/example2_rand.cu deleted file mode 100644 index 378b60ad5..000000000 --- a/docs_input/notebooks/exercises/example2_rand.cu +++ /dev/null @@ -1,47 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto A = make_tensor({4, 4}); - - (A = 0).run(); - - // TODO: Set tensor A to normally-distributed random numbers - - - print(A); -} diff --git a/docs_input/notebooks/exercises/example2_scalar.cu b/docs_input/notebooks/exercises/example2_scalar.cu deleted file mode 100644 index 7c827005d..000000000 --- a/docs_input/notebooks/exercises/example2_scalar.cu +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto A = make_tensor({2, 3}); - auto B = make_tensor({2, 3}); - auto C = make_tensor({2, 3}); - auto V = make_tensor({3}); - - A.SetVals({ {1, 2, 3}, - {4, 5, 6}}); - - V.SetVals({7, 8, 9}); - - // TODO: Add the value 1 to all elements of A and store the result in B - - - print(A); - printf("\n"); - print(B); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example2_tensor_add.cu b/docs_input/notebooks/exercises/example2_tensor_add.cu deleted file mode 100644 index 47d06344d..000000000 --- a/docs_input/notebooks/exercises/example2_tensor_add.cu +++ /dev/null @@ -1,57 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto A = make_tensor({2, 3}); - auto B = make_tensor({2, 3}); - auto C = make_tensor({2, 3}); - auto V = make_tensor({3}); - - A.SetVals({ {1, 2, 3}, - {4, 5, 6}}); - - B.SetVals({ {7, 8, 9}, - {10, 11, 12}}); - - // TODO: Add tensors A and B and store the result in C - - - print(A); - printf("\n"); - print(B); - printf("\n"); - print(C); -} \ No newline at end of file diff --git a/docs_input/notebooks/exercises/example2_tensor_div.cu b/docs_input/notebooks/exercises/example2_tensor_div.cu deleted file mode 100644 index 9cf71f383..000000000 --- a/docs_input/notebooks/exercises/example2_tensor_div.cu +++ /dev/null @@ -1,45 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto C = make_tensor({2, 3}); - - C.SetVals({{7, 8, 9}, {10, 11, 12}}); - - // TODO: Divide tensor C by 2 and store in C - - print(C); -} \ No newline at end of file diff --git a/docs_input/notebooks/exercises/example2_viz.cu b/docs_input/notebooks/exercises/example2_viz.cu deleted file mode 100644 index 8c11ccb85..000000000 --- a/docs_input/notebooks/exercises/example2_viz.cu +++ /dev/null @@ -1,47 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include -#include "matx_viz.h" - -using namespace matx; - -int main() { - auto B = make_tensor({10}); - - // TODO: Set tensor B such that it forms a Hamming window - (B = hamming_x(shape)).run(); - - viz::line(B, "Hamming Window", "Sample", "Amplitude", "hamming.html"); - - return 0; -} From bbb37a9f36a8ae302ec6fcd92285794e2d0ce66f Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Fri, 24 Jan 2025 08:35:38 +0000 Subject: [PATCH 03/91] updated transforms notebook to use cell based execution --- docs_input/notebooks/03_transforms.ipynb | 740 ++++++++++++------ .../notebooks/exercises/example3_1dfft.cu | 57 -- .../notebooks/exercises/example3_2dfft.cu | 56 -- .../exercises/example3_assignment1.cu | 115 --- .../notebooks/exercises/example3_conv1d.cu | 55 -- .../notebooks/exercises/example3_conv2d.cu | 58 -- .../notebooks/exercises/example3_fft_conv.cu | 92 --- .../exercises/example3_full_reduce.cu | 58 -- .../notebooks/exercises/example3_gemm.cu | 55 -- .../exercises/example3_partial_reduce.cu | 61 -- 10 files changed, 495 insertions(+), 852 deletions(-) delete mode 100644 docs_input/notebooks/exercises/example3_1dfft.cu delete mode 100644 docs_input/notebooks/exercises/example3_2dfft.cu delete mode 100644 docs_input/notebooks/exercises/example3_assignment1.cu delete mode 100644 docs_input/notebooks/exercises/example3_conv1d.cu delete mode 100644 docs_input/notebooks/exercises/example3_conv2d.cu delete mode 100644 docs_input/notebooks/exercises/example3_fft_conv.cu delete mode 100644 docs_input/notebooks/exercises/example3_full_reduce.cu delete mode 100644 docs_input/notebooks/exercises/example3_gemm.cu delete mode 100644 docs_input/notebooks/exercises/example3_partial_reduce.cu diff --git a/docs_input/notebooks/03_transforms.ipynb b/docs_input/notebooks/03_transforms.ipynb index e148df739..982f7aaae 100644 --- a/docs_input/notebooks/03_transforms.ipynb +++ b/docs_input/notebooks/03_transforms.ipynb @@ -33,6 +33,49 @@ "Some executors use CUDA libraries to implement their functionality, and those libraries require either a handle or a plan to operated. MatX hides this complexity by creating and caching the plan on the first call, and using the same plan on future calls where possible. More advanced users may use the handle interface directly to avoid the caching. Only the caching interface will be covered in this tutorial since it's the recommended approach, but the non-cached version can be found in the documentation." ] }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "//todo this should be moved to a hidden init block that runs automatically when the notebook starts\n", + "#pragma cling add_library_path(\"/usr/local/cuda/lib64\")\n", + "#pragma cling add_library_path(\"/opt/xeus/cling/lib\")\n", + "//#pragma cling add_library_path(\"/usr/Lib/gcc/x86_64-Linux-gnu/11/\")\n", + "#pragma cling add_library_path(\"/usr/lib/x86_64-linux-gnu/openblas64-openmp/\")\n", + "#pragma cling add_include_path(\"/usr/local/cuda/include\")\n", + "#pragma cling add_include_path(\"/usr/include/x86_64-linux-gnu/openblas64-openmp\")\n", + "#pragma cling add_include_path(\"/opt/xeus/cling/tools/Jupyter/kernel/MatX/include\")\n", + "#pragma cling add_include_path(\"/opt/xeus/cling/tools/Jupyter/kernel/MatX/build/_deps/cccl-src/libcudacxx/include\")\n", + "//#pragma cling load(\"libgomp\")\n", + "#pragma cling load(\"libopenblas64\")\n", + "#pragma cling load(\"libcuda\")\n", + "#pragma cling load(\"libcudart\")\n", + "#pragma cling load(\"libcurand\")\n", + "#pragma cling load(\"libcublas\")\n", + "#pragma cling load(\"libcublasLt\")\n", + "#pragma cling load(\"libcufft\")\n", + "\n", + "#include \n", + "#include \n", + "\n", + "#define MATX_EN_OPENBLAS\n", + "#define MATX_EN_OPENBLAS_LAPACK\n", + "#define MATX_OPENBLAS_64BITINT\n", + "\n", + "#include \"matx.h\"" + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -43,56 +86,75 @@ "\n", "We use rectangular matrices for `A` and `B`, while `C` will be a square matrix due to the outer dimensions of `A` and `B` matching. \n", "\n", - "```c++\n", - "(A = random({8, 4}, NORMAL)).run(); \n", - "(B = random({4, 8}, NORMAL)).run(); \n", - "\n", - "matmul(C, A, B);\n", - "``` \n", "\n", "Open the file [exercises/example3_gemm.cu](exercises/example3_gemm.cu) and edit the contents where you see TODO markers." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example3_gemm" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", + "execution_count": 2, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A:\n", + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[8, 4], Strides:[4,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000002: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000003: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000004: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000005: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000006: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000007: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "B:\n", + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[4, 8], Strides:[8,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000002: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000003: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "C:\n", + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[8, 8], Strides:[8,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000002: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000003: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000004: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000005: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000006: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000007: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x78e507dfec30\n" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "Expected output:\n", - "```sh\n", - "A:\n", - "000000: -0.9247 -0.4253 -2.6438 0.1452\n", - "000001: -0.1209 -0.5797 -0.6229 -0.3284\n", - "000002: -1.0745 -0.3631 -1.6711 2.2655\n", - "000003: 0.3117 -0.1842 1.2866 1.1820\n", - "000004: -0.1271 1.2169 1.4353 1.0605\n", - "000005: -0.4941 -1.4244 -0.7244 -1.2973\n", - "000006: 0.0697 -0.0074 1.8969 0.6878\n", - "000007: -0.0779 -0.8373 1.3506 -0.2879\n", - "B:\n", - "000000: 0.9911 1.0676 -0.6272 0.3202 -0.3110 -0.3441 -1.1709 -0.5371\n", - "000001: 1.3390 -0.2401 1.2149 -0.2052 1.2999 0.2181 -1.2135 -1.3723\n", - "000002: -0.4635 -0.4089 -0.0032 0.2967 -0.3587 -1.0455 -0.0450 -0.0985\n", - "000003: 1.7608 0.9107 0.0288 -1.1128 0.0929 -0.1502 -0.9854 0.7889\n", - "C:\n", - "000000: -0.0050 0.3283 0.0760 -1.1547 0.6966 2.9677 1.5747 1.4554\n", - "000001: -1.1856 -0.0342 -0.6359 0.2609 -0.5231 0.6156 1.1966 0.6628\n", - "000002: 3.2124 1.6864 0.3035 -3.2863 0.6721 1.6973 -0.4584 3.0275\n", - "000003: 1.5472 0.9272 -0.3894 -0.7960 -0.6881 -1.6701 -1.3640 0.8911\n", - "000004: 2.7056 -0.0490 1.5840 -1.0446 1.2051 -1.3507 -2.4374 -0.9065\n", - "000005: -4.3456 -1.0707 -1.4556 1.3628 -1.5586 0.8115 3.6179 1.2680\n", - "000006: 0.3910 -0.0732 -0.0391 -0.1788 -0.6479 -2.1121 -0.8357 0.3284\n", - "000007: -2.3314 -0.6966 -0.9810 0.8679 -1.5754 -1.5246 1.3302 0.8306\n", - "```" + " auto A = matx::make_tensor({8, 4});\n", + " auto B = matx::make_tensor({4, 8});\n", + " auto C = matx::make_tensor({8, 8});\n", + "\n", + " (A = matx::random({8, 4}, matx::NORMAL)).run(); \n", + " (B = matx::random({4, 8}, matx::NORMAL)).run(); \n", + "\n", + " // TODO: Perform a GEMM of C = A*B\n", + " (C = matx::matmul(A, B)).run();\n", + " \n", + " printf(\"A:\\n\");\n", + " matx::print(A);\n", + " printf(\"B:\\n\");\n", + " matx::print(B); \n", + " printf(\"C:\\n\");\n", + " matx::print(C); \n" ] }, { @@ -103,26 +165,34 @@ "### FFT\n", "MatX provides an interface to do both 1D Fast Fourier Transforms (FFTs) and 2D FFTs. Any tensor above rank 1 will be batched in a 1D FFT, and any tensor above rank 2 will be batched in a 2D FFT. FFTs may either be done in-place or out-of-place by using the same or different variables for the output and inputs. Since the tensors are strongly-typed, the type of FFT (C2C, R2C, etc) is inferred by the tensor type at compile time. Similarly, the input and output size of the executor is deduced by the type of transform, and the input/output tensors must match those sizes. There's one exception to this rule, and it's when the input FFT is to be zero-padded at the end. In this case, the input tensor can be shorter than the output tensor, and the input will be zero-padded to the length of the output tensor. This is a common tactic used in signal and image processing for both speed and FFT resolution.\n", "\n", - "In this example, we execute a 1D batched FFT on a 2D tensor populated with random complex floating point data. Since the FFT executor is performed in-place, the input and output types of the tensors are the same, and the type of the FFT is inferred as a complex-to-complex (`C2C`). The FFT length is specified by the inner dimension of the tensor, or 4 in this example, and the outer dimension is the number of batches, or 2. After the FFT completes, we perform on IFFT on the same tensor using the `ifft` interface. Ignoring floating point inaccuracies, the result of `ifft(fft(A))` should be the same as `A`, and this is shown by printing the tensors at each step. To perform a batched FFT on columns instead of rows, the tensor can be transposed by calling the `Permute` function used in the first tutorial. When the library detects a permuted tensor is being used, it can use technique to speed the FFT up over the naive method of converting the data in memory.\n", - "\n", - "```c++\n", - "C.print();\n", - "fft(C, C);\n", - "C.print();\n", - "ifft(C, C); \n", - "C.print();\n", - "```\n", - "\n", - "Open the file [exercises/example3_1dfft.cu](exercises/example3_1dfft.cu) and edit the contents where you see TODO markers." + "In this example, we execute a 1D batched FFT on a 2D tensor populated with random complex floating point data. Since the FFT executor is performed in-place, the input and output types of the tensors are the same, and the type of the FFT is inferred as a complex-to-complex (`C2C`). The FFT length is specified by the inner dimension of the tensor, or 4 in this example, and the outer dimension is the number of batches, or 2. After the FFT completes, we perform on IFFT on the same tensor using the `ifft` interface. Ignoring floating point inaccuracies, the result of `ifft(fft(A))` should be the same as `A`, and this is shown by printing the tensors at each step. To perform a batched FFT on columns instead of rows, the tensor can be transposed by calling the `Permute` function used in the first tutorial. When the library detects a permuted tensor is being used, it can use technique to speed the FFT up over the naive method of converting the data in memory." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "!./exercises/compile_and_run.sh example3_1dfft" + "auto D = matx::make_tensor({2, 4});\n", + "\n", + "// (D = matx::random(D.Shape(), matx::NORMAL)).run();\n", + "// matx::print(D);\n", + "\n", + "// (D = fft(D)).run();\n", + "// matx::print(D);\n", + "\n", + "// (D = matx::ifft(D)).run(); \n", + "// matx::print(D);" ] }, { @@ -130,66 +200,41 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "Initial C tensor:\n", - "000000: -0.9247+0.9911j -0.4253+1.0676j -2.6438-0.6272j 0.1452+0.3202j \n", - "000001: -0.1209-0.3110j -0.5797-0.3441j -0.6229-1.1709j -0.3284-0.5371j \n", - "After FFT:\n", - "000000: -3.8487+1.7517j 2.4666+2.1889j -3.2883-1.0238j 0.9718+1.0478j \n", - "000001: -1.6518-2.3630j 0.6950+1.1112j 0.1644-0.6007j 0.3090+0.6085j \n", - "After IFFT and normalization:\n", - "000000: -0.9247+0.9911j -0.4253+1.0676j -2.6438-0.6272j 0.1452+0.3202j \n", - "000001: -0.1209-0.3110j -0.5797-0.3441j -0.6229-1.1709j -0.3284-0.5371j \n", - "```" + "Next, we take the same 2D tensor and perform a 2D FFT on it. Since the rank is 2, it will not be batched as in the previous example. " ] }, { - "attachments": {}, - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 4, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(void) @0x78e507dfec30\n" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "Next, we take the same 2D tensor and perform a 2D FFT on it. Since the rank is 2, it will not be batched as in the previous example. \n", - "\n", - "```c++\n", - "C.print();\n", - "fft2(C, C);\n", - "C.print();\n", - "ifft2(C, C); \n", - "C.print();\n", - "```\n", + "(D = matx::random(D.Shape(), matx::NORMAL)).run();\n", + "// matx::print(D);\n", "\n", - "As before, the results after the IFFT closely match the original `C` tensor, but with floating point error.\n", + "// (D = fft2(D)).run();\n", + "// matx::print(D);\n", "\n", - "Open the file [exercises/example3_2dfft.cu](exercises/example3_2dfft.cu) and edit the contents where you see TODO markers." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example3_2dfft" + "// (D = matx::ifft2(D)).run(); \n", + "// matx::print(D);" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "Intial C tensor:\n", - "000000: -0.9247+0.9911j -0.4253+1.0676j -2.6438-0.6272j 0.1452+0.3202j \n", - "000001: -0.1209-0.3110j -0.5797-0.3441j -0.6229-1.1709j -0.3284-0.5371j \n", - "After FFT:\n", - "000000: -2.0506+1.4036j -0.0405-0.0434j -2.6438-0.6272j 0.1452+0.3202j \n", - "000001: -2.0051+2.7593j -0.4662-0.5353j -0.6229-1.1709j -0.3284-0.5371j \n", - "After IFFT and normalization:\n", - "000000: -1.8493+1.9823j -0.8507+2.1352j -0.6610-0.1568j 0.0363+0.0800j \n", - "000001: -0.2417-0.6220j -1.1595-0.6882j -0.1557-0.2927j -0.0821-0.1343j \n", - "```" + "As before, the results after the IFFT closely match the original `C` tensor, but with floating point error." ] }, { @@ -203,23 +248,61 @@ "MatX provides a set of optimized primitives to perform reductions on tensors for many common types. Reductions are supported across individual dimensions or on entire tensors, depending on the size of the output tensor. Currently supported reduction functions are `sum`, `min`, `max`,` mean`, `any`, and `all`.\n", "\n", "#### Full Reduction\n", - "In this example we reduce an entire tensor to a single value by applying the reduction across all dimensions of the tensor. We apply the same random initialization from previous examples on a 2D tensor `A`. Note that the output tensor must be zeroed for a `sum` reduction since that value is continually added to during the reduction. Not initializing the output tensor will give undefined results since the variables are used as accumulators throughout the reduction. With the tensor initialized, we perform both a `max` and `sum` reduction across all dimensions of the tensor:\n", - "\n", - "```c++\n", - "max(MD0, A);\n", - "sum(AD0, A);\n", - "```\n", - "\n", - "Open the file [exercises/example3_full_reduce.cu](exercises/example3_full_reduce.cu) and edit the contents where you see TODO markers." + "In this example we reduce an entire tensor to a single value by applying the reduction across all dimensions of the tensor. We apply the same random initialization from previous examples on a 2D tensor `A`. Note that the output tensor must be zeroed for a `sum` reduction since that value is continually added to during the reduction. Not initializing the output tensor will give undefined results since the variables are used as accumulators throughout the reduction. With the tensor initialized, we perform both a `max` and `sum` reduction across all dimensions of the tensor:\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A:\n", + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[8, 4], Strides:[4,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000002: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000003: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000004: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000005: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000006: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000007: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "Max: 0.000000\n", + "Sum: 0.000000\n" + ] + }, + { + "data": { + "text/plain": [ + "(int) 14\n" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "!./exercises/compile_and_run.sh example3_full_reduce" + "\n", + " auto MD0 = matx::make_tensor({});\n", + " auto AD0 = matx::make_tensor({});\n", + "\n", + " (A = matx::random(A.Shape(), matx::NORMAL)).run(); \n", + " \n", + " // Initialize max and average to 0\n", + " (MD0 = 0).run();\n", + " (AD0 = 0).run();\n", + "\n", + " (MD0 = max(A)).run();\n", + " (AD0 = sum(A)).run();\n", + "\n", + " printf(\"A:\\n\");\n", + " matx::print(A);\n", + " printf(\"Max: %f\\n\", MD0());\n", + " printf(\"Sum: %f\\n\", AD0()); " ] }, { @@ -227,68 +310,107 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "A:\n", - "000000: -0.9247 -0.4253 -2.6438 0.1452 -0.1209 \n", - "000001: -0.5797 -0.6229 -0.3284 -1.0745 -0.3631 \n", - "000002: -1.6711 2.2655 0.3117 -0.1842 1.2866 \n", - "000003: 1.1820 -0.1271 1.2169 1.4353 1.0605 \n", - "Max: 2.265505\n", - "Sum: -0.162026\n", - "```" + "#### Dimensional Reductions\n", + "Reductions can also be performed across certain dimensions instead of the whole tensor. Dimensional reductions are useful in situations where each row contains data for a different user, for example, and we wish to sum up each user's data. By setting the output tensor view to a 1D tensor, independent reductions can be performed across the input tensor where each output element corresponds to a single row reduction from the input. Using the same tensor `A` from the previous example, we only change the output tensor type to be a 1D tensor instead of a scalar:\n" ] }, { - "attachments": {}, - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 6, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(void) @0x78e507dfec30\n" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "#### Dimensional Reductions\n", - "Reductions can also be performed across certain dimensions instead of the whole tensor. Dimensional reductions are useful in situations where each row contains data for a different user, for example, and we wish to sum up each user's data. By setting the output tensor view to a 1D tensor, independent reductions can be performed across the input tensor where each output element corresponds to a single row reduction from the input. Using the same tensor `A` from the previous example, we only change the output tensor type to be a 1D tensor instead of a scalar:\n", "\n", - "```c++\n", - " max(MD1, A);\n", - " sum(AD1, A); \n", - "```\n", + " auto MD1 = matx::make_tensor({A.Size(0)});\n", + " auto AD1 = matx::make_tensor({A.Size(0)});\n", "\n", - "Printing the new reduction tensors shows the reduced values across each row of the input tensor `A`.\n", + " (A = matx::random(A.Shape(), matx::NORMAL)).run(); \n", + " \n", + " // Initialize max and average to 0\n", + " (MD1 = 0).run();\n", + " (AD1 = 0).run();\n", "\n", - "Open the file [exercises/example3_partial_reduce.cu](exercises/example3_partial_reduce.cu) and edit the contents where you see TODO markers." + " (MD1 = max(A)).run();\n", + " (AD1 = sum(A)).run();" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "!./exercises/compile_and_run.sh example3_partial_reduce" + "Printing the new reduction tensors shows the reduced values across each row of the input tensor `A`." ] }, { - "attachments": {}, - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 7, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A:\n", + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[8, 4], Strides:[4,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000002: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000003: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000004: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000005: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000006: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000007: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "Max:\n", + "tensor_1_f32: Tensor{float} Rank: 1, Sizes:[8], Strides:[1]\n", + "000000: 0.0000e+00 \n", + "000001: 0.0000e+00 \n", + "000002: 0.0000e+00 \n", + "000003: 0.0000e+00 \n", + "000004: 0.0000e+00 \n", + "000005: 0.0000e+00 \n", + "000006: 0.0000e+00 \n", + "000007: 0.0000e+00 \n", + "Sum:\n", + "tensor_1_f32: Tensor{float} Rank: 1, Sizes:[8], Strides:[1]\n", + "000000: 0.0000e+00 \n", + "000001: 0.0000e+00 \n", + "000002: 0.0000e+00 \n", + "000003: 0.0000e+00 \n", + "000004: 0.0000e+00 \n", + "000005: 0.0000e+00 \n", + "000006: 0.0000e+00 \n", + "000007: 0.0000e+00 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x78e507dfec30\n" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "Expected output:\n", - "```sh\n", - "A:\n", - "000000: -0.9247 -0.4253 -2.6438 0.1452 -0.1209 \n", - "000001: -0.5797 -0.6229 -0.3284 -1.0745 -0.3631 \n", - "000002: -1.6711 2.2655 0.3117 -0.1842 1.2866 \n", - "000003: 1.1820 -0.1271 1.2169 1.4353 1.0605 \n", - "Max:\n", - "000000: 0.1452 \n", - "000001: -0.3284 \n", - "000002: 2.2655 \n", - "000003: 1.4353 \n", - "Sum:\n", - "000000: -3.9695 \n", - "000001: -2.9686 \n", - "000002: 2.0086 \n", - "000003: 4.7676 \n", - "```" + " printf(\"A:\\n\");\n", + " matx::print(A);\n", + " printf(\"Max:\\n\");\n", + " matx::print(MD1);\n", + " printf(\"Sum:\\n\");\n", + " matx::print(AD1);" ] }, { @@ -297,20 +419,82 @@ "metadata": {}, "source": [ "### Convolution\n", - "MatX supports both 1D and 2D direct convolution using the `conv1d` and `conv2d` functions. FFT-based convolution can also be performed as a combination of existing primitives as a potentially faster alternative to direct convolution for large tensors. Both forms of direct convolution take in an extra mode which specifies how much of the output is saved, where `MATX_C_MODE_FULL` saves the entire filter ramp-up and down, `MATX_C_MODE_SAME` makes the input and output tensors the same size, and `MATX_C_MODE_VALID` only keeps valid samples (when the entire filter was part of the convolution). Convolution can be used to perform a rolling average of an input by making all filter values 1/N, where N is the length of the filter. In this example, we use a filter of length 3 to create a running average of the last 3 elements:\n", - "\n", - "```c++\n", - "conv1d(Co, C, filt, MATX_C_MODE_FULL, 0);\n", - "```" + "MatX supports both 1D and 2D direct convolution using the `conv1d` and `conv2d` functions. FFT-based convolution can also be performed as a combination of existing primitives as a potentially faster alternative to direct convolution for large tensors. Both forms of direct convolution take in an extra mode which specifies how much of the output is saved, where `MATX_C_MODE_FULL` saves the entire filter ramp-up and down, `MATX_C_MODE_SAME` makes the input and output tensors the same size, and `MATX_C_MODE_VALID` only keeps valid samples (when the entire filter was part of the convolution). Convolution can be used to perform a rolling average of an input by making all filter values 1/N, where N is the length of the filter. In this example, we use a filter of length 3 to create a running average of the last 3 elements:\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Initial CIn tensor:\n", + "tensor_1_f32: Tensor{float} Rank: 1, Sizes:[16], Strides:[1]\n", + "000000: 0.0000e+00 \n", + "000001: 0.0000e+00 \n", + "000002: 0.0000e+00 \n", + "000003: 0.0000e+00 \n", + "000004: 0.0000e+00 \n", + "000005: 0.0000e+00 \n", + "000006: 0.0000e+00 \n", + "000007: 0.0000e+00 \n", + "000008: 0.0000e+00 \n", + "000009: 0.0000e+00 \n", + "000010: 0.0000e+00 \n", + "000011: 0.0000e+00 \n", + "000012: 0.0000e+00 \n", + "000013: 0.0000e+00 \n", + "000014: 0.0000e+00 \n", + "000015: 0.0000e+00 \n", + "tensor_1_f32: Tensor{float} Rank: 1, Sizes:[18], Strides:[1]\n", + "000000: 0.0000e+00 \n", + "000001: 0.0000e+00 \n", + "000002: 0.0000e+00 \n", + "000003: 0.0000e+00 \n", + "000004: 0.0000e+00 \n", + "000005: 0.0000e+00 \n", + "000006: 0.0000e+00 \n", + "000007: 0.0000e+00 \n", + "000008: 0.0000e+00 \n", + "000009: 0.0000e+00 \n", + "000010: 0.0000e+00 \n", + "000011: 0.0000e+00 \n", + "000012: 0.0000e+00 \n", + "000013: 0.0000e+00 \n", + "000014: 0.0000e+00 \n", + "000015: 0.0000e+00 \n", + "000016: 0.0000e+00 \n", + "000017: 0.0000e+00 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x78e507dfec30\n" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "!./exercises/compile_and_run.sh example3_conv1d" + "auto CIn = matx::make_tensor({16});\n", + "auto filt = matx::make_tensor({3});\n", + "auto Co = matx::make_tensor({16 + filt.Lsize() - 1});\n", + "\n", + "filt.SetVals({1.0/3, 1.0/3, 1.0/3});\n", + "\n", + "(CIn = matx::random({16}, matx::NORMAL)).run(); \n", + "\n", + "printf(\"Initial CIn tensor:\\n\");\n", + "matx::print(CIn);\n", + "(Co = matx::conv1d(CIn, filt, matx::MATX_C_MODE_FULL)).run();\n", + "\n", + "matx::print(Co);" ] }, { @@ -318,45 +502,67 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Expected output:\n", - "```sh\n", - "Initial C tensor:\n", - "000000: -0.9247\n", - "000001: -0.4253\n", - "000002: -2.6438\n", - "000003: 0.1452\n", - "000004: -0.1209\n", - "000005: -0.5797\n", - "000006: -0.6229\n", - "000007: -0.3284\n", - "000008: -1.0745\n", - "000009: -0.3631\n", - "000010: -1.6711\n", - "000011: 2.2655\n", - "000012: 0.3117\n", - "000013: -0.1842\n", - "000014: 1.2866\n", - "000015: 1.1820\n", - "After conv1d:\n", - "000000: -0.3082\n", - "000001: -0.4500\n", - "000002: -1.3313\n", - "000003: -0.9747\n", - "000004: -0.8732\n", - "000005: -0.1851\n", - "000006: -0.4411\n", - "000007: -0.5103\n", - "000008: -0.6753\n", - "000009: -0.5887\n", - "000010: -1.0362\n", - "000011: 0.0771\n", - "000012: 0.3020\n", - "000013: 0.7977\n", - "000014: 0.4714\n", - "000015: 0.7615\n", - "000016: 0.8229\n", - "000017: 0.3940\n", - "```" + "Similar to a 1D convolution, a 2D convolution does the same computation over two dimensions. A tensor of at least rank 2 is needed for a 2D convolution. Below we use a filter of all ones using the `ones` operator to demonstrate the filter can also be an operator and not an existing tensor view. The result is the sum of the four values around each cell on the input:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Initial C tensor:\n", + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[8, 8], Strides:[8,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000002: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000003: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000004: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000005: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000006: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000007: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "After conv2d:\n", + "tensor_2_f32: Tensor{float} Rank: 2, Sizes:[8, 8], Strides:[8,1]\n", + "000000: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000001: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000002: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000003: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000004: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000005: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000006: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n", + "000007: 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 \n" + ] + }, + { + "data": { + "text/plain": [ + "(void) @0x78e507dfec30\n" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + " auto CIn2 = matx::make_tensor({8,8});\n", + " auto filt2 = matx::ones({2, 2});\n", + " auto Co2 = matx::make_tensor({8, 8});\n", + "\n", + " (CIn2 = matx::random({8, 8}, matx::NORMAL)).run(); \n", + "\n", + " printf(\"Initial C tensor:\\n\");\n", + " matx::print(C);\n", + "\n", + " (Co2 = matx::conv2d(CIn2, filt, matx::MATX_C_MODE_SAME)).run();\n", + " \n", + " printf(\"After conv2d:\\n\");\n", + " matx::print(Co2);\n", + "\n" ] }, { @@ -364,39 +570,94 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Similar to a 1D convolution, a 2D convolution does the same computation over two dimensions. A tensor of at least rank 2 is needed for a 2D convolution. Below we use a filter of all ones using the `ones` operator to demonstrate the filter can also be an operator and not an existing tensor view. The result is the sum of the four values around each cell on the input:\n", - "\n", - "```c++\n", - "conv2d(Co, C, filt, MATX_C_MODE_FULL, 0);\n", - "```" + "Last, we mentioned above that convolution can also be done in the frequency domain using FFTs. This is the preferred method for larger tensors since FFTs are much faster than direct convolutions in large sizes, and because FFT libraries are highly-optimized. FFT convolution uses more memory than direct if the inputs are not to be destroyed since it requires running an FFT on both the input signal and filter before filtering. If not done in-place, this typically requires `2N + L - 1` new elements in memory, where N is the signal length and L is the filter length. A full FFT convolution example can be found in `fft_conv.cu` in the MatX examples, but the main convolution code is shown below:\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "!./exercises/compile_and_run.sh example3_conv2d" + "\n", + "///\\todo complete this tutorial. This one is pretty complex, do we want to keep the validation code here?\n", + "\n", + "// using complex = cuda::std::complex;\n", + "// cudaExecutor exec{};\n", + "\n", + "// index_t signal_size = 16;\n", + "// index_t filter_size = 3;\n", + "// index_t filtered_size = signal_size + filter_size - 1;\n", + "\n", + "// // Create time domain buffers\n", + "// auto sig_time = make_tensor({signal_size});\n", + "// auto filt_time = make_tensor({filter_size});\n", + "// auto time_out = make_tensor({filtered_size});\n", + "\n", + "// // Frequency domain buffers\n", + "// auto sig_freq = make_tensor({filtered_size});\n", + "// auto filt_freq = make_tensor({filtered_size});\n", + "\n", + "// // Fill the time domain signals with data\n", + "// for (index_t i = 0; i < signal_size; i++) {\n", + "// sig_time(i) = {-1.0f * (2.0f * static_cast(i % 2) + 1.0f) *\n", + "// (static_cast(i % 10) / 10.0f) +\n", + "// 0.1f,\n", + "// -1.0f * (static_cast(i % 2) == 0.0f) *\n", + "// (static_cast(i % 10) / 5.0f) -\n", + "// 0.1f};\n", + "// }\n", + "// for (index_t i = 0; i < filter_size; i++) {\n", + "// filt_time(i) = {static_cast(i) / static_cast(filter_size),\n", + "// static_cast(-i) / static_cast(filter_size) +\n", + "// 0.5f};\n", + "// }\n", + "\n", + "// TODO: Perform FFT convolution\n", + "// Perform the FFT in-place on both signal and filter\n", + "// (sig_freq = fft(sig_time)).run();\n", + "// (filt_freq = fft(filt_time)).run();\n", + "\n", + "// (sig_freq = sig_freq * filt_freq).run();\n", + "\n", + "// // IFFT in-place\n", + "// (sig_freq = ifft(sig_freq)).run(); \n", + "\n", + "\n", + "// Perform the FFT in-place on both signal and filter, do an element-wise multiply of the two, then IFFT that output\n", + "// (sig_freq = ifft(fft(sig_time, filtered_size) * fft(filt_time, filtered_size))).run(stream);\n", + "\n", + "// TODO: Perform a time-domain convolution\n", + "// conv1d(time_out, sig_time, filt_time, matxConvCorrMode_t::MATX_C_MODE_FULL, 0);\n", + "\n", + "// exec.sync();\n", + "\n", + "// // Compare signals\n", + "// for (index_t i = 0; i < filtered_size; i++) {\n", + "// if ( fabs(time_out(i).real() - sig_freq(i).real()) > 0.001 || \n", + "// fabs(time_out(i).imag() - sig_freq(i).imag()) > 0.001) {\n", + "// printf(\"Verification failed at item %lld. Direct=%f%+.2fj, FFT=%f%+.2fj\\n\", i,\n", + "// time_out(i).real(), time_out(i).imag(), sig_freq(i).real(), sig_freq(i).imag());\n", + "// return -1;\n", + "// }\n", + "// }\n", + "\n", + "std::cout << \"Verification successful\" << std::endl;\n" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "Last, we mentioned above that convolution can also be done in the frequency domain using FFTs. This is the preferred method for larger tensors since FFTs are much faster than direct convolutions in large sizes, and because FFT libraries are highly-optimized. FFT convolution uses more memory than direct if the inputs are not to be destroyed since it requires running an FFT on both the input signal and filter before filtering. If not done in-place, this typically requires `2N + L - 1` new elements in memory, where N is the signal length and L is the filter length. A full FFT convolution example can be found in `fft_conv.cu` in the MatX examples, but the main convolution code is shown below:\n", - "\n", - "```c++\n", - " // Perform the FFT in-place on both signal and filter\n", - " (sig_freq = fft(sig_time)).run();\n", - " (filt_freq = fft(filt_time)).run();\n", - "\n", - " (sig_freq = sig_freq * filt_freq).run();\n", - "\n", - " // IFFT in-place\n", - " (sig_freq = ifft(sig_freq)).run();\n", - "```\n", "Since the expected output size of the full filtering operation is signal_len + filter_len - 1, both the filter and signal time domain inputs are shorter than the output. This would normally require a separate stage of allocating buffers of the appropriate size, zeroing them out, copying the time domain data to the buffers, and performing the FFT. However, MatX has an API to do all of this automatically in the library using asynchronous allocations. This makes the call have a noticeable performance hit on the first call, but subsequent calls will be close to the time without allocation. To recognize that automatic padding is wanted, MatX uses the output tensor size compared to the input tensor size to determine whether to pad the input with zeros. In this case the output signal (sig_time and filt_time) are shorter than the output tensors (sig_freq and filt_freq), so it will automatically zero-pad the input.\n", "\n", "The above expression can also be combined into a single line:\n", @@ -413,21 +674,7 @@ "conv1d(time_out, sig_time, filt_time, matxConvCorrMode_t::MATX_C_MODE_FULL, 0);\n", "```\n", "\n", - "To match the FFT results we do a full convolution to get all the samples from the filter ramp up and ramp down. However, if we wanted either valid or same mode we could slice the FFT convolution output at the appropriate places to give the same answer. Edit the file [exercises/example3_fft_conv.cu](exercises/example3_fft_conv.cu) and add the missing code where you see TODOs. After running the verification code at the bottom will check for accuracy.\n", - "\n", - "Expected output:\n", - "```sh\n", - "Verification successful\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!./exercises/compile_and_run.sh example3_fft_conv" + "To match the FFT results we do a full convolution to get all the samples from the filter ramp up and ramp down. However, if we wanted either valid or same mode we could slice the FFT convolution output at the appropriate places to give the same answer. Edit the file [exercises/example3_fft_conv.cu](exercises/example3_fft_conv.cu) and add the missing code where you see TODOs. After running the verification code at the bottom will check for accuracy." ] }, { @@ -446,12 +693,15 @@ "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" }, "kernelspec": { - "display_name": "Python 3.6.9 64-bit", - "name": "python3" + "display_name": "C++17", + "language": "C++", + "name": "cling-cpp17" }, "language_info": { - "name": "python", - "version": "" + "codemirror_mode": "c++", + "file_extension": ".c++", + "mimetype": "text/x-c++src", + "name": "c++" } }, "nbformat": 4, diff --git a/docs_input/notebooks/exercises/example3_1dfft.cu b/docs_input/notebooks/exercises/example3_1dfft.cu deleted file mode 100644 index cd5bf70da..000000000 --- a/docs_input/notebooks/exercises/example3_1dfft.cu +++ /dev/null @@ -1,57 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto C = make_tensor>({2, 4}); - - (C = random({2, 4}, NORMAL)).run(); - - printf("Initial C tensor:\n"); - print(C); - - // TODO: Perform an in-place FFT on C across rows - - printf("After FFT:\n"); - print(C); - - // TODO: Perform an in-place IFFT on C across rows. - - printf("After IFFT and normalization:\n"); - print(C); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example3_2dfft.cu b/docs_input/notebooks/exercises/example3_2dfft.cu deleted file mode 100644 index ebe117df4..000000000 --- a/docs_input/notebooks/exercises/example3_2dfft.cu +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto C = make_tensor>({2, 4}); - - (C = random({2, 4}, NORMAL)).run(); - printf("Initial C tensor:\n"); - print(C); - - // TODO: Perform an in-place 2D FFT on C across rows - - printf("After FFT:\n"); - print(C); - - // TODO: Perform an in-place 2D IFFT on C across rows - - printf("After IFFT and normalization:\n"); - print(C); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example3_assignment1.cu b/docs_input/notebooks/exercises/example3_assignment1.cu deleted file mode 100644 index 07f37ef14..000000000 --- a/docs_input/notebooks/exercises/example3_assignment1.cu +++ /dev/null @@ -1,115 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -/** - * MatX training assignment 3. This training goes through tensor operations that - * were learned in the 03_transformations notebook. Uncomment each verification - * block as you go to ensure your solutions are correct. - */ - -int main() { - using complex = cuda::std::complex; - auto A = make_tensor({2, 3}); - auto B = make_tensor({2, 3}); - - cudaExecutor exec{}; - - /**************************************************************************************************** - * Use the random number generator with a seed of 12345 to generate - * normally-distributed numbers in the tensor A. Next, take the FFT across - * columns of A (a 2-element FFT), and store the results in-place back in A. - * An example of random number generation can be found in the second tutorial - * or in the quick start guide here: - * - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/quickstart.html#random-numbers - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/api/random.html - ****************************************************************************************************/ - - /*** End editing ***/ - - // Verify init is correct - B.SetVals({{{0.5927, -0.3677}, {-2.6895, 1.8154}, {-0.0129, 0.9246}}, - {{0.5646, 0.8638}, {1.6400, 0.3494}, {-0.5709, 0.5919}}}); - A.print(); - B.print(); - exec.sync(); - for (int row = 0; row < A.Size(0); row++) { - for (int col = 0; col < A.Size(1); col++) { - if (fabs(A(row, col).real() - B(row, col).real()) > 0.001) { - printf( - "Mismatch in real part of FFT view! actual = %f, expected = %f\n", - A(row, col).real(), B(row, col).real()); - exit(-1); - } - if (fabs(A(row, col).imag() - B(row, col).imag()) > 0.001) { - printf( - "Mismatch in imag part of FFT view! actual = %f, expected = %f\n", - A(row, col).imag(), B(row, col).imag()); - exit(-1); - } - } - } - - printf("FFT verification passed!\n"); - - /**************************************************************************************************** - * Create a 3D tensor of floats using a normal distribution and with shape - * 10x5x15. Reduce the entire tensor down to a single float containing the max - * value. Scale the original tensor by this max value and do another max - * reduction. The final reduction should be 1.0. - * - * Hint: the reduction function is named rmax and takes the output, input, and - * stream as parameters - * https://devtech-compute.gitlab-master-pages.nvidia.com/matx/api/reduce.html - ****************************************************************************************************/ - // Create and initialize 3D tensor - - // Create scalar tensor for reduction - tensor_t redv; - - /*** End editing ***/ - - // Verify init is correct - exec.sync(); - if (fabs(redv() - 1.0) > 0.001) { - printf("Mismatch on final reduction. Expected=1.0, actual = %f\n", redv()); - exit(-1); - } - - printf("Reduction verification passed!\n"); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example3_conv1d.cu b/docs_input/notebooks/exercises/example3_conv1d.cu deleted file mode 100644 index 1a5b83a71..000000000 --- a/docs_input/notebooks/exercises/example3_conv1d.cu +++ /dev/null @@ -1,55 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto C = make_tensor({16}); - auto filt = make_tensor({3}); - auto Co = make_tensor({16 + filt.Lsize() - 1}); - - filt.SetVals({1.0/3, 1.0/3, 1.0/3}); - - (C = random({16}, NORMAL)).run(); - - printf("Initial C tensor:\n"); - print(C); - - // TODO: Perform a 1D direct convolution on C with filter filt - - - printf("After conv1d:\n"); - print(Co); - return 0; -} diff --git a/docs_input/notebooks/exercises/example3_conv2d.cu b/docs_input/notebooks/exercises/example3_conv2d.cu deleted file mode 100644 index d1ac06b3c..000000000 --- a/docs_input/notebooks/exercises/example3_conv2d.cu +++ /dev/null @@ -1,58 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto C = make_tensor({8,8}); - auto filt = make_tensor({3}); - auto Co = make_tensor({16 + filt.Lsize() - 1}); - - auto filt = ones({2, 2}); - auto Co = make_tensor({8 + filt.Size(0) - 1, 8 + filt.Size(1) - 1}); - - (C = randTrandom({8, 8}, NORMAL)).run(); - - printf("Initial C tensor:\n"); - print(C); - - // TODO: Perform a 2D direct convolution on C with filter filt - - - - printf("After conv2d:\n"); - print(Co); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example3_fft_conv.cu b/docs_input/notebooks/exercises/example3_fft_conv.cu deleted file mode 100644 index d922ec820..000000000 --- a/docs_input/notebooks/exercises/example3_fft_conv.cu +++ /dev/null @@ -1,92 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - using complex = cuda::std::complex; - cudaExecutor exec{}; - - index_t signal_size = 16; - index_t filter_size = 3; - index_t filtered_size = signal_size + filter_size - 1; - - // Create time domain buffers - auto sig_time = make_tensor({signal_size}); - auto filt_time = make_tensor({filter_size}); - auto time_out = make_tensor({filtered_size}); - - // Frequency domain buffers - auto sig_freq = make_tensor({filtered_size}); - auto filt_freq = make_tensor({filtered_size}); - - // Fill the time domain signals with data - for (index_t i = 0; i < signal_size; i++) { - sig_time(i) = {-1.0f * (2.0f * static_cast(i % 2) + 1.0f) * - (static_cast(i % 10) / 10.0f) + - 0.1f, - -1.0f * (static_cast(i % 2) == 0.0f) * - (static_cast(i % 10) / 5.0f) - - 0.1f}; - } - for (index_t i = 0; i < filter_size; i++) { - filt_time(i) = {static_cast(i) / static_cast(filter_size), - static_cast(-i) / static_cast(filter_size) + - 0.5f}; - } - - // TODO: Perform FFT convolution - // Perform the FFT in-place on both signal and filter, do an element-wise multiply of the two, then IFFT that output - - - // TODO: Perform a time-domain convolution - - - exec.sync(); - - // Compare signals - for (index_t i = 0; i < filtered_size; i++) { - if ( fabs(time_out(i).real() - sig_freq(i).real()) > 0.001 || - fabs(time_out(i).imag() - sig_freq(i).imag()) > 0.001) { - printf("Verification failed at item %lld. Direct=%f%+.2fj, FFT=%f%+.2fj\n", i, - time_out(i).real(), time_out(i).imag(), sig_freq(i).real(), sig_freq(i).imag()); - return -1; - } - } - - std::cout << "Verification successful" << std::endl; - - return 0; -} diff --git a/docs_input/notebooks/exercises/example3_full_reduce.cu b/docs_input/notebooks/exercises/example3_full_reduce.cu deleted file mode 100644 index 49c81832d..000000000 --- a/docs_input/notebooks/exercises/example3_full_reduce.cu +++ /dev/null @@ -1,58 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto A = make_tensor({4, 5}); - auto MD0 = make_tensor(); - auto AD0 = make_tensor(); - - (A = random({4, 5}, NORMAL)).run(); - - // Initialize max and average to 0 - (MD0 = 0).run(); - (AD0 = 0).run(); - - // TODO: Perform a max and sum reduction of A into MD0 and AD0, respectively. - - - printf("A:\n"); - print(A); - printf("Max: %f\n", MD0()); - printf("Sum: %f\n", AD0()); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example3_gemm.cu b/docs_input/notebooks/exercises/example3_gemm.cu deleted file mode 100644 index 824ec9af2..000000000 --- a/docs_input/notebooks/exercises/example3_gemm.cu +++ /dev/null @@ -1,55 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - auto A = make_tensor({8, 4}); - auto B = make_tensor({4, 8}); - auto C = make_tensor({8, 8}); - - (A = random({8, 4}, NORMAL)).run(); - (B = random({4, 8}, NORMAL)).run(); - - // TODO: Perform a GEMM of C = A*B - - printf("A:\n"); - print(A); - printf("B:\n"); - print(B); - printf("C:\n"); - print(C); - - return 0; -} diff --git a/docs_input/notebooks/exercises/example3_partial_reduce.cu b/docs_input/notebooks/exercises/example3_partial_reduce.cu deleted file mode 100644 index e48e407ba..000000000 --- a/docs_input/notebooks/exercises/example3_partial_reduce.cu +++ /dev/null @@ -1,61 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// BSD 3-Clause License -// -// Copyright (c) 2021, 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: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -///////////////////////////////////////////////////////////////////////////////// - -#include - -using namespace matx; - -int main() { - - auto A = make_tensor({4, 5}); - auto MD0 = make_tensor({4}); - auto AD0 = make_tensor({4}); - - (A = random(shape, NORMAL)).run(); - - // Initialize max and average to 0 - (MD1 = 0).run(); - (AD1 = 0).run(); - - // TODO: Reduce all rows of A by max where each reduction is a separate value in the vector MD1 - - - - printf("A:\n"); - print(A); - printf("Max:\n"); - print(MD1); - printf("Sum:\n"); - print(AD1); - - return 0; -} From 6903ac4b53e13cb70b672c024d0d7d287dfbf40e Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Fri, 24 Jan 2025 08:36:39 +0000 Subject: [PATCH 04/91] adding script for notebook. has hardcoded paths --- docs_input/notebooks/run.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 docs_input/notebooks/run.sh diff --git a/docs_input/notebooks/run.sh b/docs_input/notebooks/run.sh new file mode 100755 index 000000000..6e2d639f0 --- /dev/null +++ b/docs_input/notebooks/run.sh @@ -0,0 +1,19 @@ +#!/bin/bash +USER_ID=$(id -u) +GROUP_ID=$(id -g) +CMDS="/bin/bash" + # -u $USER_ID:$GROU P_ID \ + +docker run -it --rm \ + -p 8888:8888 \ + --gpus all \ + -v /home/scratch.tylera_sw/:/scratch \ + -v /home/scratch.tylera_sw/projects/matx_holo_lab_2025:/notebooks \ + --env="DISPLAY" \ + --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \ + --cap-add CAP_SYS_PTRACE \ + --ipc=host \ + --ulimit memlock=-1 \ + --ulimit stack=67108864 \ + gitlab-master.nvidia.com:5005/devtech-compute/sigx-group/container/cling:latest \ + /bin/bash \ No newline at end of file From 7825f950fac5c66e40c598b6bd108cf5a9a3e7c4 Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Fri, 24 Jan 2025 08:47:34 +0000 Subject: [PATCH 05/91] adding empty notebooks for fusion/profiling --- docs_input/notebooks/05_fusion.ipynb | 25 +++++++++++++++++++++++++ docs_input/notebooks/06_profiling.ipynb | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 docs_input/notebooks/05_fusion.ipynb create mode 100644 docs_input/notebooks/06_profiling.ipynb diff --git a/docs_input/notebooks/05_fusion.ipynb b/docs_input/notebooks/05_fusion.ipynb new file mode 100644 index 000000000..4a15e305d --- /dev/null +++ b/docs_input/notebooks/05_fusion.ipynb @@ -0,0 +1,25 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Fusing Operations in MatX" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## " + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs_input/notebooks/06_profiling.ipynb b/docs_input/notebooks/06_profiling.ipynb new file mode 100644 index 000000000..ff5f93301 --- /dev/null +++ b/docs_input/notebooks/06_profiling.ipynb @@ -0,0 +1,25 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Profiling and Optimizing with MatX" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Automated NVTX Ranges" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From fb8e89a953327d9947306712e610a624cd358991 Mon Sep 17 00:00:00 2001 From: cliffburdick Date: Mon, 27 Jan 2025 14:07:45 -0800 Subject: [PATCH 06/91] Adding timing metrics to CUDA and host executors --- docs_input/basics/profiling.rst | 38 ++++++++++++++++++++++++++++++++ examples/spectrogram.cu | 21 ++++++------------ include/matx/executors/cuda.h | 39 ++++++++++++++++++++++++++++++--- include/matx/executors/host.h | 27 +++++++++++++++++++++++ 4 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 docs_input/basics/profiling.rst diff --git a/docs_input/basics/profiling.rst b/docs_input/basics/profiling.rst new file mode 100644 index 000000000..740565267 --- /dev/null +++ b/docs_input/basics/profiling.rst @@ -0,0 +1,38 @@ +.. _profiling: + +Profiling +######### + +Profiling is a way to measure the performance of a program and to identify bottlenecks in your MatX application. Since +the method for profiling depends on the executor, each executor implements its own profiling mechanism. For example, +the CUDA executor can use events encapsulating the kernels it's profiling. The profiling is done through the executor +object rather than the `run` statement so that multiple `run`s can be profiled together. + +Profiling is done by calling the `start_timer()` method of the executor: + +.. code-block:: cpp + + exec.start_timer(); + +To stop the profiler, `stop_timer()` is called: + +.. code-block:: cpp + + exec.stop_timer(); + +Depending on the executor, `stop_timer()` may need to block for the operation to conplete on an asynchronous executor. + +Once `stop_timer()` returns, the execution time between the timers can be retrieved by calling `get_time_ms()`: + +.. code-block:: cpp + + auto time = exec.get_time_ms(); + +In the above example `time` contains the runtime of everything executed between the `start_timer()` and `stop_timer()` calls. For +a CUDA executor this is the time between the beginning of the first kernel and the end of the last. For a CPU executor this is the CPU +time between the two calls. + +.. note:: + Profiling does not work a multi-threaded host executor currently + +For a full example of profiling, see the `spectrogram` example. \ No newline at end of file diff --git a/examples/spectrogram.cu b/examples/spectrogram.cu index 79b066a07..9d238b0ee 100644 --- a/examples/spectrogram.cu +++ b/examples/spectrogram.cu @@ -60,11 +60,6 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) cudaStream_t stream; cudaStreamCreate(&stream); - - cudaEvent_t start, stop; - cudaEventCreate(&start); - cudaEventCreate(&stop); - cudaExecutor exec{stream}; float fs = 10000; @@ -96,11 +91,11 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) (time = linspace<0>(num_samps, 0.0f, static_cast(N) - 1.0f) / fs) .run(exec); // mod = 500 * np.cos(2*np.pi*0.25*time) - (modulation = 500 * cos(2 * M_PI * 0.25 * time)).run(exec); + (modulation = 500.f * cos(2.f * static_cast(M_PI) * 0.25f * time)).run(exec); // carrier = amp * np.sin(2*np.pi*3e3*time + modulation) - (carrier = amp * sin(2 * M_PI * 3000 * time + modulation)).run(exec); + (carrier = amp * sin(2.f * static_cast(M_PI) * 3000.f * time + modulation)).run(exec); // noise = 0.01 * fs / 2 * np.random.randn(time.shape) - (noise = sqrt(0.01 * fs / 2) * random({N}, NORMAL)).run(exec); + (noise = sqrt(0.01f * fs / 2.f) * random({N}, NORMAL)).run(exec); // noise *= np.exp(-time/5) (noise = noise * exp(-1.0f * time / 5.0f)).run(exec); // x = carrier + noise @@ -108,11 +103,11 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) for (uint32_t i = 0; i < num_iterations; i++) { if (i == 2) { // Start timer on third loop to allow generation of plot - cudaEventRecord(start, stream); + exec.start_timer(); } // DFT Sample Frequencies (rfftfreq) - (freqs = (1.0 / (static_cast(nfft) * 1 / fs)) * + (freqs = (1.0f / (static_cast(nfft) * 1.f / fs)) * linspace<0>(half_win, 0.0f, static_cast(nfft) / 2.0f)) .run(exec); @@ -143,15 +138,13 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) } - cudaEventRecord(stop, stream); + exec.stop_timer(); exec.sync(); - cudaEventElapsedTime(&time_ms, start, stop); + time_ms = exec.get_time_ms(); printf("Spectrogram Time Without Graphs = %.2fus per iteration\n", time_ms * 1e3 / num_iterations); - cudaEventDestroy(start); - cudaEventDestroy(stop); cudaStreamDestroy(stream); MATX_CUDA_CHECK_LAST_ERROR(); diff --git a/include/matx/executors/cuda.h b/include/matx/executors/cuda.h index fb583ce19..7843ebe13 100644 --- a/include/matx/executors/cuda.h +++ b/include/matx/executors/cuda.h @@ -54,14 +54,24 @@ namespace matx * * @param stream CUDA stream */ - cudaExecutor(cudaStream_t stream) : stream_(stream) {} - cudaExecutor(int stream) : stream_(reinterpret_cast(stream)) {} + cudaExecutor(cudaStream_t stream) : stream_(stream) { + MATX_CUDA_CHECK(cudaEventCreate(&start_)); + MATX_CUDA_CHECK(cudaEventCreate(&stop_)); + } + + cudaExecutor(int stream) : stream_(reinterpret_cast(stream)) { + MATX_CUDA_CHECK(cudaEventCreate(&start_)); + MATX_CUDA_CHECK(cudaEventCreate(&stop_)); + } /** * @brief Construct a new cudaExecutor object using the default stream * */ - cudaExecutor() : stream_(0) {} + cudaExecutor() : stream_(0) { + MATX_CUDA_CHECK(cudaEventCreate(&start_)); + MATX_CUDA_CHECK(cudaEventCreate(&stop_)); + } /** * @brief Returns stream associated with executor @@ -73,6 +83,27 @@ namespace matx * */ void sync() { cudaStreamSynchronize(stream_); } + + /** + * @brief Start a timer for profiling workload + */ + void start_timer() { cudaEventRecord(start_, stream_); } + + /** + * @brief Stop a timer for profiling workload + */ + void stop_timer() { cudaEventRecord(stop_, stream_); } + + /** + * @brief Get the time in milliseconds between start_timer and stop_timer. + * This will block until the event is synchronized + */ + float get_time_ms() { + float time; + cudaEventSynchronize(stop_); + cudaEventElapsedTime(&time, start_, stop_); + return time; + } /** * Execute an operator on a device @@ -139,6 +170,8 @@ namespace matx private: cudaStream_t stream_; + cudaEvent_t start_; + cudaEvent_t stop_; }; }; diff --git a/include/matx/executors/host.h b/include/matx/executors/host.h index cb65a7842..d1a40aefc 100644 --- a/include/matx/executors/host.h +++ b/include/matx/executors/host.h @@ -112,6 +112,31 @@ class HostExecutor { */ void sync() {} + /** + * @brief Start a timer for profiling workload + */ + void start_timer() { + MATX_STATIC_ASSERT_STR(MODE == ThreadsMode::SINGLE, matxNotSupported, "Timer not supported in multi-threaded mode"); + start_ = std::chrono::high_resolution_clock::now(); + } + + /** + * @brief Stop a timer for profiling workload + */ + void stop_timer() { + MATX_STATIC_ASSERT_STR(MODE == ThreadsMode::SINGLE, matxNotSupported, "Timer not supported in multi-threaded mode"); + stop_ = std::chrono::high_resolution_clock::now(); + } + + /** + * @brief Get the time in milliseconds between start_timer and stop_timer. + * This will block until the event is synchronized + */ + float get_time_ms() { + auto duration = std::chrono::duration_cast(stop_ - start_); + return static_cast(static_cast(duration.count()) / 1e3); + } + /** * @brief Execute an operator * @@ -151,6 +176,8 @@ class HostExecutor { private: HostExecParams params_; + std::chrono::time_point start_; + std::chrono::time_point stop_; }; using SingleThreadedHostExecutor = HostExecutor; From c47e4b390da763976fda3a1111e02af7452881f5 Mon Sep 17 00:00:00 2001 From: cliffburdick Date: Wed, 29 Jan 2025 12:11:10 -0800 Subject: [PATCH 07/91] Fixed docs --- docs_input/basics/profiling.rst | 2 +- docs_input/build.rst | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs_input/basics/profiling.rst b/docs_input/basics/profiling.rst index 740565267..7fb39a74d 100644 --- a/docs_input/basics/profiling.rst +++ b/docs_input/basics/profiling.rst @@ -6,7 +6,7 @@ Profiling Profiling is a way to measure the performance of a program and to identify bottlenecks in your MatX application. Since the method for profiling depends on the executor, each executor implements its own profiling mechanism. For example, the CUDA executor can use events encapsulating the kernels it's profiling. The profiling is done through the executor -object rather than the `run` statement so that multiple `run`s can be profiled together. +object rather than the `run` statement so that multiple `run`\s can be profiled together. Profiling is done by calling the `start_timer()` method of the executor: diff --git a/docs_input/build.rst b/docs_input/build.rst index aad031937..19773a416 100644 --- a/docs_input/build.rst +++ b/docs_input/build.rst @@ -11,10 +11,10 @@ Optional features of MatX that require downloading separate libraries use additi be explicit about their requirements. The MatX CMake build configuration is intented to help download any libraries for both the required and optional features. -The CPM_ build system is used to help with package management and version control. By default, CPM will fetch other packages +The CPM build system is used to help with package management and version control. By default, CPM will fetch other packages from the internet. Alternatively, the option ``CPM_USE_LOCAL_PACKAGES`` can be used to point to local downloads in an air-gapped or offline environment. Choosing local versions of packages uses the typical ``find_packages`` CMake search methods. Please see -the CPM_ documentation or the documentation for each package for more information. +the CPM documentation or the documentation for each package for more information. System Requirements @@ -27,8 +27,7 @@ for supported host compilers. Other requirements for optional components are lis Required Third-party Dependencies --------------------------------- -- `CPM `_ (* Included in the project source and does not require a separate download) -- `CCCL `_ 2.7.0+ +- `CCCL `_ 2.7.0+ commit cbc6b9b or higher Optional Third-party Dependencies From 82d584639a371ad24f23accd2df8e782370ca4ef Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Wed, 29 Jan 2025 20:23:50 +0000 Subject: [PATCH 08/91] details added to notebook 1 --- .../notebooks/gtc_lab/01_lab_intro.ipynb | 690 ++++++++++++++++++ .../notebooks/gtc_lab/02_lab_fusion.ipynb | 266 +++++++ 2 files changed, 956 insertions(+) create mode 100644 docs_input/notebooks/gtc_lab/01_lab_intro.ipynb create mode 100644 docs_input/notebooks/gtc_lab/02_lab_fusion.ipynb diff --git a/docs_input/notebooks/gtc_lab/01_lab_intro.ipynb b/docs_input/notebooks/gtc_lab/01_lab_intro.ipynb new file mode 100644 index 000000000..be28b7577 --- /dev/null +++ b/docs_input/notebooks/gtc_lab/01_lab_intro.ipynb @@ -0,0 +1,690 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# MatX Introduction\n", + "intro to class and goals " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [ + "//todo this should be moved to a hidden init block that runs automatically when the notebook starts\n", + "#pragma cling add_library_path(\"/usr/local/cuda/lib64\")\n", + "#pragma cling add_library_path(\"/opt/xeus/cling/lib\")\n", + "//#pragma cling add_library_path(\"/usr/Lib/gcc/x86_64-Linux-gnu/11/\")\n", + "#pragma cling add_library_path(\"/usr/lib/x86_64-linux-gnu/openblas64-openmp/\")\n", + "#pragma cling add_include_path(\"/usr/local/cuda/include\")\n", + "#pragma cling add_include_path(\"/usr/include/x86_64-linux-gnu/openblas64-openmp\")\n", + "#pragma cling add_include_path(\"/opt/xeus/cling/tools/Jupyter/kernel/MatX/include\")\n", + "#pragma cling add_include_path(\"/opt/xeus/cling/tools/Jupyter/kernel/MatX/build/_deps/cccl-src/libcudacxx/include\")\n", + "//#pragma cling load(\"libgomp\")\n", + "#pragma cling load(\"libopenblas64\")\n", + "#pragma cling load(\"libcuda\")\n", + "#pragma cling load(\"libcudart\")\n", + "#pragma cling load(\"libcurand\")\n", + "#pragma cling load(\"libcublas\")\n", + "#pragma cling load(\"libcublasLt\")\n", + "\n", + "#include \n", + "#include \n", + "\n", + "#define MATX_EN_OPENBLAS\n", + "#define MATX_EN_OPENBLAS_LAPACK\n", + "#define MATX_OPENBLAS_64BITINT\n", + "\n", + "#include \"matx.h\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tensor Creation and Memory Backing\n", + "\n", + "Tensors are the base class of memory backed data storage in MatX. The Tensor class is highly flexible with many options for memory backing, residency, and ownership, but has defaults that makes it easy to use out-of-the box. A set of utility `make_tensor` functions are provided out of the box to help streamline and simplify tensor creation; this is the suggested use pattern for beginners and experts alike. \n", + "\n", + "`make_tensor` takes one template parameter indicating the type of the tensor, and zero or more function parameters. At a minimum, the sizes of the tensor are specified in curly braces, or in the case of a 0-D tensor, no size list is specified. For a complete guide on creating tensors in different ways, please visit: https://nvidia.github.io/MatX/creation.html.\n", + "\n", + "**NOTE** Unlike MATLAB, MatX follows the C-style for indexing, meaning we assume row-major formats rather than column-major, and 0-based indexing rather than 1-based. \n", + "\n", + "In the following cell we demonstrate creating tensors of 0D (scalar), 1D, and 2D data. Tensors can be scaled to any arbitrary dimension." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "// declare a 0D tensor (Scalar)\n", + "auto t0 = matx::make_tensor({});\n", + "\n", + "// declare a 1D tensor of length 4\n", + "auto t1 = matx::make_tensor({4});\n", + "\n", + "// declare a 2D tensor of size with 4 rows and 5 columns\n", + "auto t2 = matx::make_tensor({4,5});\n", + "\n", + "// declare tensor with user provided memory (maybe?)\n", + "\n", + "// declare tensor with shape of tensor t2\n", + "auto t2_b = matx::make_tensor(t2.Shape());" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Printing & Assigning\n", + "MatX also provides several utilities for initializing and viewing its data.\n", + "\n", + "Values can be initialized using a nested initializer list inside of the `SetVals` member function, specifying the values of the matrix. The initializer list is a single-nested list to match a 2D tensor shape, but this can be extended up to 4D tensors. `operator()` is also available to set and get individual values of a tensor as an alternative.\n", + "\n", + "`print` is a utility function to print a tensor or operator's contents to stdout. Printing can be used with any type of operator, including ones that have no memory backing them (see upcoming generators section). With no arguments `print` will print the entire contents of the tensor. The size of the printing can also be limited by passing a limit to each dimension. For example, `print(3,2)` would print the first 2 columns and 3 rows of the 2D tensor. `operator()` can also be used to retun a single value, and combine with traditional pritining techniques" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "// setVals in tensor\n", + "t2.SetVals({ \n", + " {1, 2, 3, 4},\n", + " {5, 6, 7, 8},\n", + " {9, 10, 11, 12},\n", + " {13, 14, 15, 16},\n", + " {17, 18, 19, 20}\n", + " });\n", + "\n", + "// print a tensor\n", + "matx::print(t2);\n", + "\n", + "// print elements of tensor\n", + "std::cout << t2(0,0) << std::endl;\n", + "\n", + "\n", + "t2(0,0) = 42;\n", + "t2(3,2) = 117;\n", + "\n", + "matx::print(t2);\n", + "\n", + "std::cout << \"My updates value for (3,2): \" << t2(3,2) << std::endl;" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise: First Tensor\n", + "\n", + "Try defining a new integer tensor of size `{3, 5}` and initilaize its values in increasing values from 0 to 15.\n", + "\n", + "print your tensor to ensure the values are as expected.\n", + "\n", + "update the 4th element `{1,1}` to `101`.\n", + "\n", + "print the 4th element to ensure your update was valid.\n", + "\n", + "try other tensor manipulations to test the API!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "// declare a tensor\n", + "// auto myTensor = matx::make_tensor({3,5});\n", + "\n", + "\n", + "// setVals in myTensor\n", + "// myTensor.SetVals({ \n", + "// {1, 2, 3},\n", + "// {4, 5, 6},\n", + "// {7, 8, 9},\n", + "// {10, 11, 12},\n", + "// {13, 14, 15}\n", + "// });\n", + "\n", + "\n", + "// print your new tensor\n", + "// matx::print(myTensor);\n", + "\n", + "\n", + "// update the value at {1,1} to 101\n", + "// myTensor(1,1) = 101;" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tensors Views\n", + "MatX provides a powerful set of functions that enable arbitrary views into existing tensors, without incuring additional memory storage or processing cost to reorganize the data. These views provide \"zero copy\" accessors to a tensor that can be used in MatX logic as if it were a real memory-backed tensor.\n", + "\n", + "MatX has feature parity to most operations expected in cupy / matlab style environments; a full table of the translation of a given operation to it's MatX equivilant can be found in our full documentation [here](https://nvidia.github.io/MatX/basics/matlabpython.html#conversion-table)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Permute\n", + "`permute` returns a view of the data with the dimensions swapped to match the order of the initializer list argument. In the exmaple below we swap our two dimenions, so it's equivalent to a matrix transpose. However, `permute` can be used on higher-order tensors with the dimensions swapped in any order.\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "//permute\n", + "print(t2);\n", + "auto t2p = permute(t2, {1,0});\n", + "print(t2p);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Slice\n", + "`slice` provides a view of a subset of data in a tensor, allowing that subset to be used and manipulated as a single entity. The `slice` utility function takes the input operator and two initilization lists to define the range of the provided input operator the slice will container. the ranges are defined wit the start index and end (exclusive) index. \n", + "\n", + "in the example below, `t2s` will corespond to the elemnts [`1:2),1:2`] of the larger t2 tensor\n", + "\n", + "![2D Slice](../img/dli-slice.png)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "//slice example 1: same Rank\n", + "auto t2s = matx::slice(t2, {1,1}, {3, 3});\n", + "matx::print(t2s);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Similarly, `slice` can be used with a template parameter to define an operator of a different rank (dimensionality) than the input tensor. In the second example, we demonstrate slicing the 0th column from the t2 tensor as shown in the image below.\n", + "\n", + "![Column Slice](../img/dli-slice_col.png)\n", + "\n", + "MatX also includes several helper defines to make tensor bound definitions easier. To include all values from the beginning on, a special sentinel of `matxEnd` can be used. Similarly, `matxDropDim` is used to indicate this dimension is the one being sliced (i.e. removed)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "//slice example 2: reduce rank requires template parameter\n", + "auto t1Col = matx::slice<1>(t2, {0, 1}, {matx::matxEnd, matx::matxDropDim});\n", + "matx::print(t1Col);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Clone\n", + "`clone` provides a utlity funciton to expand a smaller rank tensor to a larger rank by replicating the original data. \n", + "\n", + "for example, a 1D Tensor can be cloned to create a 2D tensor.\n", + "\n", + "In the clone example below, we will take the t1Col from our previous operation, and clone it to build a 2D [5,4] tensor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "//clone\n", + "auto t2c_cols = matx::clone<2>(t1Col, {5, matx::matxKeepDim});\n", + "matx::print(t2c_cols);\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### View Data Backing\n", + "We established earlier that views are not new data, but variable accessors into the original memory-backed tensor. this is a powerful tool when operating on the core data, as we can desctruct a large data block into the set of data we want to operate on. \n", + "\n", + "**It is very important to remember that modifying the data in a view modified the original tensor**\n", + "\n", + "This means any change to the original tensor, through the view or in any other fashion, will reflect in all views of that tensor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "// modify the original tensor\n", + "t2(1,0) = 10;\n", + "// print our views to show the updated values\n", + "matx::print(t2);\n", + "matx::print(t1Col);\n", + "matx::print(t2c_cols);\n", + "\n", + "\n", + "//modify the tensor through a view\n", + "t1Col(1) = 203;\n", + "\n", + "// print our views to show the updated values\n", + "matx::print(t2);\n", + "matx::print(t1Col);\n", + "matx::print(t2c_cols);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise Views\n", + "Lets demonstrate your new skills in creating views of a tensor. using the pre-defined `baseTensor2D` please create the following views:\n", + "\n", + "- the complete first row of the `baseTensor`\n", + "- a 2D square of 4 elements, comprized of the first 2 rows and 2 columns of data\n", + "- modify the {1,1} element of baseTensor2D through the view corresponding to that data to assign it the value of 87.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "auto baseTensor2D = matx::make_tensor({3,5});\n", + "\n", + "baseTensor2D.SetVals({ \n", + " {1, 2, 3},\n", + " {4, 5, 6},\n", + " {7, 8, 9},\n", + " {10, 11, 12},\n", + " {13, 14, 15}\n", + " });\n", + "\n", + "\n", + "// slice the first row of baseTensor\n", + "// auto baseTensor_row0 = matx::slice<1>(baseTensor2D, {0,0}, {matx::matxDropDim, matx::matxEnd});\n", + "matx::print(base_tensor_row0);\n", + "\n", + "\n", + "\n", + "//slice the 2D sqaure of the first 4 elements\n", + "// auto baseSquare = matx::slice(baseTensor2D, {0,0}, {3,3});\n", + "matx::print(baseSquare);\n", + "\n", + "// baseSquare(1,1) = 87;\n", + "matx::print(baseTensor2D);" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "source": [ + "## MatX Operations\n", + "Operators in MatX are an abstract type that defines an operation that returns a value at a given index. This concept is intentionally vague, which makes it extremely powerful for representing different concepts. As an example, both a tensor type and the addition operator `+` are MatX operators. In the case of the tensor, it returns the value in memory at that location, but for the addition operator, it returns the sum of values at a given location from both the left and right hand sides.\n", + "\n", + "Most operators come in unary types for operating on a single input or a binary type for operating on two inputs. For example, the expression `A + B` uses the binary `AddOp` operator to lazily add two tensors or other operators together. MatX supports most of the standard unary operators a user would expect, and work with both MatX tensor/operator types, as well as scalar values that are compatible with the base type of the operator.\n", + "\n", + "below we'll demonstrate both scalar and matrix support for the basic unary operators (`+`, `-`, `x`, `/`)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "auto A = matx::make_tensor({2, 3});\n", + "auto B = matx::make_tensor({2, 3});\n", + "auto C = matx::make_tensor({2, 3});\n", + "auto D = matx::make_tensor({2, 2});\n", + "\n", + "A.SetVals({ {1, 2, 3},\n", + " {4, 5, 6}\n", + " });\n", + "(B = A).run(); \n", + "\n", + "matx::print(A); \n", + "\n", + "// add\n", + "matx::print(A + 5); // scalar \n", + "matx::print(A + B); // matrix\n", + "\n", + "// subtraction\n", + "matx::print(A - 5);\n", + "matx::print(A - B);\n", + "\n", + "// multiplication (dot)\n", + "matx::print(A * 5);\n", + "matx::print(A * B);\n", + "\n", + "// division \n", + "matx::print(A / 5);\n", + "matx::print(A / B);\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise: Operators\n", + "Please use the provided A and B tensors to complete the following set of operations:\n", + "\n", + "- Multiply `A` by it's scalar weight factor `aScale`\n", + "- subtract `bOffset` from the matrix `B`\n", + "- Add the `A` and `B` Tensors\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "int aScale = 5;\n", + "int bOffset = 2;\n", + "\n", + "// scale A by aScale\n", + "// print( A * ascale);\n", + "\n", + "// subtract B by bOffset\n", + "//print( B - bOffset);\n", + "\n", + "// add A and B Tensors\n", + "// print(A + B);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## MatX Transforms\n", + "Transforms are operators that take one or more inputs and call a backend library or kernel. Transforms usually changes one or more properties of the input, but that is not always the case. An fft may change the input type or shape, but a sort transform does not. Depending on the context used, a transform may asynchronously allocate temporary memory if the expression requires it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Matrix Multiplication\n", + "The `matmul` executor performs the matrix-matrix multiply of $$C = {\\alpha}A * B + {\\beta}C$$ where `A` is of dimensions `MxK`, `B` is `KxN`, and `C` is `MxN`. We first populate the `A` and `B` matrices with random values before the multiply as we did in the example above, then the GEMM is performed. Since the random number generator allocates memory sufficient to randomize the entire tensor, we create a random number generator large enough to generate values for both A or B. This allows us to create a single random number generator, but pull different random values for A and B by simply calling `run` twice. As mentioned above, any rank above 2 is consiered a batching dimension.\n", + "\n", + "We use rectangular matrices for `A` and `B`, while `C` will be a square matrix due to the outer dimensions of `A` and `B` matching. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "// matrix multiplication\n", + "(C = matx::matmul(A,matx::transpose(B))).run();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### FFTs\n", + "MatX provides an interface to do both 1D Fast Fourier Transforms (FFTs) and 2D FFTs. Any tensor above rank 1 will be batched in a 1D FFT, and any tensor above rank 2 will be batched in a 2D FFT. FFTs may either be done in-place or out-of-place by using the same or different variables for the output and inputs. Since the tensors are strongly-typed, the type of FFT (C2C, R2C, etc) is inferred by the tensor type at compile time. Similarly, the input and output size of the executor is deduced by the type of transform, and the input/output tensors must match those sizes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "// FFT\n", + "auto D = matx::make_tensor({2, 4});\n", + "\n", + "(D = matx::random(D.Shape(), matx::NORMAL)).run(); // explained later\n", + "matx::print(D);\n", + "\n", + "(D = fft(D)).run();\n", + "matx::print(D);\n", + "\n", + "(D = matx::ifft(D)).run(); \n", + "matx::print(D);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reductions\n", + "Reductions are one of the most common operations perfomed on the GPU, which means they've been heavily researched and optimized for highly-parallel processors. Modern NVIDIA GPUs have special instructions for performing reductions to give even larger speedups over naive implementations. All of these details are hidden from the user and MatX automatically chooses the optimized path based on the hardware capabilities. \n", + "\n", + "MatX provides a set of optimized primitives to perform reductions on tensors for many common types. Reductions are supported across individual dimensions or on entire tensors, depending on the size of the output tensor. Currently supported reduction functions are `sum`, `min`, `max`,` mean`, `any`, and `all`\n", + "\n", + "below is a simple example for calcluate a full reduction of the max and sum of our A data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "auto MD0 = matx::make_tensor({});\n", + "auto AD0 = matx::make_tensor({});\n", + "\n", + "(A = matx::random(A.Shape(), matx::NORMAL)).run(); \n", + "\n", + "\n", + "// max of data\n", + "(MD0 = max(A)).run();\n", + "// min of data\n", + "(AD0 = sum(A)).run();\n", + "\n", + "printf(\"A:\\n\");\n", + "matx::print(A);\n", + "printf(\"Max: %f\\n\", MD0());\n", + "printf(\"Sum: %f\\n\", AD0()); " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "source": [ + "### Additional Transforms\n", + "MatX Supports a wide range of transforms, including specializations for specific domains of signal processing. Please review the [MatX documentation](https://nvidia.github.io/MatX/api/index.html) for an exhaustive list of supported operations, but we'll review a few of the most common here." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "// Do we want to show any additional reducitons here? Talk about batching?\n", + "// convolution\n", + "// batched transforms" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## MatX Generators\n", + "Generators are a type of operator that can generate values without another tensor or operator as input. For example, windowing functions, such as a Hamming window, can generate values by only taking a length as input. Generators are efficient since they require no memory.\n", + "\n", + "Common generators include random number generation, filters, or identity matricies. Below is an example of each:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "auto H = matx::make_tensor({10});\n", + "\n", + "// random\n", + "(A = 0).run();\n", + "(A = matx::random(A.Size(), matx::NORMAL)).run();\n", + "matx::print(A);\n", + "\n", + "// eye\n", + "(A = matx::eye(A.Size())).run();\n", + "matx::print(A);\n", + "\n", + "// hamming\n", + "(H = matx::hamming<0>(H.Shape())).run();\n", + "matx::print(H);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise: Transforms and generators:\n", + "\n", + "For this example we will generate random data to verify the distribution of our generator functions. Please implement the following:\n", + "\n", + "- generate 10 1D data arrays of 1000 elements\n", + "- perform a 1D FFT on the entire data set\n", + "- find the max bin of each fft'd data set" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "//input data storage\n", + "auto input = matx::make_tensor({10,1000});\n", + "auto maxVal = matx::Make_tensor({10});\n", + "auto maxIdx = matx::Make_tensor({10});\n", + "\n", + "// generate random data\n", + "// (input = matx::random({input_size});\n", + "auto S = matx::make_tensor({input_size});\n", + "auto V = matx::make_tensor({input_size});\n", + "auto r = matx::make_tensor({input_size});\n", + "auto T = matx::make_tensor({input_size});\n", + "auto output = matx::make_tensor({input_size}); \n", + "auto referenceOutput = matx::make_tensor({input_size}); \n", + "\n", + "// Individually Evaluated Reference\n", + "(referenceOutput = S * matx::normcdf((matx::log(S / K) + (r + 0.5 * V * V) * T) / V * matx::sqrt(T)) - K * matx::exp(-1 * r * T) * matx::normcdf((matx::log(S / K) + (r + 0.5 * V * V) * T) / V * sqrt(T) - V * sqrt(T);)).run(exec);\n", + "print(referenceOutput);\n", + "\n", + "// well organized version\n", + "// auto VsqrtT = V * sqrt(T);\n", + "// auto d1 = (log(S / K) + (r + 0.5 * V * V) * T) / VsqrtT ;\n", + "// auto d2 = d1 - VsqrtT;\n", + "// auto cdf_d1 = normcdf(d1);\n", + "// auto cdf_d2 = normcdf(d2);\n", + "// auto expRT = exp(-1 * r * T); \n", + "\n", + "// (output = S * cdf_d1 - K * expRT * cdf_d2).run(exec);\n", + "\n", + "\n" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From c695d5a76c24c0cb1044eb41294e77b0f85f5aec Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Wed, 29 Jan 2025 22:06:43 +0000 Subject: [PATCH 09/91] adding incomplete books --- .../notebooks/gtc_lab/03_lab_radar.ipynb | 86 +++++++++++++++++++ .../notebooks/gtc_lab/04_lab_profiling.ipynb | 80 +++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 docs_input/notebooks/gtc_lab/03_lab_radar.ipynb create mode 100644 docs_input/notebooks/gtc_lab/04_lab_profiling.ipynb diff --git a/docs_input/notebooks/gtc_lab/03_lab_radar.ipynb b/docs_input/notebooks/gtc_lab/03_lab_radar.ipynb new file mode 100644 index 000000000..c60caef25 --- /dev/null +++ b/docs_input/notebooks/gtc_lab/03_lab_radar.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# MatX Radar Tutorial\n", + "This notebooks demonstrates MatX's ability to quickly prototype and implement a real-world workflow, using a radar pipeline as a representative taks. In this notebook we'll combine all of our learned skillsets in MatX to quickly implement a complex radar operation in a few simple lines." + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Radar Example Pipeline\n", + "\n", + "\n", + "### Pulse Compression Theory\n", + "Pulse compression is a signal processing technique commonly used by radar, sonar and echography to either increase the range resolution when pulse length is constrained or increase the signal to noise ratio when the peak power and the bandwidth (or equivalently range resolution) of the transmitted signal are constrained. This is achieved by modulating the transmitted pulse and then correlating the received signal with the transmitted pulse. \n", + "\n", + "![image.png](attachment:image.png)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implementing Pulse Compression \n", + "### Set of Operations to Perform" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "// organize the incoming data and waveform\n", + "auto waveformPart = slice(waveformView, {0}, {waveformLength});\n", + "auto waveformT = waveformView.template Clone<3>({numChannels, numPulses, matxKeepDim});\n", + "auto waveformFull = slice(waveformView, {0}, {numSamplesRnd});\n", + "\n", + "auto x = inputView;\n", + "\n", + "// create waveform expression for this dwell\n", + "(waveformPart = waveformPart * hamming<0>({waveformLength})).run(exec);\n", + "\n", + "// compute L2 norm\n", + "(norms = sum(abs2(waveformPart))).run(exec);\n", + "(norms = sqrt(norms)).run(exec);\n", + "\n", + "(waveformPart = waveformPart / norms).run(exec);\n", + "(waveformFull = fft(waveformPart, numSamplesRnd)).run(exec);\n", + "(waveformFull = conj(waveformFull)).run(exec);\n", + "\n", + "//FFT based convolution\n", + "(x = fft(x)).run(exec);\n", + "(x = x * waveformT).run(exec);\n", + "(x = ifft(x)).run(exec);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimization of Pulse Compression" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs_input/notebooks/gtc_lab/04_lab_profiling.ipynb b/docs_input/notebooks/gtc_lab/04_lab_profiling.ipynb new file mode 100644 index 000000000..69ab04700 --- /dev/null +++ b/docs_input/notebooks/gtc_lab/04_lab_profiling.ipynb @@ -0,0 +1,80 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Profiling Notebook\n", + "\n", + "## Profiling in MatX\n", + "\n", + "### Why we profile\n", + "### When to profile " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## NVIDIA Profiling Tools\n", + "\n", + "### Nsight Systems GUI\n", + "### Nsight Systems CLI" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## MatX Profiling tools\n", + "\n", + "### Automatic Ranges\n", + "\n", + "### User Defined Ranges" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "// example of how to define your own ranges both scoped and manual " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Profile Level \n", + "\n", + "### Compile Time Control" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Profiling Radar Application\n", + "\n", + "### Standalone PC Ops\n", + "\n", + "### Fused PC Ops\n", + "\n", + "### GPU Ops\n" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 9fa6c817f75bcff9451a1d0426d44e1436ef3dc4 Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Wed, 29 Jan 2025 18:49:24 -0700 Subject: [PATCH 10/91] update profiling lab with content explaining API --- .../notebooks/gtc_lab/04_lab_profiling.ipynb | 134 +++++++++++++++--- 1 file changed, 117 insertions(+), 17 deletions(-) diff --git a/docs_input/notebooks/gtc_lab/04_lab_profiling.ipynb b/docs_input/notebooks/gtc_lab/04_lab_profiling.ipynb index 69ab04700..793fb486b 100644 --- a/docs_input/notebooks/gtc_lab/04_lab_profiling.ipynb +++ b/docs_input/notebooks/gtc_lab/04_lab_profiling.ipynb @@ -4,33 +4,88 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Profiling Notebook\n", + "# Profiling in MatX\n", + "Improving performance is at the heart of MatX's value, so it must facilitate any easy to implement and powerful capability for benchmarking and analysing code both at deployment and during development.\n", "\n", - "## Profiling in MatX\n", - "\n", - "### Why we profile\n", - "### When to profile " + "The NVIDIA software ecosystem provides a powerful profiling suite of tools through [Nsight Systems]() and [Nsight Compute]() that allows developers to gain great insight into the performance of their code and utilization of their hardware. MatX leverages this powerful ecosystem through the [NVTX toolkit]() which allows developers to annote their code for use with the Nsight suite of tools. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## NVIDIA Profiling Tools\n", + "## MatX Profiling tools\n", + "MatX provides an NVTX API to enable native compile-in profiling capabilities. The MatX NVTX API enable a user to \n", + "easily profile all MatX calls using built-in NVTX ranges, while also providing a convenient API for the user to insert \n", + "custom ranges in their own code. This API provides many convenience features such as:\n", + "\n", + "- A convenient compile-in/compile-out MACRO based API \n", + "- verbosity levels allowing varying levels of profiling detail\n", + "- Built-in color rotation\n", + "- Automatic scope management and range naming \n", + "- Overloaded API for manual range specification\n", + "\n", + "MatX Implements it's NVTX API as a set of macros, which allows users to easily compile NVTX functionality into, or out of your code. This completely removes any runtime penality that may be caused by NVTX in the most latency sensitive deployments.\n", "\n", - "### Nsight Systems GUI\n", - "### Nsight Systems CLI" + "To enable the NVTX Profiling API, simply compile with the ``MATX_NVTX_FLAGS=ON`` enabled in the cmake command." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## MatX Profiling tools\n", + "### User Defined Ranges\n", + "User defined NVTX ranges require the user to provide a name and unique ID for each range. The name will appear in the NVTX range of your nsight profiles, while the unique ID is only used interally to track your ranges during deletion. Because of this, the unique ID **must** be unique for any ranges that overlap, otherwise you may delete the incorrect range during tear-down.\n", + "\n", + "Below is an example of a user-defined NVTX range:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "using dtype = double;\n", + "index_t input_size = 10;\n", + "// index_t inputIsze = 10000000; // increase size to measure performance\n", + "\n", + "//declare input data\n", + "auto K = matx::make_tensor({input_size});\n", + "auto S = matx::make_tensor({input_size});\n", + "auto V = matx::make_tensor({input_size});\n", + "auto r = matx::make_tensor({input_size});\n", + "auto T = matx::make_tensor({input_size});\n", + "auto output = matx::make_tensor({input_size}); \n", + "auto referenceOutput = matx::make_tensor({input_size}); \n", + "\n", + "MATX_NVTX_START_RANGE(\"Black-Scholes Op Creation\", 0)\n", + "// well organized version\n", + "auto VsqrtT = V * sqrt(T);\n", + "auto d1 = (log(S / K) + (r + 0.5 * V * V) * T) / VsqrtT ;\n", + "auto d2 = d1 - VsqrtT;\n", + "auto cdf_d1 = normcdf(d1);\n", + "auto cdf_d2 = normcdf(d2);\n", + "auto expRT = exp(-1 * r * T); \n", + "MATX_NVTX_END_RANGE(0)\n", "\n", + "MATX_NVTX_START_RANGE(\"Black-Scholes Execution\", 1)\n", + "(output = S * cdf_d1 - K * expRT * cdf_d2).run(exec);\n", + "MATX_NVTX_END_RANGE(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "### Automatic Ranges\n", + "Alternative versions of the timing macros are provided to auomate handling the NatX NVTX ranges. The `MATX_NVTX_START_RANGE` has an overload which allows the its use without providing a unique ID. Instead the macro returns an ID, which can be stored in an int variable and later passed to the end range call. when NVTX ranges are compiled out, the Macros simply return 0, and no action is taken on the end call.\n", "\n", - "### User Defined Ranges" + "Below is an example using the automatic enumeration feature:" ] }, { @@ -43,30 +98,75 @@ }, "outputs": [], "source": [ - "// example of how to define your own ranges both scoped and manual " + "int bc_range = MATX_NVTX_START_RANGE(\"Black-Scholes Execution\");\n", + "(output = S * cdf_d1 - K * expRT * cdf_d2).run(exec);\n", + "MATX_NVTX_END_RANGE(bc_range);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ + "### Scope Based Ranges\n", + "A final version of the API, `MATX_NVTX_START` is provided that matches the life of the NVTX range to the life of the scope in which it is defined. This automatically enumates a unique ID, and does not need to be explicitly destroyed by the user. \n", "\n", - "### Profile Level \n", + "Similarly it will also inherit the name of the functions it is called from, and do not require a name. This is especially useful for automating ranges for entire functions.\n", "\n", - "### Compile Time Control" + "An example of this API is as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "cpp" + } + }, + "outputs": [], + "source": [ + "void myFunction\n", + "{\n", + " MATX_NVTX_START(\"\");\n", + " \n", + " (output = S * cdf_d1 - K * expRT * cdf_d2).run(exec);\n", + "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Profiling Radar Application\n", "\n", - "### Standalone PC Ops\n", + "### Profile Level \n", + "The MatX NVTX API supports logging levels, allowing you to fine-tune the levels of NVTX ranges that are captured at a given time. the logging level is checked at runtime, so can be dynamically changed throughout program execution.\n", + "A utility macro `MATX_NVTX_SET_LOG_LEVEL(LOG_LEVEL)`.\n", + "\n", + "All Events default to the log level `MATX_NVTX_LOG_USER`, and the default verbosity is `MATX_NVTX_LOG_API`. \n", "\n", - "### Fused PC Ops\n", "\n", - "### GPU Ops\n" + "There are 5 increasing levels of verbosity:\n", + "```\n", + "MATX_NVTX_LOG_NONE\n", + "MATX_NVTX_LOG_USER\n", + "MATX_NVTX_LOG_API\n", + "MATX_NVTX_LOG_INTERNAL\n", + "MATX_NVTX_LOG_ALL\n", + "``` \n", + "\n", + "`MATX_NVTX_LOG_NONE` ensures that no Ranges are recorded.\n", + "`MATX_NVTX_LOG_ALL` ensures all NVTX Ranges are recorded.\n", + "\n", + "Any intermediate level ensures that level and all levesl avove it are recoded. For exmaple, if `MATX_NVTX_LOG_API`\n", + "is enabled, then all events of type `MATX_NVTX_LOG_USER` **AND** `MATX_NVTX_LOG_API` will be recoded.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Profiling Radar Application\n", + "To demonstrate the power of the NVTX ranges, we'll demonstrate using the [Radar Pipeline example]() in the MatX example codes. This pipeline showcases both the powerful accleration MatX provides, as well as the granular insight we gain into our performance through the MatX NVTX API.\n" ] } ], From e57459d70c31641d086ba2710a4dcf90e87bb606 Mon Sep 17 00:00:00 2001 From: Tyler Allen Date: Wed, 29 Jan 2025 20:45:10 -0700 Subject: [PATCH 11/91] adding exec to all runs --- .../notebooks/gtc_lab/01_lab_intro.ipynb | 30 +++++---- .../notebooks/gtc_lab/02_lab_fusion.ipynb | 64 ++++++++++++++++--- 2 files changed, 70 insertions(+), 24 deletions(-) diff --git a/docs_input/notebooks/gtc_lab/01_lab_intro.ipynb b/docs_input/notebooks/gtc_lab/01_lab_intro.ipynb index be28b7577..f45bf20f4 100644 --- a/docs_input/notebooks/gtc_lab/01_lab_intro.ipynb +++ b/docs_input/notebooks/gtc_lab/01_lab_intro.ipynb @@ -42,7 +42,9 @@ "#define MATX_EN_OPENBLAS_LAPACK\n", "#define MATX_OPENBLAS_64BITINT\n", "\n", - "#include \"matx.h\"" + "#include \"matx.h\"\n", + "\n", + "exec = matx::SingleThreadedHostExecutor;" ] }, { @@ -492,7 +494,7 @@ "source": [ "\n", "// matrix multiplication\n", - "(C = matx::matmul(A,matx::transpose(B))).run();" + "(C = matx::matmul(A,matx::transpose(B))).run(exec);" ] }, { @@ -516,13 +518,13 @@ "// FFT\n", "auto D = matx::make_tensor({2, 4});\n", "\n", - "(D = matx::random(D.Shape(), matx::NORMAL)).run(); // explained later\n", + "(D = matx::random(D.Shape(), matx::NORMAL)).run(exec); // explained later\n", "matx::print(D);\n", "\n", - "(D = fft(D)).run();\n", + "(D = fft(D)).run(exec);\n", "matx::print(D);\n", "\n", - "(D = matx::ifft(D)).run(); \n", + "(D = matx::ifft(D)).run(exec); \n", "matx::print(D);" ] }, @@ -551,13 +553,13 @@ "auto MD0 = matx::make_tensor({});\n", "auto AD0 = matx::make_tensor({});\n", "\n", - "(A = matx::random(A.Shape(), matx::NORMAL)).run(); \n", + "(A = matx::random(A.Shape(), matx::NORMAL)).run(exec); \n", "\n", "\n", "// max of data\n", - "(MD0 = max(A)).run();\n", + "(MD0 = max(A)).run(exec);\n", "// min of data\n", - "(AD0 = sum(A)).run();\n", + "(AD0 = sum(A)).run(exec);\n", "\n", "printf(\"A:\\n\");\n", "matx::print(A);\n", @@ -620,16 +622,16 @@ "auto H = matx::make_tensor({10});\n", "\n", "// random\n", - "(A = 0).run();\n", - "(A = matx::random(A.Size(), matx::NORMAL)).run();\n", + "(A = 0).run(exec);\n", + "(A = matx::random(A.Size(), matx::NORMAL)).run(exec);\n", "matx::print(A);\n", "\n", "// eye\n", - "(A = matx::eye(A.Size())).run();\n", + "(A = matx::eye(A.Size())).run(exec);\n", "matx::print(A);\n", "\n", "// hamming\n", - "(H = matx::hamming<0>(H.Shape())).run();\n", + "(H = matx::hamming<0>(H.Shape())).run(exec);\n", "matx::print(H);" ] }, @@ -662,13 +664,13 @@ "auto maxIdx = matx::Make_tensor({10});\n", "\n", "// generate random data\n", - "// (input = matx::random