(5770,17728,'2014-06-06 19:26:03','2014-06-06 19:26:03','A lot of scientists and programmers want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking to speed up the calculation of distances from every point in a set <strong>A</strong> to every point in set <strong>B</strong>. i.e. if <strong> A </strong> has <strong> 200 </strong> points and <strong> B </strong> has <strong> 300 </strong> points, the distance matrix will be of size <strong>200 x 300</strong>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\nGFOR is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <strong>A </strong>and replicate it to create a matrix that is the same size as <strong>B</strong>. You can now find distance of a <strong><em>single</em></strong> point in <strong>A </strong>from <strong><em>all </em></strong>points in <strong>B</strong>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><strong>Vectorizing along three dimensions</strong></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <strong>A<em> </em></strong> from every point in <strong>B </strong> in parallel. This can be achieved by modifying and tiling <strong>A</strong>, <strong>B </strong>to get matrices of size <strong>[3, Alen, Blen]</strong>.\r\n\r\nFor <strong>A, </strong>we need to tile it for each point present in <strong>B</strong>.<strong> </strong>This generates a 3D array of the desired dimensions. For <strong>B, </strong>we need to first modify it such that each point in <strong>B</strong> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. A simple illustration of what is happening can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_naive: 5006.01ms\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><strong>20,000 </strong><strong>times</strong><strong> faster</strong></em> than the <em><strong>naive implementation</strong></em>. It is also <em><strong>29 times faster</strong></em> than the next fastest methods.</li>\r\n	<li><strong>gfor2</strong> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><strong>B</strong></em><strong> </strong>has more points than <em><strong>A. </strong></em></li>\r\n	<li><strong>tile1</strong> and <strong>gfor2 </strong>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><strong>tile2 </strong>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <strong>[feat_len, Alen, Blen]. </strong>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <strong>gfor2 </strong>and <strong>tile1 </strong>give the same performance, <strong>tile1 </strong>should be preferred. This is because <strong>GFOR </strong>can not be nested. However using the <strong>tile1 </strong>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <strong>tile1</strong> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the method shown here can provide better performance than <strong>tile1.  </strong>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:26:03','2014-06-06 19:26:03','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5771,17728,'2014-06-06 19:27:19','2014-06-06 19:27:19','A lot of scientists and programmers want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking to speed up the calculation of distances from every point in a set <strong>A</strong> to every point in set <strong>B</strong>. i.e. if <strong> A </strong> has <strong> 200 </strong> points and <strong> B </strong> has <strong> 300 </strong> points, the distance matrix will be of size <strong>200 x 300</strong>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <strong>A </strong>and replicate it to create a matrix that is the same size as <strong>B</strong>. You can now find distance of a <strong><em>single</em></strong> point in <strong>A </strong>from <strong><em>all </em></strong>points in <strong>B</strong>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><strong>Vectorizing along three dimensions</strong></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <strong>A<em> </em></strong> from every point in <strong>B </strong> in parallel. This can be achieved by modifying and tiling <strong>A</strong>, <strong>B </strong>to get matrices of size <strong>[3, Alen, Blen]</strong>.\r\n\r\nFor <strong>A, </strong>we need to tile it for each point present in <strong>B</strong>.<strong> </strong>This generates a 3D array of the desired dimensions. For <strong>B, </strong>we need to first modify it such that each point in <strong>B</strong> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. A simple illustration of what is happening can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_naive: 5006.01ms\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><strong>20,000 </strong><strong>times</strong><strong> faster</strong></em> than the <em><strong>naive implementation</strong></em>. It is also <em><strong>29 times faster</strong></em> than the next fastest methods.</li>\r\n	<li><strong>gfor2</strong> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><strong>B</strong></em><strong> </strong>has more points than <em><strong>A. </strong></em></li>\r\n	<li><strong>tile1</strong> and <strong>gfor2 </strong>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><strong>tile2 </strong>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <strong>[feat_len, Alen, Blen]. </strong>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <strong>gfor2 </strong>and <strong>tile1 </strong>give the same performance, <strong>tile1 </strong>should be preferred. This is because <strong>GFOR </strong>can not be nested. However using the <strong>tile1 </strong>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <strong>tile1</strong> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the method shown here can provide better performance than <strong>tile1.  </strong>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:27:19','2014-06-06 19:27:19','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5773,17728,'2014-06-06 19:30:31','2014-06-06 19:30:31','A lot of scientists and programmers want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking to speed up the calculation of distances from every point in a set <strong>A</strong> to every point in set <strong>B</strong>. i.e. if <strong> A </strong> has <strong> 200 </strong> points and <strong> B </strong> has <strong> 300 </strong> points, the distance matrix will be of size <strong>200 x 300</strong>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <strong>A </strong>and replicate it to create a matrix that is the same size as <strong>B</strong>. You can now find distance of a <strong><em>single</em></strong> point in <strong>A </strong>from <strong><em>all </em></strong>points in <strong>B</strong>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><strong>Vectorizing along three dimensions</strong></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <strong>A<em> </em></strong> from every point in <strong>B </strong> in parallel. This can be achieved by modifying and tiling <strong>A</strong>, <strong>B </strong>to get matrices of size <strong>[3, Alen, Blen]</strong>.\r\n\r\nFor <strong>A, </strong>we need to tile it for each point present in <strong>B</strong>.<strong> </strong>This generates a 3D array of the desired dimensions. For <strong>B, </strong>we need to first modify it such that each point in <strong>B</strong> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. A simple illustration of what is happening can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_naive: 5006.01ms\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><strong>20,000 </strong><strong>times</strong><strong> faster</strong></em> than the <em><strong>naive implementation</strong></em>. It is also <em><strong>29 times faster</strong></em> than the next fastest methods.</li>\r\n	<li><strong>gfor2</strong> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><strong>B</strong></em><strong> </strong>has more points than <em><strong>A. </strong></em></li>\r\n	<li><strong>tile1</strong> and <strong>gfor2 </strong>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><strong>tile2 </strong>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <strong>[feat_len, Alen, Blen]. </strong>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <strong>gfor2 </strong>and <strong>tile1 </strong>give the same performance, <strong>tile1 </strong>should be preferred. This is because <strong>GFOR </strong>can not be nested. However using the <strong>tile1 </strong>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <strong>tile1</strong> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <strong>tile1.  </strong>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:30:31','2014-06-06 19:30:31','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5774,17728,'2014-06-06 19:35:39','2014-06-06 19:35:39','A lot of scientists and programmers want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking to speed up the calculation of distances from every point in a set <strong>A</strong> to every point in set <strong>B</strong>. i.e. if <strong> A </strong> has <strong> 200 </strong> points and <strong> B </strong> has <strong> 300 </strong> points, the distance matrix will be of size <strong>200 x 300</strong>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <strong>A </strong>and replicate it to create a matrix that is the same size as <strong>B</strong>. You can now find distance of a <strong><em>single</em></strong> point in <strong>A </strong>from <strong><em>all </em></strong>points in <strong>B</strong>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><strong>Vectorizing along three dimensions</strong></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <strong>A<em> </em></strong> from every point in <strong>B </strong> in parallel. This can be achieved by modifying and tiling <strong>A</strong>, <strong>B </strong>to get matrices of size <strong>[3, Alen, Blen]</strong>.\r\n\r\nFor <strong>A, </strong>we need to tile it for each point present in <strong>B</strong>.<strong> </strong>This generates a 3D array of the desired dimensions. For <strong>B, </strong>we need to first modify it such that each point in <strong>B</strong> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. A simple illustration of what is happening can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><strong>8,700 </strong><strong>times</strong><strong> faster</strong></em> than the first optimization. It is also <em><strong>29 times faster</strong></em> than the next fastest methods.</li>\r\n	<li><strong>gfor2</strong> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><strong>B</strong></em><strong> </strong>has more points than <em><strong>A. </strong></em></li>\r\n	<li><strong>tile1</strong> and <strong>gfor2 </strong>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><strong>tile2 </strong>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <strong>[feat_len, Alen, Blen]. </strong>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <strong>gfor2 </strong>and <strong>tile1 </strong>give the same performance, <strong>tile1 </strong>should be preferred. This is because <strong>GFOR </strong>can not be nested. However using the <strong>tile1 </strong>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <strong>tile1</strong> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <strong>tile1.  </strong>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:35:39','2014-06-06 19:35:39','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5775,17728,'2014-06-06 19:35:48','2014-06-06 19:35:48','A lot of scientists and programmers want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking to speed up the calculation of distances from every point in a set <strong>A</strong> to every point in set <strong>B</strong>. i.e. if <strong> A </strong> has <strong> 200 </strong> points and <strong> B </strong> has <strong> 300 </strong> points, the distance matrix will be of size <strong>200 x 300</strong>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <strong>A </strong>and replicate it to create a matrix that is the same size as <strong>B</strong>. You can now find distance of a <strong><em>single</em></strong> point in <strong>A </strong>from <strong><em>all </em></strong>points in <strong>B</strong>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><strong>Vectorizing along three dimensions</strong></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <strong>A<em> </em></strong> from every point in <strong>B </strong> in parallel. This can be achieved by modifying and tiling <strong>A</strong>, <strong>B </strong>to get matrices of size <strong>[3, Alen, Blen]</strong>.\r\n\r\nFor <strong>A, </strong>we need to tile it for each point present in <strong>B</strong>.<strong> </strong>This generates a 3D array of the desired dimensions. For <strong>B, </strong>we need to first modify it such that each point in <strong>B</strong> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. A simple illustration of what is happening can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><strong>8,700 </strong><strong>times</strong><strong> faster</strong></em> than the first optimization. It is also <em><strong>29 times faster</strong></em> than the next fastest methods.</li>\r\n	<li><strong>gfor2</strong> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><strong>B</strong></em><strong> </strong>has more points than <em><strong>A. </strong></em></li>\r\n	<li><strong>tile1</strong> and <strong>gfor2 </strong>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><strong>tile2 </strong>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <strong>[feat_len, Alen, Blen]. </strong>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <strong>gfor2 </strong>and <strong>tile1 </strong>give the same performance, <strong>tile1 </strong>should be preferred. This is because <strong>GFOR </strong>can not be nested. However using the <strong>tile1 </strong>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <strong>tile1</strong> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <strong>tile1.  </strong>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:35:48','2014-06-06 19:35:48','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5776,17728,'2014-06-06 19:38:39','2014-06-06 19:38:39','A lot of scientists and programmers want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking to speed up the calculation of distances from every point in a set <strong>A</strong> to every point in set <strong>B</strong>. i.e. if <strong> A </strong> has <strong> 200 </strong> points and <strong> B </strong> has <strong> 300 </strong> points, the distance matrix will be of size <strong>200 x 300</strong>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <strong>A </strong>and replicate it to create a matrix that is the same size as <strong>B</strong>. You can now find distance of a <strong><em>single</em></strong> point in <strong>A </strong>from <strong><em>all </em></strong>points in <strong>B</strong>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><strong>Vectorizing along three dimensions</strong></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <strong>A<em> </em></strong> from every point in <strong>B </strong> in parallel. This can be achieved by modifying and tiling <strong>A</strong>, <strong>B </strong>to get matrices of size <strong>[3, Alen, Blen]</strong>.\r\n\r\nFor <strong>A, </strong>we need to tile it for each point present in <strong>B</strong>.<strong> </strong>This generates a 3D array of the desired dimensions. For <strong>B, </strong>we need to first modify it such that each point in <strong>B</strong> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. A simple illustration of what is happening can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><strong>8,700 </strong><strong>times</strong><strong> faster</strong></em> than the 1D vectorized code. It is also <em><strong>29 times faster</strong></em> than the next fastest methods.</li>\r\n	<li><strong>gfor2</strong> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><strong>B</strong></em><strong> </strong>has more points than <em><strong>A. </strong></em></li>\r\n	<li><strong>tile1</strong> and <strong>gfor2 </strong>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><strong>tile2 </strong>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <strong>[feat_len, Alen, Blen]. </strong>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <strong>gfor2 </strong>and <strong>tile1 </strong>give the same performance, <strong>tile1 </strong>should be preferred. This is because <strong>GFOR </strong>can not be nested. However using the <strong>tile1 </strong>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <strong>tile1</strong> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <strong>tile1.  </strong>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:38:39','2014-06-06 19:38:39','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5777,17728,'2014-06-06 19:39:32','2014-06-06 19:39:32','A lot of scientists and programmers want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <strong>A</strong> to every point in set <strong>B</strong>. i.e. if <strong> A </strong> has <strong> 200 </strong> points and <strong> B </strong> has <strong> 300 </strong> points, the distance matrix will be of size <strong>200 x 300</strong>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <strong>A </strong>and replicate it to create a matrix that is the same size as <strong>B</strong>. You can now find distance of a <strong><em>single</em></strong> point in <strong>A </strong>from <strong><em>all </em></strong>points in <strong>B</strong>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><strong>Vectorizing along three dimensions</strong></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <strong>A<em> </em></strong> from every point in <strong>B </strong> in parallel. This can be achieved by modifying and tiling <strong>A</strong>, <strong>B </strong>to get matrices of size <strong>[3, Alen, Blen]</strong>.\r\n\r\nFor <strong>A, </strong>we need to tile it for each point present in <strong>B</strong>.<strong> </strong>This generates a 3D array of the desired dimensions. For <strong>B, </strong>we need to first modify it such that each point in <strong>B</strong> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. A simple illustration of what is happening can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><strong>8,700 </strong><strong>times</strong><strong> faster</strong></em> than the 1D vectorized code. It is also <em><strong>29 times faster</strong></em> than the next fastest methods.</li>\r\n	<li><strong>gfor2</strong> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><strong>B</strong></em><strong> </strong>has more points than <em><strong>A. </strong></em></li>\r\n	<li><strong>tile1</strong> and <strong>gfor2 </strong>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><strong>tile2 </strong>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <strong>[feat_len, Alen, Blen]. </strong>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <strong>gfor2 </strong>and <strong>tile1 </strong>give the same performance, <strong>tile1 </strong>should be preferred. This is because <strong>GFOR </strong>can not be nested. However using the <strong>tile1 </strong>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <strong>tile1</strong> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <strong>tile1.  </strong>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:39:32','2014-06-06 19:39:32','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5778,17728,'2014-06-06 19:42:14','2014-06-06 19:42:14','Programmers and Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. i.e. if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><code>Vectorizing along three dimensions</code></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> from every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. \r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <code>tile1.  </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:42:14','2014-06-06 19:42:14','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5779,17728,'2014-06-06 19:43:11','2014-06-06 19:43:11','Programmers and Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. i.e. if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii &lt; a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk &lt; a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii &lt; a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii &lt; a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj &lt; blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3><code>Vectorizing along three dimensions</code></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> from every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <code>tile1.  </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:43:11','2014-06-06 19:43:11','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5780,17728,'2014-06-06 19:43:27','2014-06-06 19:43:27','Programmers and Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. i.e. if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><code>Vectorizing along three dimensions</code></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> from every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. \r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <code>tile1.  </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:43:27','2014-06-06 19:43:27','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5781,17728,'2014-06-06 19:43:57','2014-06-06 19:43:57','Programmers and Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. i.e. if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences                                                                                                                                                                   \r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a                                                                                                                                                                                     \r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b                                                                                                                                                                              \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a                                                                                                                                                                                       \r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b                                                                                                                                                                                \r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{   \r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b                                                                                                                                                                                       \r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A                                                                                                                                                                              \r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector                                                                                                                                                                       \r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{   \r\n    // int feat_len = a.dims(0); // Same as b.dims(0);                                                                                                                                                               \r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b                                                                                                                                                                                  \r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b                                                                                                                                                                                \r\n        // shape of bvec is (feat_len, 1)                                                                                                                                                                            \r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a                                                                                                                                                                            \r\n        // shape of bvec_tiled is (feat_len, alen)                                                                                                                                                                   \r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences                                                                                                                                                                       \r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector                                                                                                                                                           \r\n        // transpose sad and fill in dist_mat                                                                                                                                                                        \r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><code>Vectorizing along three dimensions</code></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> from every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions. \r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{   \r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)                                                                                                                                                                             \r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)                                                                                                                                                        \r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)                                                                                                                                                               \r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension                                                                                                                                                                    \r\n    // Output is of shape (1, alen, blen)                                                                                                                                                                            \r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)                                                                                                                                                         \r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <code>tile1.  </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a> ','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:43:57','2014-06-06 19:43:57','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5782,17728,'2014-06-06 19:45:05','2014-06-06 19:45:05','Programmers and Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. i.e. if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><code>Vectorizing along three dimensions</code></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> from every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <code>tile1.  </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 19:45:05','2014-06-06 19:45:05','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5784,17728,'2014-06-06 20:06:02','2014-06-06 20:06:02','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. i.e. if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has co-ordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in co-ordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three co-ordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without having to use the third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><code>Vectorizing along three dimensions</code></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> from every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final performance improvements are about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <code>tile1.  </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 20:06:02','2014-06-06 20:06:02','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5785,17728,'2014-06-06 20:18:25','2014-06-06 20:18:25','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, we present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n\r\n<pre>\r\nA = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n\r\n<pre>\r\n// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n\r\n<pre>\r\nstatic array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s can not be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n\r\n<pre>\r\nstatic array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n\r\n<pre>\r\nstatic array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n\r\n<h3><code>Vectorizing along three dimensions</code></h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n\r\n<pre>\r\nOriginal\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\n\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>\r\nstatic array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n\r\n<pre>\r\nTime for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms which combine one or two of the methods shown here can provide better performance than <code>tile1.  </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\n\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-06 20:18:25','2014-06-06 20:18:25','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5786,7,'2014-06-09 17:41:10','2014-06-09 17:41:10','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\n\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\n<h3>The problem</h3>\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\n<pre>A = randu(3, 200);\nB = randu(3, 300);\n</pre>\n<h3>Naive implementation</h3>\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\n\nThis can be implemented in the following manner.\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\nstatic array dist_naive(array a, array b)\n{\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\n\n    // Iterate through columns a\n    for (int ii = 0; ii &lt; a.dims(1); ii++) {\n\n        // Iterate through columns of b\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\n\n            // Get the sum of absolute differences\n            for (int kk = 0; kk &lt; a.dims(0); kk++) {\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\n            }\n        }\n    }\n\n    return dist_mat;\n}\n</pre>\n<h3>Vectorizing along one dimension</h3>\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\n<pre>static array dist_vec(array a, array b)\n{\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\n\n    // Iterate through columns a\n    for (int ii = 0; ii &lt; a.dims(1); ii++) {\n        array avec = a(span, ii);\n\n        // Iterate through columns of b\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\n            array bvec = b(span, jj);\n\n            // get SAD using sum on the vector\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\n        }\n    }\n\n    return dist_mat;\n}\n</pre>\n<h3>Using GFOR</h3>\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\n<pre>static array dist_gfor1(array a, array b)\n{\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\n\n    // GFOR along columns of a\n    gfor (array ii, a.dims(1)) {\n        array avec = a(span, ii);\n\n        // Itere through columns of b\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\n            array bvec = b(span, jj);\n\n            // get SAD using sum on the vector\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\n        }\n    }\n\n    return dist_mat;\n}\n\nstatic array dist_gfor2(array a, array b)\n{\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\n\n    // GFOR along columns of b\n    gfor (array jj, b.dims(1)) {\n        array bvec = b(span, jj);\n\n        // Iterate through columns of A\n        for (int ii = 0; ii &lt; a.dims(1); ii++) {\n            array avec = a(span, ii);\n\n            // get SAD using sum on the vector\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\n        }\n    }\n\n    return dist_mat;\n}\n</pre>\n<h3>Vectorizing along two dimensions</h3>\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\n<pre>static array dist_tile1(array a, array b)\n{\n    // int feat_len = a.dims(0); // Same as b.dims(0);\n    int alen = a.dims(1);\n    int blen = b.dims(1);\n\n    array dist_mat = constant(0, alen, blen);\n\n    // Iterate through columns of b\n    for (int jj = 0; jj &lt; blen; jj++) {\n\n        // Get the column vector of b\n        // shape of bvec is (feat_len, 1)\n        array bvec = b(span, jj);\n\n        // Tile avec to be same size as a\n        // shape of bvec_tiled is (feat_len, alen)\n        array bvec_tiled = tile(bvec, 1, alen);\n\n        // Get the sum of absolute differences\n        array sad = sum(abs(bvec_tiled - a));\n\n        // sad is row vector, dist_mat needs column vector\n        // transpose sad and fill in dist_mat\n        dist_mat(span, jj) = sad.T();\n    }\n\n    return dist_mat;\n}\n</pre>\n<h3>Vectorizing along three dimensions</h3>\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\n\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\n\nA simple illustration of what tiling does to the data can be seen below.\n<pre>Original\nA [2 4] =\n       10.0000    11.0000    12.0000    13.0000\n       14.0000    15.0000    16.0000    17.0000\n\nB [2 3] =\n       20.0000    21.0000    22.0000\n       23.0000    24.0000    25.0000\n\nModified\nA_mod [2 4] =\n       10.0000    11.0000    12.0000    13.0000\n       14.0000    15.0000    16.0000    17.0000\n\nB_mod [2 1 3] =\n       20.0000\n       23.0000\n\n       21.0000\n       24.0000\n\n       22.0000\n       25.0000\n\nTiled\nA_tiled [2 4 3] =\n       10.0000    11.0000    12.0000    13.0000\n       14.0000    15.0000    16.0000    17.0000\n\n       10.0000    11.0000    12.0000    13.0000\n       14.0000    15.0000    16.0000    17.0000\n\n       10.0000    11.0000    12.0000    13.0000\n       14.0000    15.0000    16.0000    17.0000\n\nB_tiled [2 4 3] =\n       20.0000    20.0000    20.0000    20.0000\n       23.0000    23.0000    23.0000    23.0000\n\n       21.0000    21.0000    21.0000    21.0000\n       24.0000    24.0000    24.0000    24.0000\n\n       22.0000    22.0000    22.0000    22.0000\n       25.0000    25.0000    25.0000    25.0000\n</pre>\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\n<pre>static array dist_tile2(array a, array b)\n{\n    int feat_len = a.dims(0);\n    int alen = a.dims(1);\n    int blen = b.dims(1);\n\n    // Shape of a is (feat_len, alen, 1)\n    array a_mod = a;\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\n    array b_mod = moddims(b, feat_len, 1, blen);\n\n    // Tile both matrices to be (feat_len, alen, blen)\n    array a_tiled = tile(a_mod, 1, 1, blen);\n    array b_tiled = tile(b_mod, 1, alen, 1);\n\n    // Do The sum operation along first dimension\n    // Output is of shape (1, alen, blen)\n    array dist_mod = sum(abs(a_tiled - b_tiled));\n\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\n    array dist_mat = moddims(dist_mod, alen, blen);\n    return dist_mat;\n}\n</pre>\n<h3>Results</h3>\nThe following results have been generated on a NVIDIA Quadro K5000.\n<pre>Time for dist_vec  : 2177.73ms\nTime for dist_gfor1: 10.80ms\nTime for dist_gfor2: 7.35ms\nTime for dist_tile1: 7.23ms\nTime for dist_tile2: 0.25ms\n</pre>\n<ul>\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\n</ul>\n<h3>Considerations</h3>\n<ul>\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1.  </code>We will talk about such algorithms at a later date.</li>\n</ul>\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-autosave-v1','','','2014-06-09 17:41:10','2014-06-09 17:41:10','',5762,'http://sandbox.arrayfire.com/5762-autosave-v1/',0,'revision','',0),(5787,7,'2014-06-09 17:41:53','2014-06-09 17:41:53','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii &lt; a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk &lt; a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii &lt; a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj &lt; b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii &lt; a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj &lt; blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-09 17:41:53','2014-06-09 17:41:53','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5788,17728,'2014-06-09 17:53:16','2014-06-09 17:53:16','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner.\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-09 17:53:16','2014-06-09 17:53:16','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5790,17728,'2014-06-09 17:54:31','2014-06-09 17:54:31','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner. <em> The code is shown for reference. This is extremely slow on GPUs </em>\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <b>gfor2</b> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-09 17:54:31','2014-06-09 17:54:31','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5791,17728,'2014-06-09 18:01:45','2014-06-09 18:01:45','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner. <em> The code is shown for reference. This is extremely slow on GPUs </em>\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <code>gfor1</code> (GFOR over A) because <em><code>B</code></em><code> </code>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-09 18:01:45','2014-06-09 18:01:45','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0);
INSERT INTO `wp_posts` VALUES (5792,17728,'2014-06-09 18:04:13','2014-06-09 18:04:13','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner. <em> The code is shown for reference. This is extremely slow on GPUs </em>\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <code>gfor1</code> (GFOR over A) because <em><code>B</code></em> has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, <code>feat_len</code> was 3, <code>Alen</code> was 200 and <code>Blen</code> was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-autosave-v1','','','2014-06-09 18:04:13','2014-06-09 18:04:13','',5762,'http://sandbox.arrayfire.com/5762-autosave-v1/',0,'revision','',0),(5793,17728,'2014-06-09 18:02:20','2014-06-09 18:02:20','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner. <em> The code is shown for reference. This is extremely slow on GPUs </em>\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <code>gfor1</code> (GFOR over A) because <em><code>B</code></em>has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-09 18:02:20','2014-06-09 18:02:20','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5794,17728,'2014-06-09 18:03:09','2014-06-09 18:03:09','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner. <em> The code is shown for reference. This is extremely slow on GPUs </em>\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <code>gfor1</code> (GFOR over A) because <em><code>B</code></em> has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, feat_len was 3, Alen was 200 and Blen was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-09 18:03:09','2014-06-09 18:03:09','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5795,17728,'2014-06-09 18:04:09','2014-06-09 18:04:09','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner. <em> The code is shown for reference. This is extremely slow on GPUs </em>\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <code>gfor1</code> (GFOR over A) because <em><code>B</code></em> has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, <code>feat_len</code> was 3, <code>Alen</code> was 200 and <code>Blen</code> was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-09 18:04:09','2014-06-09 18:04:09','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5796,17728,'2014-06-09 18:05:09','2014-06-09 18:05:09','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. There are many ways you can vectorize a given code segment. Each method has its own benefits and drawbacks. Hence, writing vectorized code involves analyzing the pros and cons of the available methods and choosing the right one to solve your problem.\r\n\r\nIn this post, I present various ways to vectorize your code using ArrayFire. ArrayFire is chosen because of my familiarity with the software. The same methods can be easily used in numpy, octave, julia or other scientific computing software.\r\n<h3>The problem</h3>\r\nThe problem we will be looking at is the calculation of distances from every point in a set <code>A</code> to every point in set <code>B</code>. For example, if <code> A </code> has <code> 200 </code> points and <code> B </code> has <code> 300 </code> points, the distance matrix will be of size <code>200 x 300</code>. Each point has coordinates in 3 dimensional space. We can generate the necessary data in the following manner.\r\n<pre>A = randu(3, 200);\r\nB = randu(3, 300);\r\n</pre>\r\n<h3>Naive implementation</h3>\r\nThe naive method would be to have three loops. The outer most loop iterating through points in A. The second loop iterating through points in B. The inner most loop iterating through the three dimensions. You can find difference in coordinates between the two points and find the distance between the two points.\r\n\r\nThis can be implemented in the following manner. <em> The code is shown for reference. This is extremely slow on GPUs </em>\r\n<pre>// CODE SHOWN FOR REFERENCE. DO NOT USE. IT IS EXTREMELY SLOW.\r\nstatic array dist_naive(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n\r\n            // Get the sum of absolute differences\r\n            for (int kk = 0; kk < a.dims(0); kk++) {\r\n                dist_mat(ii, jj) += abs(a(kk, ii) - b(kk, jj));\r\n            }\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along one dimension</h3>\r\nKeeping the outer two loops the same, you can improve the performance by treating the set of three coordinates as a single vector. You can perform the difference between these vectors in parallel. A reduction operation after getting the absolute differences will give us the distance without the need of a third loop.\r\n<pre>static array dist_vec(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // Iterate through columns a\r\n    for (int ii = 0; ii < a.dims(1); ii++) {\r\n        array avec = a(span, ii);\r\n\r\n        // Iterate through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Using GFOR</h3>\r\n<a href=\"http://sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR</a> is a parallel version of the for loop in ArrayFire. Since GFOR\'s cannot be nested, we can replace one of the for loops using GFOR. This can be done in the following manners.\r\n<pre>static array dist_gfor1(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of a\r\n    gfor (array ii, a.dims(1)) {\r\n        array avec = a(span, ii);\r\n\r\n        // Itere through columns of b\r\n        for (int jj = 0; jj < b.dims(1); jj++) {\r\n            array bvec = b(span, jj);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n\r\nstatic array dist_gfor2(array a, array b)\r\n{\r\n    array dist_mat = constant(0, a.dims(1), b.dims(1));\r\n\r\n    // GFOR along columns of b\r\n    gfor (array jj, b.dims(1)) {\r\n        array bvec = b(span, jj);\r\n\r\n        // Iterate through columns of A\r\n        for (int ii = 0; ii < a.dims(1); ii++) {\r\n            array avec = a(span, ii);\r\n\r\n            // get SAD using sum on the vector\r\n            dist_mat(ii, jj) = sum(abs(avec - bvec));\r\n        }\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along two dimensions</h3>\r\nWe can get rid of another FOR loop to have 2-D vectorized code. You can get a single point from set <code>A </code>and replicate it to create a matrix that is the same size as <code>B</code>. You can now find distance of a <code><em>single</em></code> point in <code>A </code>from <code><em>all </em></code>points in <code>B</code>. The code can be seen below.\r\n<pre>static array dist_tile1(array a, array b)\r\n{\r\n    // int feat_len = a.dims(0); // Same as b.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    array dist_mat = constant(0, alen, blen);\r\n\r\n    // Iterate through columns of b\r\n    for (int jj = 0; jj < blen; jj++) {\r\n\r\n        // Get the column vector of b\r\n        // shape of bvec is (feat_len, 1)\r\n        array bvec = b(span, jj);\r\n\r\n        // Tile avec to be same size as a\r\n        // shape of bvec_tiled is (feat_len, alen)\r\n        array bvec_tiled = tile(bvec, 1, alen);\r\n\r\n        // Get the sum of absolute differences\r\n        array sad = sum(abs(bvec_tiled - a));\r\n\r\n        // sad is row vector, dist_mat needs column vector\r\n        // transpose sad and fill in dist_mat\r\n        dist_mat(span, jj) = sad.T();\r\n    }\r\n\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Vectorizing along three dimensions</h3>\r\nThe previous method can be further extended. This would involve getting the differences between every point in <code>A<em> </em></code> and every point in <code>B </code> in parallel. This can be achieved by modifying and tiling <code>A</code>, <code>B </code>to get matrices of size <code>[3, Alen, Blen]</code>.\r\n\r\nFor <code>A, </code>we need to tile it for each point present in <code>B</code>.<code> </code>This generates a 3D array of the desired dimensions. For <code>B, </code>we need to first modify it such that each point in <code>B</code> is represented in the 3rd dimension rather than the second. This is followed up by a tiling operation in the second dimension to generate a 3D array of the desired dimensions.\r\n\r\nA simple illustration of what tiling does to the data can be seen below.\r\n<pre>Original\r\nA [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB [2 3] =\r\n       20.0000    21.0000    22.0000\r\n       23.0000    24.0000    25.0000\r\n\r\nModified\r\nA_mod [2 4] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_mod [2 1 3] =\r\n       20.0000\r\n       23.0000\r\n\r\n       21.0000\r\n       24.0000\r\n\r\n       22.0000\r\n       25.0000\r\n\r\nTiled\r\nA_tiled [2 4 3] =\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\n       10.0000    11.0000    12.0000    13.0000\r\n       14.0000    15.0000    16.0000    17.0000\r\n\r\nB_tiled [2 4 3] =\r\n       20.0000    20.0000    20.0000    20.0000\r\n       23.0000    23.0000    23.0000    23.0000\r\n\r\n       21.0000    21.0000    21.0000    21.0000\r\n       24.0000    24.0000    24.0000    24.0000\r\n\r\n       22.0000    22.0000    22.0000    22.0000\r\n       25.0000    25.0000    25.0000    25.0000\r\n</pre>\r\nOnce we have the tiled versions of the matrices, a single reduction generates the desired results in a single step. The code for this optimization can be seen below.\r\n<pre>static array dist_tile2(array a, array b)\r\n{\r\n    int feat_len = a.dims(0);\r\n    int alen = a.dims(1);\r\n    int blen = b.dims(1);\r\n\r\n    // Shape of a is (feat_len, alen, 1)\r\n    array a_mod = a;\r\n    // Reshape b from (feat_len, blen) to (feat_len, 1, blen)\r\n    array b_mod = moddims(b, feat_len, 1, blen);\r\n\r\n    // Tile both matrices to be (feat_len, alen, blen)\r\n    array a_tiled = tile(a_mod, 1, 1, blen);\r\n    array b_tiled = tile(b_mod, 1, alen, 1);\r\n\r\n    // Do The sum operation along first dimension\r\n    // Output is of shape (1, alen, blen)\r\n    array dist_mod = sum(abs(a_tiled - b_tiled));\r\n\r\n    // Reshape dist_mat from (1, alen, blen) to (alen, blen)\r\n    array dist_mat = moddims(dist_mod, alen, blen);\r\n    return dist_mat;\r\n}\r\n</pre>\r\n<h3>Results</h3>\r\nThe following results have been generated on a NVIDIA Quadro K5000.\r\n<pre>Time for dist_vec  : 2177.73ms\r\nTime for dist_gfor1: 10.80ms\r\nTime for dist_gfor2: 7.35ms\r\nTime for dist_tile1: 7.23ms\r\nTime for dist_tile2: 0.25ms\r\n</pre>\r\n<ul>\r\n	<li>As you can see the final code is about <em><code>8,700 </code><code>times</code><code> faster</code></em> than the 1D vectorized code. It is also <em><code>29 times faster</code></em> than the next fastest methods.</li>\r\n	<li><code>gfor2</code> (GFOR over B) is faster than <code>gfor1</code> (GFOR over A) because <em><code>B</code></em> has more points than <em><code>A. </code></em></li>\r\n	<li><code>tile1</code> and <code>gfor2 </code>have similar performance because they employ similar mechanisms internally.</li>\r\n</ul>\r\n<h3>Considerations</h3>\r\n<ul>\r\n	<li><code>tile2 </code>is the fastest method, but it also uses up the most memory as scratch space. It requires two temporary matrices of sizes <code>[feat_len, Alen, Blen]. </code>In this particular case, <code>feat_len</code> was 3, <code>Alen</code> was 200 and <code>Blen</code> was 300. However, it is easy for the scratch space requirements to grow to a few gigabytes when the number for points is much higher (as is the case with most machine learning algorithms).</li>\r\n	<li>Though <code>gfor2 </code>and <code>tile1 </code>give the same performance, <code>tile1 </code>should be preferred. This is because <code>GFOR </code>can not be nested. However using the <code>tile1 </code>method enables us to use GFOR at a higher level in the program.</li>\r\n	<li>Of the functions presented here, <code>tile1</code> is perhaps the best compromise when constrained by memory.</li>\r\n	<li>Hybrid algorithms, which combine one or two of the methods shown here, can provide better performance than <code>tile1. </code>We will talk about such algorithms at a later date.</li>\r\n</ul>\r\nThe relevant code for this post can be found on <a href=\"http://github.com/arrayfire\">our github</a> page over <a href=\"https://github.com/arrayfire/arrayfire_examples/blob/master/getting_started/vectorize.cpp\">here</a>.','How to write vectorized code','','inherit','open','open','','5762-revision-v1','','','2014-06-09 18:05:09','2014-06-09 18:05:09','',5762,'http://sandbox.arrayfire.com/5762-revision-v1/',0,'revision','',0),(5799,17729,'2014-06-12 18:09:49','2014-06-12 18:09:49','In this post we will be looking at benchmarks of the following ArrayFire image processing functions on an ARM device.\r\n<ul>\r\n	<li><a href=\"http://www.sandbox.arrayfire.com/docs/group__morph__mat.htm\">Erosion/Dilation</a></li>\r\n	<li><a href=\"http://www.sandbox.arrayfire.com/docs/group__image__func__cpp__medfilt.htm\">Median filter</a></li>\r\n	<li><a href=\"http://www.sandbox.arrayfire.com/docs/group__image__func__cpp__resize.htm\">Resize</a></li>\r\n	<li><a href=\"http://www.sandbox.arrayfire.com/docs/group__image__func__cpp__histogram.htm\">Histogram</a></li>\r\n	<li><a href=\"http://www.sandbox.arrayfire.com/docs/group__image__func__cpp__bilateral.htm\">Bilateral filter</a></li>\r\n	<li><a href=\"http://www.sandbox.arrayfire.com/docs/group__signal__func__cpp__convolve.htm\">Convolution</a></li>\r\n</ul>\r\nWe pitted the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU (from here on referred as TK1) on the Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the the following resolutions are used for benchmarks.\r\n<ul>\r\n	<li>480p (720x480)</li>\r\n	<li>720p and 1080p HD</li>\r\n	<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis (Frames per second) in all of the plots is on log scale. The higher the value along the vertical axis, the better the run times are for that function on a given device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<iframe src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=1799759820\" width=\"792\" height=\"563\" frameborder=\"0\" scrolling=\"no\" seamless=\"\"></iframe>\r\n\r\nA 3x3 mask was used to benchmark <a href=\"http://www.sandbox.arrayfire.com/docs/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode because they use the same algorithm with a different local neighborhood operator.\r\n<h4 id=\"median-filter\">Median Filter</h4>\r\n<iframe src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=629321992\" width=\"794\" height=\"561\" frameborder=\"0\" scrolling=\"no\" seamless=\"\"></iframe>\r\n\r\nA 3x3 mask was used to benchmark <a href=\"http://www.sandbox.arrayfire.com/docs/group__image__func__cpp__medfilt.htm\"><code>medfilt</code></a> function as well.\r\n<h4 id=\"resize\">Resize</h4>\r\n<iframe src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=1318972511\" width=\"793\" height=\"561\" frameborder=\"0\" scrolling=\"no\" seamless=\"\"></iframe>\r\n\r\nWe benchmarked <a href=\"http://www.sandbox.arrayfire.com/docs/group__image__func__cpp__resize.htm\"><code>resize</code></a> for halving the image size.\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<iframe src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=12968102\" width=\"794\" height=\"566\" frameborder=\"0\" scrolling=\"no\" seamless=\"\"></iframe>\r\n\r\nStandard 256 bin <code><a href=\"http://www.sandbox.arrayfire.com/docs/group__image__func__cpp__histogram.htm\">histogram</a>.</code>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<iframe src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=528280719\" width=\"792\" height=\"560\" frameborder=\"0\" scrolling=\"no\" seamless=\"\"></iframe>\r\n\r\nWe used 3.5 (7x7 window) spatial variance and 50 chromatic variance to benchmark <a href=\"http://www.sandbox.arrayfire.com/docs/group__image__func__cpp__bilateral.htm\"><code>bilateral</code></a> function.\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<iframe src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=905426513\" width=\"795\" height=\"563\" frameborder=\"0\" scrolling=\"no\" seamless=\"\"></iframe>\r\n\r\nA 5x5 blur kernel was used to benchmark <a href=\"http://www.sandbox.arrayfire.com/docs/group__signal__func__cpp__convolve.htm\"><code>convolve</code></a> function.\r\n<h3>Conclusion</h3>\r\n<ul>\r\n	<li><code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.</li>\r\n	<li><code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.</li>\r\n	<li><code>bilateral</code> runs in real time until 1080p HD resolution and falls to 8 fps for 4k UHD.</li>\r\n	<li><code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.</li>\r\n</ul>\r\nThere are a plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.sandbox.arrayfire.com/docs/group__image__mat.htm\">here</a>. The main take away point from this post is that we can easily do image processing in real time using Jetson TK1 for up to 4k UHD resolution.\r\n\r\n<h4> Update </h4>\r\n\r\n<del> If you want to try out ArrayFire on your Jetson TK1, please contact us at sales@arrayfire.com. </del>\r\n\r\nWe\'ve released ArrayFire for Jetson TK1. You can now get access to the latest version from our <a href=\"http://sandbox.arrayfire.com/download\"> download  page</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','publish','open','open','','arrayfire-on-nvidia-tegra-tk1','','','2014-06-30 15:52:45','2014-06-30 15:52:45','',0,'http://sandbox.arrayfire.com/?p=5799',0,'post','',6),(5806,17729,'2014-06-11 18:19:15','2014-06-11 18:19:15','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new NVIDIA Tegra tk1 against a NVIDIA\'s mobile(netbook) gpu. The closest match to Tegra tk1 we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a Tegra tk1,<br />there are many other parameters that influence the performance. Below given is the spec comparision of both the GPUs for your reference. The properties that are have more critical effect on the performance of the functions are only listed here.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Tegra tk1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode-300x225.png\" alt=\"erode\" width=\"300\" height=\"225\" class=\"alignnone size-medium wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt-300x231.png\" alt=\"medfilt\" width=\"300\" height=\"231\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize-300x216.png\" alt=\"resize\" width=\"300\" height=\"216\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist-300x225.png\" alt=\"hist\" width=\"300\" height=\"225\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral-300x217.png\" alt=\"bilateral\" width=\"300\" height=\"217\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv-300x227.png\" alt=\"conv\" width=\"300\" height=\"227\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>','ArrayFire on NVIDIA Tegra tk1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 18:19:15','2014-06-11 18:19:15','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5808,17729,'2014-06-11 18:27:51','2014-06-11 18:27:51','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a NVIDIA\'s mobile(netbook) gpu. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. Below given is the spec comparison of both the GPUs for your reference. The properties that are have more critical effect on the performance of the functions are only listed here.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 18:27:51','2014-06-11 18:27:51','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5809,17729,'2014-06-11 18:28:38','2014-06-11 18:28:38','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a NVIDIA\'s mobile(netbook) gpu. The closest match to the GPU(from here on referred as `TK1`) on Jetson board we have in our mobile card deck is a `NVIDIA GT 650M`. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. Below given is the spec comparison of both the GPUs for your reference. The properties that are have more critical effect on the performance of the functions are only listed here.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 18:28:38','2014-06-11 18:28:38','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5810,17729,'2014-06-11 18:29:03','2014-06-11 18:29:03','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a NVIDIA\'s mobile(netbook) gpu. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. Below given is the spec comparison of both the GPUs for your reference. The properties that are have more critical effect on the performance of the functions are only listed here.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 18:29:03','2014-06-11 18:29:03','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5811,17729,'2014-06-11 18:40:07','2014-06-11 18:40:07','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a NVIDIA\'s mobile(netbook) gpu. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. Below given is the spec comparison of both the GPUs for your reference. The properties that are have more critical effect on the performance of the functions are only listed here.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 18:40:07','2014-06-11 18:40:07','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5812,17729,'2014-06-11 20:44:25','2014-06-11 20:44:25','','conv','','inherit','open','open','','conv-2','','','2014-06-11 20:44:25','2014-06-11 20:44:25','',5799,'http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png',0,'attachment','image/png',0),(5814,17729,'2014-06-11 20:44:28','2014-06-11 20:44:28','','hist','','inherit','open','open','','hist','','','2014-06-11 20:44:28','2014-06-11 20:44:28','',5799,'http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png',0,'attachment','image/png',0),(5815,17729,'2014-06-11 20:44:29','2014-06-11 20:44:29','','resize','','inherit','open','open','','resize','','','2014-06-11 20:44:29','2014-06-11 20:44:29','',5799,'http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png',0,'attachment','image/png',0),(5816,17729,'2014-06-11 20:44:30','2014-06-11 20:44:30','','medfilt','','inherit','open','open','','medfilt','','','2014-06-11 20:44:30','2014-06-11 20:44:30','',5799,'http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png',0,'attachment','image/png',0),(5817,17729,'2014-06-11 20:44:31','2014-06-11 20:44:31','','erode','','inherit','open','open','','erode','','','2014-06-11 20:44:31','2014-06-11 20:44:31','',5799,'http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png',0,'attachment','image/png',0),(5818,17729,'2014-06-11 20:50:27','2014-06-11 20:50:27','','bilateral','','inherit','open','open','','bilateral','','','2014-06-11 20:50:27','2014-06-11 20:50:27','',5799,'http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png',0,'attachment','image/png',0),(5819,17729,'2014-06-11 20:52:34','2014-06-11 20:52:34','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a NVIDIA\'s mobile(netbook) gpu. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. Below given is the spec comparison of both the GPUs for your reference. The properties that are have more critical effect on the performance of the functions are only listed here.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 20:52:34','2014-06-11 20:52:34','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5822,17729,'2014-06-11 21:35:57','2014-06-11 21:35:57','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. Below given is the spec comparison of both the GPUs for your reference. The properties that have more critical effect on the performance of the functions are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 21:35:57','2014-06-11 21:35:57','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5823,17729,'2014-06-11 21:58:57','2014-06-11 21:58:57','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. Below given is the spec comparison of both the GPUs for your reference. The properties that have more critical effect on the performance of the functions are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for 480p, and all HD resolutions 720p, 1080p and 4K except ','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 21:58:57','2014-06-11 21:58:57','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5824,17729,'2014-06-11 22:06:21','2014-06-11 22:06:21','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. Below given is the spec comparison of both the GPUs for your reference. The properties that have more critical effect on the performance of the functions are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:06:21','2014-06-11 22:06:21','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5825,17729,'2014-06-11 22:09:42','2014-06-11 22:09:42','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. Though it has twice as many cores as a TK1, there are many other parameters that influence the performance of the CUDA kernels. The spec comparison of both the GPUs used for benchmarks is given below for your reference. The properties that have more critical effect on the performance of the functions are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:09:42','2014-06-11 22:09:42','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5826,17729,'2014-06-11 22:10:44','2014-06-11 22:10:44','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The spec comparison of both the GPUs used for benchmarks is given below for your reference. The properties that have more critical effect on the performance of the functions are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>','ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:10:44','2014-06-11 22:10:44','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5827,17729,'2014-06-11 22:11:18','2014-06-11 22:11:18','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The spec comparison of both the GPUs used for benchmarks is given below for your reference. The properties that have more critical effect on the performance of the functions are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>','Image Processing using ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:11:18','2014-06-11 22:11:18','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5828,17729,'2014-06-11 22:13:49','2014-06-11 22:13:49','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The spec comparison of both the GPUs used for benchmarks is given below for your reference. The properties that have more critical effect on the performance of the functions are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in the library. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing using ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:13:49','2014-06-11 22:13:49','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5829,17729,'2014-06-11 22:17:34','2014-06-11 22:17:34','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The spec comparison of both the GPUs used for benchmarks is given below for your reference(properties that have more critical effect on the performance of the functions are only listed).</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in the library. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing using ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:17:34','2014-06-11 22:17:34','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5830,17729,'2014-06-11 22:17:53','2014-06-11 22:17:53','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The spec comparison of both the GPUs used for benchmarks is given below for your reference (properties that have more critical effect on the performance of the functions are only listed).</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in the library. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing using ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:17:53','2014-06-11 22:17:53','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5831,17729,'2014-06-11 22:21:24','2014-06-11 22:21:24','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The comparision of properties that have critical effect on performance is listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in the library. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing using ArrayFire on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:21:24','2014-06-11 22:21:24','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5832,17729,'2014-06-11 22:23:10','2014-06-11 22:23:10','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The comparision of properties that have critical effect on performance is listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in the library. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:23:10','2014-06-11 22:23:10','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5833,17729,'2014-06-11 22:23:39','2014-06-11 22:23:39','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The comparision of properties that have critical effect on performance is listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <code>erode</code> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in the library. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:23:39','2014-06-11 22:23:39','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5834,17729,'2014-06-11 22:30:38','2014-06-11 22:30:38','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li>Erosion/Dilation<br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:30:38','2014-06-11 22:30:38','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5835,17729,'2014-06-11 22:31:04','2014-06-11 22:31:04','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\">Erosion/Dilation<a><br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:31:04','2014-06-11 22:31:04','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5836,17729,'2014-06-11 22:31:11','2014-06-11 22:31:11','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\">Erosion/Dilation</a><br /></li>\r\n<li>Median filter<br /></li>\r\n<li>Resize<br /></li>\r\n<li>Histogram<br /></li>\r\n<li>Bilateral filter<br /></li>\r\n<li>Convolution</li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:31:11','2014-06-11 22:31:11','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5837,17729,'2014-06-11 22:33:50','2014-06-11 22:33:50','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\">Erosion/Dilation</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\">Median filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\">Resize</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\">Histogram</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\">Bilateral filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\">Convolution</a></li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <code>medfilt</code> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:33:50','2014-06-11 22:33:50','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5838,17729,'2014-06-11 22:34:38','2014-06-11 22:34:38','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\">Erosion/Dilation</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\">Median filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\">Resize</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\">Histogram</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\">Bilateral filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\">Convolution</a></li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\"><code>medfilt</code></a> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <code>resize</code> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <code>histogram</code></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <code>bilateral</code> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <code>convolve</code> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:34:38','2014-06-11 22:34:38','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5839,17729,'2014-06-11 22:35:57','2014-06-11 22:35:57','<p>In this post, we will be looking at benchmarks of the below listed ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\">Erosion/Dilation</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\">Median filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\">Resize</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\">Histogram</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\">Bilateral filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\">Convolution</a></li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\"><code>medfilt</code></a> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\"><code>resize</code></a> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\"><code>histogram</code></a></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\"><code>bilateral</code></a> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\"><code>convolve</code></a> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:35:57','2014-06-11 22:35:57','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5840,17729,'2014-06-11 22:37:10','2014-06-11 22:37:10','<p>In this post, we will be looking at benchmarks of the following ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\">Erosion/Dilation</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\">Median filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\">Resize</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\">Histogram</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\">Bilateral filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\">Convolution</a></li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\"><code>medfilt</code></a> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\"><code>resize</code></a> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\"><code>histogram</code></a></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\"><code>bilateral</code></a> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\"><code>convolve</code></a> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:37:10','2014-06-11 22:37:10','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5841,17729,'2014-06-11 22:43:13','2014-06-11 22:43:13','<p>In this post, we will be looking at benchmarks of the following ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\">Erosion/Dilation</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\">Median filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\">Resize</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\">Histogram</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\">Bilateral filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\">Convolution</a></li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<iframe height=563 width=792 src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=1799759820\" seamless frameborder=0 scrolling=no></iframe>\r\n<!--a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/erode.png\" alt=\"erode\" width=\"640\" height=\"480\" class=\"alignnone size-full wp-image-5805\" /></a-->\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/medfilt.png\" alt=\"medfilt\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5801\" /></a>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\"><code>medfilt</code></a> function as well.</p>\r\n<h4 id=\"resize\">Resize</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/resize.png\" alt=\"resize\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5800\" /></a>\r\n<p>We benchmarked <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\"><code>resize</code></a> for halving the image size.</p>\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/hist.png\" alt=\"hist\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5802\" /></a>\r\n<p>Standard 256 bin <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\"><code>histogram</code></a></p>\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/bilateral.png\" alt=\"bilateral\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5804\" /></a>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\"><code>bilateral</code></a> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/06/conv.png\" alt=\"conv\" width=\"640\" height=\"480\" class=\"alignnone size-medium wp-image-5803\" /></a>\r\n<p>5x5 blur kernel was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\"><code>convolve</code></a> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:43:13','2014-06-11 22:43:13','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),(5842,17729,'2014-06-11 22:49:19','2014-06-11 22:49:19','<p>In this post, we will be looking at benchmarks of the following ArrayFire image processing functions on an ARM device.</p>\r\n<ul>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\">Erosion/Dilation</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\">Median filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\">Resize</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\">Histogram</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\">Bilateral filter</a><br /></li>\r\n<li><a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\">Convolution</a></li>\r\n</ul>\r\n<p>We pitched the brand new compute 3.2 GPU on NVIDIA Jetson TK1 against a mobile NVIDIA GPU. The closest match to the GPU(from here on referred as TK1) on Jetson board we have in our mobile card deck is a NVIDIA GT 650M. The GPU device properties that have critical effect on the function performance are listed below.</p>\r\n<table>\r\n<thead>\r\n<tr class=\"header\">\r\n<th style=\"text-align: left;\">Property Name / Device Name</th>\r\n<th style=\"text-align: left;\">Jetson TK1 GK20A</th>\r\n<th style=\"text-align: left;\">GT 650M</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Compute</td>\r\n<td style=\"text-align: left;\">3.2</td>\r\n<td style=\"text-align: left;\">3.0</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Number of multiprocessors</td>\r\n<td style=\"text-align: left;\">1</td>\r\n<td style=\"text-align: left;\">2</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Cores</td>\r\n<td style=\"text-align: left;\">192</td>\r\n<td style=\"text-align: left;\">384</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Base clock rate</td>\r\n<td style=\"text-align: left;\">852 MHz</td>\r\n<td style=\"text-align: left;\">950 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total global memory</td>\r\n<td style=\"text-align: left;\">1746 MB</td>\r\n<td style=\"text-align: left;\">2048 MB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total shared memory per block</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n<td style=\"text-align: left;\">48 KB</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Total constant memory</td>\r\n<td style=\"text-align: left;\">64 KB</td>\r\n<td style=\"text-align: left;\">64KB</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Memory clock rate</td>\r\n<td style=\"text-align: left;\">924 MHz</td>\r\n<td style=\"text-align: left;\">900 MHz</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Memory bus width</td>\r\n<td style=\"text-align: left;\">64-bit</td>\r\n<td style=\"text-align: left;\">128-bit</td>\r\n</tr>\r\n<tr class=\"even\">\r\n<td style=\"text-align: left;\">Total registers per block</td>\r\n<td style=\"text-align: left;\">32768</td>\r\n<td style=\"text-align: left;\">65536</td>\r\n</tr>\r\n<tr class=\"odd\">\r\n<td style=\"text-align: left;\">Warp size</td>\r\n<td style=\"text-align: left;\">32</td>\r\n<td style=\"text-align: left;\">32</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h3 id=\"benchmarks\">Benchmarks</h3>\r\nImages with the below resolutions are used for benchmarks. \r\n<ul>\r\n<li>480p (720x480)</li>\r\n<li>720p and 1080p HD</li>\r\n<li>4K and 8K UHD</li>\r\n</ul>\r\nNote that the vertical axis(Frames per second) in all the plots is on log scale. The higher the value along vertical axis, the better the run times are for that function on that specific device.\r\n\r\n<h4 id=\"erosiondilation\">Erosion/Dilation</h4>\r\n<iframe height=563 width=792 src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=1799759820\" seamless frameborder=0 scrolling=no></iframe>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__morph__mat.htm\"><code>erode</code></a> function. Dilate results will be similar to erode as they use the same algorithm with different local neighborhood operator.</p>\r\n\r\n<h4 id=\"median-filter\">Median filter</h4>\r\n<iframe height=561 width=794 src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=629321992\" seamless frameborder=0 scrolling=no></iframe>\r\n<p>3x3 mask was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__medfilt.htm\"><code>medfilt</code></a> function as well.</p>\r\n\r\n<h4 id=\"resize\">Resize</h4>\r\n<iframe height=561 width=793 src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=1318972511\" seamless frameborder=0 scrolling=no></iframe>\r\n<p>We benchmarked <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__resize.htm\"><code>resize</code></a> for halving the image size.</p>\r\n\r\n<h4 id=\"histogram\">Histogram</h4>\r\n<iframe height=566 width=794 src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=12968102\" seamless frameborder=0 scrolling=no></iframe>\r\n<p>Standard 256 bin <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__histogram.htm\"><code>histogram</code></a></p>\r\n\r\n<h4 id=\"bilateral-filter\">Bilateral filter</h4>\r\n<iframe height=560 width=792 src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=528280719\" seamless frameborder=0 scrolling=no></iframe>\r\n<p>We used 3.5(7x7 window) spatial variance and 50 chromatic variance to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__func__cpp__bilateral.htm\"><code>bilateral</code></a> function. Note that for the 4320p resolution, we got one frame per second processing speed.</p>\r\n\r\n<h4 id=\"convolution\">Convolution</h4>\r\n<iframe height=563 width=795 src=\"//docs.google.com/a/sandbox.arrayfire.com/spreadsheets/d/1HMKSexMq_G8o8OKtVYq6lpuoezDVNJ2JwNfOS_h-5u8/gviz/chartiframe?oid=905426513\" seamless frameborder=0 scrolling=no></iframe>\r\n<p>5x5 blur kernel was used to benchmark <a href=\"http://www.accelereyes.com/arrayfire/c/group__signal__func__cpp__convolve.htm\"><code>convolve</code></a> function.</p>\r\n\r\n<h3>Conclusion</h3>\r\n<ul>\r\n<li>\r\n    <code>erode</code>, <code>resize</code> and <code>conv</code> run in real time for all resolutions except 8K UHD.\r\n</li>\r\n<li>\r\n    <code>medfilt</code> runs in real time until 1080p HD resolution and falls to interactive rates for 4K UHD.\r\n</li>\r\n<li>\r\n    <code>bilateral</code> runs in real time until 720p HD resolution and falls to interactive rates for 1080p HD.\r\n</li>\r\n<li>\r\n    <code>histogram</code> run times are good enough for it to be used in any photo editing software without noticing any lag for generating image histograms.\r\n</li>\r\n</ul>\r\nThere are plethora of other image processing functions available in ArrayFire. You can find the complete list of the functions available in our documentation <a href=\"http://www.accelereyes.com/arrayfire/c/group__image__mat.htm\">here</a>.','Image Processing Benchmarks on NVIDIA Jetson TK1','','inherit','open','open','','5799-revision-v1','','','2014-06-11 22:49:19','2014-06-11 22:49:19','',5799,'http://sandbox.arrayfire.com/5799-revision-v1/',0,'revision','',0),