{"id":182,"date":"2018-03-19T17:41:27","date_gmt":"2018-03-19T17:41:27","guid":{"rendered":"https:\/\/blogs.mathworks.com\/deep-learning\/?p=182"},"modified":"2021-04-06T15:52:19","modified_gmt":"2021-04-06T19:52:19","slug":"creating-a-dag-network-from-dag-parts","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/deep-learning\/2018\/03\/19\/creating-a-dag-network-from-dag-parts\/","title":{"rendered":"Creating a DAG Network from DAG Parts"},"content":{"rendered":"<div class=\"content\"><p>In my <a href=\"https:\/\/blogs.mathworks.com\/deep-learning\/2018\/02\/14\/create-a-simple-dag-network\/\">14-Feb-2018 blog post<\/a> about creating a simple DAG network, reader Daniel Morris wanted to know if there's a less tedious way, compared to adding layers one at a time, to combine two (or more) DAGs into a network. I asked the development team about this. I learned that, although it is not yet as easy as they would like to make it, one can write a couple of utility functions to make the task easier.<\/p><p>The first utility function, <tt>createLgraphUsingConnections<\/tt>, is used by a new doc example, <a href=\"https:\/\/www.mathworks.com\/help\/deeplearning\/examples\/train-deep-learning-network-to-classify-new-images.html\">Transfer Learning Using GoogLeNet<\/a>, that was added to R2018a. The function is included at the bottom of this blog post.ame)<\/em><\/p><p>The second utility function, <tt>subgraphConnections<\/tt>, is something I wrote for this post. It handles multiple-input and multiple-output situations when merging two DAGs. This function is also at the bottom of this post.<\/p><p>I will illustrate these function by using them to recreate a portion of the structure of GoogLeNet.<\/p><pre class=\"codeinput\">net = googlenet;\r\nplot(net)\r\naxis <span class=\"string\">off<\/span>\r\nxlim([0 5])\r\nylim([45 65])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/deep-learning\/files\/2018\/03\/CreateDAGFromSubgraphsExample_m_01.png\" alt=\"\"> <p>Suppose we make six different sub-DAGs: the input branch, the four branches of inception layer 3a, and the 3a output layer. Here's one way to make these sub-DAGs.<\/p><pre class=\"codeinput\">subdag1 = layerGraph([ <span class=\"keyword\">...<\/span>\r\n    imageInputLayer([224 224 3],<span class=\"string\">'Name'<\/span>,<span class=\"string\">'data'<\/span>)\r\n    convolution2dLayer([7 7],64,<span class=\"string\">'NumChannels'<\/span>,3,<span class=\"string\">'Stride'<\/span>,[2 2],<span class=\"string\">'Padding'<\/span>,[3 3 3 3],<span class=\"string\">'Name'<\/span>,<span class=\"string\">'conv1-7x7_s2'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'conv1-relu_7x7'<\/span>)\r\n    maxPooling2dLayer([3 3],<span class=\"string\">'Stride'<\/span>,[2 2],<span class=\"string\">'Padding'<\/span>,[0 1 0 1],<span class=\"string\">'Name'<\/span>,<span class=\"string\">'pool1-3x3_s2'<\/span>)\r\n    crossChannelNormalizationLayer(5,<span class=\"string\">'K'<\/span>,1,<span class=\"string\">'Name'<\/span>,<span class=\"string\">'pool1-normal'<\/span>)\r\n    convolution2dLayer([1 1],64,<span class=\"string\">'NumChannels'<\/span>,64,<span class=\"string\">'Name'<\/span>,<span class=\"string\">'conv2-3x3_reduce'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'conv2-relu_3x3_reduce'<\/span>)\r\n    convolution2dLayer([3 3],192,<span class=\"string\">'NumChannels'<\/span>,64,<span class=\"string\">'Padding'<\/span>,[1 1 1 1],<span class=\"string\">'Name'<\/span>,<span class=\"string\">'conv2-3x3'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'conv2-relu_3x3'<\/span>)\r\n    crossChannelNormalizationLayer(5,<span class=\"string\">'K'<\/span>,1,<span class=\"string\">'Name'<\/span>,<span class=\"string\">'conv2-norm2'<\/span>)\r\n    maxPooling2dLayer([3 3],<span class=\"string\">'Stride'<\/span>,[2 2],<span class=\"string\">'Name'<\/span>,<span class=\"string\">'pool2-3x3_s2'<\/span>)\r\n    ]);\r\n\r\nsubdag2 = layerGraph([ <span class=\"keyword\">...<\/span>\r\n    convolution2dLayer([1 1],64,<span class=\"string\">'NumChannels'<\/span>,192,<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-1x1'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-relu_1x1'<\/span>)]);\r\n\r\nsubdag3 = layerGraph([ <span class=\"keyword\">...<\/span>\r\n    convolution2dLayer([1 1],96,<span class=\"string\">'NumChannels'<\/span>,192,<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-3x3_reduce'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-relu_3x3_reduce'<\/span>)\r\n    convolution2dLayer([3 3],128,<span class=\"string\">'NumChannels'<\/span>,96,<span class=\"string\">'Padding'<\/span>,[1 1 1 1],<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-3x3'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-relu_3x3'<\/span>)]);\r\n\r\nsubdag4 = layerGraph([ <span class=\"keyword\">...<\/span>\r\n    convolution2dLayer([1 1],16,<span class=\"string\">'NumChannels'<\/span>,192,<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-5x5_reduce'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-relu_5x5_reduce'<\/span>)\r\n    convolution2dLayer([5 5],32,<span class=\"string\">'NumChannels'<\/span>,16,<span class=\"string\">'Padding'<\/span>,[2 2 2 2],<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-5x5'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-relu_5x5'<\/span>)]);\r\n\r\nsubdag5 = layerGraph([ <span class=\"keyword\">...<\/span>\r\n    maxPooling2dLayer([3 3],<span class=\"string\">'Padding'<\/span>,[1 1 1 1],<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-pool'<\/span>)\r\n    convolution2dLayer([1 1],32,<span class=\"string\">'NumChannels'<\/span>,192,<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-pool_proj'<\/span>)\r\n    reluLayer(<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-relu_pool_proj'<\/span>)]);\r\n\r\nsubdag6 = layerGraph(depthConcatenationLayer(4,<span class=\"string\">'Name'<\/span>,<span class=\"string\">'inception_3a-output'<\/span>));\r\n<\/pre><p>Let's combine all of the layers.<\/p><pre class=\"codeinput\">all_layers = [ <span class=\"keyword\">...<\/span>\r\n    subdag1.Layers\r\n    subdag2.Layers\r\n    subdag3.Layers\r\n    subdag4.Layers\r\n    subdag5.Layers\r\n    subdag6.Layers ]\r\n<\/pre><pre class=\"codeoutput\">\r\nall_layers = \r\n\r\n  25x1 Layer array with layers:\r\n\r\n     1   'data'                           Image Input                   224x224x3 images with 'zerocenter' normalization\r\n     2   'conv1-7x7_s2'                   Convolution                   64 7x7x3 convolutions with stride [2  2] and padding [3  3  3  3]\r\n     3   'conv1-relu_7x7'                 ReLU                          ReLU\r\n     4   'pool1-3x3_s2'                   Max Pooling                   3x3 max pooling with stride [2  2] and padding [0  1  0  1]\r\n     5   'pool1-normal'                   Cross Channel Normalization   cross channel normalization with 5 channels per element\r\n     6   'conv2-3x3_reduce'               Convolution                   64 1x1x64 convolutions with stride [1  1] and padding [0  0  0  0]\r\n     7   'conv2-relu_3x3_reduce'          ReLU                          ReLU\r\n     8   'conv2-3x3'                      Convolution                   192 3x3x64 convolutions with stride [1  1] and padding [1  1  1  1]\r\n     9   'conv2-relu_3x3'                 ReLU                          ReLU\r\n    10   'conv2-norm2'                    Cross Channel Normalization   cross channel normalization with 5 channels per element\r\n    11   'pool2-3x3_s2'                   Max Pooling                   3x3 max pooling with stride [2  2] and padding [0  0  0  0]\r\n    12   'inception_3a-1x1'               Convolution                   64 1x1x192 convolutions with stride [1  1] and padding [0  0  0  0]\r\n    13   'inception_3a-relu_1x1'          ReLU                          ReLU\r\n    14   'inception_3a-3x3_reduce'        Convolution                   96 1x1x192 convolutions with stride [1  1] and padding [0  0  0  0]\r\n    15   'inception_3a-relu_3x3_reduce'   ReLU                          ReLU\r\n    16   'inception_3a-3x3'               Convolution                   128 3x3x96 convolutions with stride [1  1] and padding [1  1  1  1]\r\n    17   'inception_3a-relu_3x3'          ReLU                          ReLU\r\n    18   'inception_3a-5x5_reduce'        Convolution                   16 1x1x192 convolutions with stride [1  1] and padding [0  0  0  0]\r\n    19   'inception_3a-relu_5x5_reduce'   ReLU                          ReLU\r\n    20   'inception_3a-5x5'               Convolution                   32 5x5x16 convolutions with stride [1  1] and padding [2  2  2  2]\r\n    21   'inception_3a-relu_5x5'          ReLU                          ReLU\r\n    22   'inception_3a-pool'              Max Pooling                   3x3 max pooling with stride [1  1] and padding [1  1  1  1]\r\n    23   'inception_3a-pool_proj'         Convolution                   32 1x1x192 convolutions with stride [1  1] and padding [0  0  0  0]\r\n    24   'inception_3a-relu_pool_proj'    ReLU                          ReLU\r\n    25   'inception_3a-output'            Depth concatenation           Depth concatenation of 4 inputs\r\n<\/pre><p>Most of the connections in the final DAG already exist in the subDAGs. Let's grab those and combine them into one list of connections.<\/p><pre class=\"codeinput\">all_connections = [ <span class=\"keyword\">...<\/span>\r\n    subdag1.Connections\r\n    subdag2.Connections\r\n    subdag3.Connections\r\n    subdag4.Connections\r\n    subdag5.Connections\r\n    subdag6.Connections]\r\n<\/pre><pre class=\"codeoutput\">\r\nall_connections =\r\n\r\n  19&times;2 table\r\n\r\n                Source                         Destination          \r\n    ______________________________    ______________________________\r\n\r\n    'data'                            'conv1-7x7_s2'                \r\n    'conv1-7x7_s2'                    'conv1-relu_7x7'              \r\n    'conv1-relu_7x7'                  'pool1-3x3_s2'                \r\n    'pool1-3x3_s2'                    'pool1-normal'                \r\n    'pool1-normal'                    'conv2-3x3_reduce'            \r\n    'conv2-3x3_reduce'                'conv2-relu_3x3_reduce'       \r\n    'conv2-relu_3x3_reduce'           'conv2-3x3'                   \r\n    'conv2-3x3'                       'conv2-relu_3x3'              \r\n    'conv2-relu_3x3'                  'conv2-norm2'                 \r\n    'conv2-norm2'                     'pool2-3x3_s2'                \r\n    'inception_3a-1x1'                'inception_3a-relu_1x1'       \r\n    'inception_3a-3x3_reduce'         'inception_3a-relu_3x3_reduce'\r\n    'inception_3a-relu_3x3_reduce'    'inception_3a-3x3'            \r\n    'inception_3a-3x3'                'inception_3a-relu_3x3'       \r\n    'inception_3a-5x5_reduce'         'inception_3a-relu_5x5_reduce'\r\n    'inception_3a-relu_5x5_reduce'    'inception_3a-5x5'            \r\n    'inception_3a-5x5'                'inception_3a-relu_5x5'       \r\n    'inception_3a-pool'               'inception_3a-pool_proj'      \r\n    'inception_3a-pool_proj'          'inception_3a-relu_pool_proj' \r\n\r\n<\/pre><p>Now we have to get the connections that join the various subDAGs together. This is where <tt>subgraphConnections<\/tt> comes in handy.<\/p><p>First, get all the desired connections between the last layer of subDAG 1 and the first layer of subDAGs 2-5.<\/p><pre class=\"codeinput\">new_connections = subgraphConnections(subdag1.Layers(end),<span class=\"keyword\">...<\/span>\r\n    [subdag2.Layers(1) subdag3.Layers(1) subdag4.Layers(1) subdag5.Layers(1)])\r\nall_connections = [all_connections ; new_connections];\r\n<\/pre><pre class=\"codeoutput\">\r\nnew_connections =\r\n\r\n  4&times;2 table\r\n\r\n        Source               Destination       \r\n    ______________    _________________________\r\n\r\n    'pool2-3x3_s2'    'inception_3a-1x1'       \r\n    'pool2-3x3_s2'    'inception_3a-3x3_reduce'\r\n    'pool2-3x3_s2'    'inception_3a-5x5_reduce'\r\n    'pool2-3x3_s2'    'inception_3a-pool'      \r\n\r\n<\/pre><p>Now get the desired connections between the last layer of subDAGs 2-5 and the first (and only) layer of subDAG 6.<\/p><pre class=\"codeinput\">src_layers = [subdag2.Layers(end) subdag3.Layers(end) subdag4.Layers(end) <span class=\"keyword\">...<\/span>\r\n    subdag5.Layers(end)];\r\nnew_connections = subgraphConnections(src_layers,subdag6.Layers(1))\r\n<\/pre><pre class=\"codeoutput\">\r\nnew_connections =\r\n\r\n  4&times;2 table\r\n\r\n               Source                       Destination       \r\n    _____________________________    _________________________\r\n\r\n    'inception_3a-relu_1x1'          'inception_3a-output\/in1'\r\n    'inception_3a-relu_3x3'          'inception_3a-output\/in2'\r\n    'inception_3a-relu_5x5'          'inception_3a-output\/in3'\r\n    'inception_3a-relu_pool_proj'    'inception_3a-output\/in4'\r\n\r\n<\/pre><p>Note that the utility function <tt>subgraphConnections<\/tt> automatically adds the input specifiers for a multiple-input layer.<\/p><pre class=\"codeinput\">new_connections.Destination\r\nall_connections = [all_connections ; new_connections];\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n  4&times;1 cell array\r\n\r\n    {'inception_3a-output\/in1'}\r\n    {'inception_3a-output\/in2'}\r\n    {'inception_3a-output\/in3'}\r\n    {'inception_3a-output\/in4'}\r\n\r\n<\/pre><p>Finally, use <tt>createLgraphUsingConnections<\/tt> to create the merged DAG.<\/p><pre class=\"codeinput\">lgraph = createLgraphUsingConnections(all_layers,all_connections);\r\nplot(lgraph)\r\naxis <span class=\"string\">off<\/span><\/pre>\r\n\r\n<p>\r\n<img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/deep-learning\/files\/2018\/03\/CreateDAGFromSubgraphsExample_m_02.png\" alt=\"\"> \r\n<\/p>\r\n\r\n<p><i>The code below includes the utility functions used above.<\/i><\/p><pre class=\"codeinput\"><span class=\"keyword\">function<\/span> lgraph = createLgraphUsingConnections(layers,connections)\r\n<span class=\"comment\">% lgraph = createLgraphUsingConnections(layers,connections) creates a layer<\/span>\r\n<span class=\"comment\">% graph with the layers in the layer array |layers| connected by the<\/span>\r\n<span class=\"comment\">% connections in |connections|.<\/span>\r\n\r\nlgraph = layerGraph();\r\n<span class=\"keyword\">for<\/span> i = 1:numel(layers)\r\n    lgraph = addLayers(lgraph,layers(i));\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"keyword\">for<\/span> c = 1:size(connections,1)\r\n    lgraph = connectLayers(lgraph,connections.Source{c},connections.Destination{c});\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"keyword\">function<\/span> c = subgraphConnections(src,dest)\r\n<span class=\"keyword\">if<\/span> numel(src) &gt; 1\r\n    dest_name_root = [dest.Name <span class=\"string\">'\/in'<\/span>];\r\n    tmp = cell(numel(src),2);\r\n    <span class=\"keyword\">for<\/span> k = 1:numel(src)\r\n        tmp{k,1} = src(k).Name;\r\n        tmp{k,2} = [dest_name_root num2str(k)];\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">elseif<\/span> numel(dest) &gt; 1\r\n    tmp = cell(numel(dest),2);\r\n    <span class=\"keyword\">for<\/span> k = 1:numel(dest)\r\n        tmp{k,1} = src.Name;\r\n        tmp{k,2} = dest(k).Name;\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\nc = table(tmp(:,1),tmp(:,2),<span class=\"string\">'VariableNames'<\/span>,{<span class=\"string\">'Source'<\/span>,<span class=\"string\">'Destination'<\/span>});\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><script language=\"JavaScript\"> <!-- \r\n    function grabCode_22336fc4409141fb893dfadb5f976caf() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='22336fc4409141fb893dfadb5f976caf ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 22336fc4409141fb893dfadb5f976caf';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2018 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_22336fc4409141fb893dfadb5f976caf()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2018a<br><\/p><\/div><!--\r\n22336fc4409141fb893dfadb5f976caf ##### SOURCE BEGIN #####\r\n%% \r\n% In my <https:\/\/blogs.mathworks.com\/deep-learning\/2018\/02\/14\/create-a-simple-dag-network\/ \r\n% 14-Feb-2018 blog post> about creating a simple DAG network, reader Daniel Morris \r\n% wanted to know if there's a less tedious way, compared to adding layers one \r\n% at a time, to combine two (or more) DAGs into a network. I asked the development \r\n% team about this. I learned that, although it is not yet as easy as they would \r\n% like to make it, one can write a couple of utility functions to make the task \r\n% easier.\r\n% \r\n% The first utility function, |createLgraphUsingConnections|, is used by \r\n% a new doc example, <https:\/\/www.mathworks.com\/examples\/deep-learning\/mw\/nnet-ex74362329-train-deep-learning-network-to-classify-new-images\r\n% Transfer Learning Using GoogLeNet>, that was added to R2018a. The function is \r\n% included at the bottom of this blog post.\r\n% \r\n% The second utility function, |subgraphConnections|, is something I wrote \r\n% for this post. It handles multiple-input and multiple-output situations when \r\n% merging two DAGs. This function is also at the bottom of this post.\r\n% \r\n% I will illustrate these function by using them to recreate a portion of \r\n% the structure of GoogLeNet.\r\n\r\nnet = googlenet;\r\nplot(net)\r\naxis off\r\nxlim([0 5])\r\nylim([45 65])\r\n%% \r\n% Suppose we make six different sub-DAGs: the input branch, the four branches \r\n% of inception layer 3a, and the 3a output layer. Here's one way to make these \r\n% sub-DAGs.\r\n%%\r\nsubdag1 = layerGraph([ ...\r\n    imageInputLayer([224 224 3],'Name','data')\r\n    convolution2dLayer([7 7],64,'NumChannels',3,'Stride',[2 2],'Padding',[3 3 3 3],'Name','conv1-7x7_s2')\r\n    reluLayer('Name','conv1-relu_7x7')\r\n    maxPooling2dLayer([3 3],'Stride',[2 2],'Padding',[0 1 0 1],'Name','pool1-3x3_s2')\r\n    crossChannelNormalizationLayer(5,'K',1,'Name','pool1-normal')\r\n    convolution2dLayer([1 1],64,'NumChannels',64,'Name','conv2-3x3_reduce')\r\n    reluLayer('Name','conv2-relu_3x3_reduce')\r\n    convolution2dLayer([3 3],192,'NumChannels',64,'Padding',[1 1 1 1],'Name','conv2-3x3')\r\n    reluLayer('Name','conv2-relu_3x3')\r\n    crossChannelNormalizationLayer(5,'K',1,'Name','conv2-norm2')\r\n    maxPooling2dLayer([3 3],'Stride',[2 2],'Name','pool2-3x3_s2')\r\n    ]);\r\n\r\nsubdag2 = layerGraph([ ...\r\n    convolution2dLayer([1 1],64,'NumChannels',192,'Name','inception_3a-1x1')\r\n    reluLayer('Name','inception_3a-relu_1x1')]);\r\n\r\nsubdag3 = layerGraph([ ...\r\n    convolution2dLayer([1 1],96,'NumChannels',192,'Name','inception_3a-3x3_reduce')\r\n    reluLayer('Name','inception_3a-relu_3x3_reduce')\r\n    convolution2dLayer([3 3],128,'NumChannels',96,'Padding',[1 1 1 1],'Name','inception_3a-3x3')\r\n    reluLayer('Name','inception_3a-relu_3x3')]);\r\n\r\nsubdag4 = layerGraph([ ...\r\n    convolution2dLayer([1 1],16,'NumChannels',192,'Name','inception_3a-5x5_reduce')\r\n    reluLayer('Name','inception_3a-relu_5x5_reduce')\r\n    convolution2dLayer([5 5],32,'NumChannels',16,'Padding',[2 2 2 2],'Name','inception_3a-5x5')\r\n    reluLayer('Name','inception_3a-relu_5x5')]);\r\n\r\nsubdag5 = layerGraph([ ...\r\n    maxPooling2dLayer([3 3],'Padding',[1 1 1 1],'Name','inception_3a-pool')\r\n    convolution2dLayer([1 1],32,'NumChannels',192,'Name','inception_3a-pool_proj')\r\n    reluLayer('Name','inception_3a-relu_pool_proj')]);\r\n\r\nsubdag6 = layerGraph(depthConcatenationLayer(4,'Name','inception_3a-output'));\r\n%% \r\n% Let's combine all of the layers.\r\n%%\r\nall_layers = [ ...\r\n    subdag1.Layers\r\n    subdag2.Layers\r\n    subdag3.Layers\r\n    subdag4.Layers\r\n    subdag5.Layers\r\n    subdag6.Layers ]\r\n%% \r\n% Most of the connections in the final DAG already exist in the subDAGs. \r\n% Let's grab those and combine them into one list of connections.\r\n%%\r\nall_connections = [ ...\r\n    subdag1.Connections\r\n    subdag2.Connections\r\n    subdag3.Connections\r\n    subdag4.Connections\r\n    subdag5.Connections\r\n    subdag6.Connections]\r\n%% \r\n% Now we have to get the connections that join the various subDAGs together. \r\n% This is where |subgraphConnections| comes in handy.\r\n% \r\n% First, get all the desired connections between the last layer of subDAG \r\n% 1 and the first layer of subDAGs 2-5.\r\n%%\r\nnew_connections = subgraphConnections(subdag1.Layers(end),...\r\n    [subdag2.Layers(1) subdag3.Layers(1) subdag4.Layers(1) subdag5.Layers(1)])\r\nall_connections = [all_connections ; new_connections];\r\n%% \r\n% Now get the desired connections between the last layer of subDAGs 2-5 \r\n% and the first (and only) layer of subDAG 6.\r\n%%\r\nsrc_layers = [subdag2.Layers(end) subdag3.Layers(end) subdag4.Layers(end) ...\r\n    subdag5.Layers(end)];\r\nnew_connections = subgraphConnections(src_layers,subdag6.Layers(1))\r\n%% \r\n% Note that the utility function |subgraphConnections| automatically adds \r\n% the input specifiers for a multiple-input layer.\r\n\r\nnew_connections.Destination\r\nall_connections = [all_connections ; new_connections];\r\n%% \r\n% Finally, use |createLgraphUsingConnections| to create the merged DAG.\r\n%%\r\nlgraph = createLgraphUsingConnections(all_layers,all_connections);\r\nplot(lgraph)\r\naxis off\r\n%% \r\n% _The code below includes the utility functions used above._\r\n%%\r\nfunction lgraph = createLgraphUsingConnections(layers,connections)\r\n% lgraph = createLgraphUsingConnections(layers,connections) creates a layer\r\n% graph with the layers in the layer array |layers| connected by the\r\n% connections in |connections|.\r\n\r\nlgraph = layerGraph();\r\nfor i = 1:numel(layers)\r\n    lgraph = addLayers(lgraph,layers(i));\r\nend\r\n\r\nfor c = 1:size(connections,1)\r\n    lgraph = connectLayers(lgraph,connections.Source{c},connections.Destination{c});\r\nend\r\n\r\nend\r\n\r\nfunction c = subgraphConnections(src,dest)\r\nif numel(src) > 1\r\n    dest_name_root = [dest.Name '\/in'];\r\n    tmp = cell(numel(src),2);\r\n    for k = 1:numel(src)\r\n        tmp{k,1} = src(k).Name;\r\n        tmp{k,2} = [dest_name_root num2str(k)];\r\n    end\r\nelseif numel(dest) > 1\r\n    tmp = cell(numel(dest),2);\r\n    for k = 1:numel(dest)\r\n        tmp{k,1} = src.Name;\r\n        tmp{k,2} = dest(k).Name;\r\n    end\r\nend\r\nc = table(tmp(:,1),tmp(:,2),'VariableNames',{'Source','Destination'});\r\nend\r\n##### SOURCE END ##### 22336fc4409141fb893dfadb5f976caf\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/deep-learning\/files\/2018\/03\/CreateDAGFromSubgraphsExample_m_02.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>In my 14-Feb-2018 blog post about creating a simple DAG network, reader Daniel Morris wanted to know if there's a less tedious way, compared to adding layers one at a time, to combine two (or more)... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/deep-learning\/2018\/03\/19\/creating-a-dag-network-from-dag-parts\/\">read more >><\/a><\/p>","protected":false},"author":42,"featured_media":186,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/posts\/182"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/users\/42"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/comments?post=182"}],"version-history":[{"count":11,"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/posts\/182\/revisions"}],"predecessor-version":[{"id":3094,"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/posts\/182\/revisions\/3094"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/media\/186"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/media?parent=182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/categories?post=182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/deep-learning\/wp-json\/wp\/v2\/tags?post=182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}