.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "getting-started/tutorials/05_common_transformations.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_getting-started_tutorials_05_common_transformations.py: PC Structural Transformation Functions ====================================== In this tutorial, you will learn how to use the built-in structural transformation algorithms to easily create and manipulate PCs. .. GENERATED FROM PYTHON SOURCE LINES 7-10 .. code-block:: Python # sphinx_gallery_thumbnail_path = 'imgs/juice.png' .. GENERATED FROM PYTHON SOURCE LINES 11-12 Let's start by importing the necessary packages. .. GENERATED FROM PYTHON SOURCE LINES 12-17 .. code-block:: Python import torch import pyjuice as juice import pyjuice.nodes.distributions as dists .. GENERATED FROM PYTHON SOURCE LINES 18-20 Clone a PC ---------- .. GENERATED FROM PYTHON SOURCE LINES 22-24 :code:`pyjuice.deepcopy` allows us to clone a PC, with some options to manipulate the copy. Let's start by defining a PC. .. GENERATED FROM PYTHON SOURCE LINES 24-38 .. code-block:: Python with juice.set_block_size(block_size = 4): i00 = juice.inputs(0, num_node_blocks = 8, dist = dists.Categorical(num_cats = 5)) i10 = juice.inputs(1, num_node_blocks = 8, dist = dists.Categorical(num_cats = 5)) i11 = juice.inputs(1, num_node_blocks = 8, dist = dists.Categorical(num_cats = 5)) ms0 = juice.multiply(i00, i10) ms1 = juice.multiply(i00, i11) ns = juice.summate(ms0, ms1, num_node_blocks = 1) ns.init_parameters() .. GENERATED FROM PYTHON SOURCE LINES 39-40 To create an independent copy of :code:`ns`, we can run: .. GENERATED FROM PYTHON SOURCE LINES 40-43 .. code-block:: Python new_ns1 = juice.deepcopy(ns) .. GENERATED FROM PYTHON SOURCE LINES 44-45 By setting :code:`tie_params` to :code:`True`, we can tie the parameters of the original PC with that of the copied PC. Note that tied parameters will remain the same during all transformation/learning procedures implemented in PyJuice. .. GENERATED FROM PYTHON SOURCE LINES 45-48 .. code-block:: Python new_ns2 = juice.deepcopy(ns, tie_params = True) .. GENERATED FROM PYTHON SOURCE LINES 49-50 By providing a :code:`var_mapping`, we can define the copied PC on another set of variables. .. GENERATED FROM PYTHON SOURCE LINES 50-54 .. code-block:: Python var_mapping = {0: 2, 1: 3} new_ns3 = juice.deepcopy(ns, var_mapping = var_mapping) .. GENERATED FROM PYTHON SOURCE LINES 55-56 Note that :code:`tie_params` and :code:`var_mapping` can be used simultaneously: .. GENERATED FROM PYTHON SOURCE LINES 56-59 .. code-block:: Python new_ns3 = juice.deepcopy(ns, tie_params = True, var_mapping = var_mapping) .. GENERATED FROM PYTHON SOURCE LINES 60-62 Merge PCs --------- .. GENERATED FROM PYTHON SOURCE LINES 64-66 :code:`juice.merge` can be used to collapse vectors of nodes defined on the same variable scope into a single vector of nodes. Take the following PC as an example: .. GENERATED FROM PYTHON SOURCE LINES 66-79 .. code-block:: Python with juice.set_block_size(block_size = 4): i00 = juice.inputs(0, num_node_blocks = 8, dist = dists.Categorical(num_cats = 5)) i01 = juice.inputs(0, num_node_blocks = 8, dist = dists.Categorical(num_cats = 5)) i10 = juice.inputs(1, num_node_blocks = 8, dist = dists.Categorical(num_cats = 5)) i11 = juice.inputs(1, num_node_blocks = 8, dist = dists.Categorical(num_cats = 5)) ms00 = juice.multiply(i00, i10) ms01 = juice.multiply(i01, i11) ns = juice.summate(ms00, ms01, num_node_blocks = 1, block_size = 1) .. GENERATED FROM PYTHON SOURCE LINES 80-82 In the above PC (i.e., :code:`ns`), :code:`i00` and :code:`i01` (also :code:`i10` and :code:`i11`) can be merged into a single object since they define on the same variable and has the same distribution. :code:`juice.merge` outputs an equivalent PC with the objects properly merged: .. GENERATED FROM PYTHON SOURCE LINES 82-85 .. code-block:: Python new_ns1 = juice.merge(ns) .. GENERATED FROM PYTHON SOURCE LINES 86-87 Another usage of the merge function is to "concatenate" nodes defined by multiple PyJuice objects, if they are defined on the same set of variables. .. GENERATED FROM PYTHON SOURCE LINES 87-93 .. code-block:: Python ns0 = juice.summate(ms00, num_node_blocks = 8, block_size = 4) ns1 = juice.summate(ms01, num_node_blocks = 8, block_size = 4) new_ns2 = juice.merge(ns0, ns1) .. GENERATED FROM PYTHON SOURCE LINES 94-95 :code:`new_ns2` will also be equivalent to :code:`ns`. .. GENERATED FROM PYTHON SOURCE LINES 97-99 Adjust block sizes ------------------ .. GENERATED FROM PYTHON SOURCE LINES 101-103 In the second tutorial (i.e., "Construct Simple PCs"), we mentioned that defining PCs with large :code:`block_size` is crucial to their efficiency. While the best practice is to set high block sizes manually whenever possible, we provide :code:`pyjuice.blockify` to try bumping the group size of all vectors of nodes within a PC. .. GENERATED FROM PYTHON SOURCE LINES 103-122 .. code-block:: Python with juice.set_block_size(block_size = 2): ni0 = juice.inputs(0, num_node_blocks = 2, dist = dists.Categorical(num_cats = 2)) ni1 = juice.inputs(1, num_node_blocks = 2, dist = dists.Categorical(num_cats = 2)) ni2 = juice.inputs(2, num_node_blocks = 2, dist = dists.Categorical(num_cats = 2)) ni3 = juice.inputs(3, num_node_blocks = 2, dist = dists.Categorical(num_cats = 2)) ms1 = juice.multiply(ni0, ni1, edge_ids = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1]], dtype = torch.long)) ns1 = juice.summate(ms1, edge_ids = torch.tensor([[0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 2, 3, 0, 1, 2, 3]], dtype = torch.long)) ms2 = juice.multiply(ni2, ni3, edge_ids = torch.tensor([[0, 0], [1, 1]], dtype = torch.long)) ns2 = juice.summate(ms2, edge_ids = torch.tensor([[0, 0, 1, 1], [0, 1, 0, 1]], dtype = torch.long)) ms = juice.multiply(ns1, ns2, edge_ids = torch.tensor([[0, 0], [1, 1]], dtype = torch.long)) ns = juice.summate(ms, edge_ids = torch.tensor([[0, 0], [0, 1]], dtype = torch.long), block_size = 1) ns.init_parameters() .. GENERATED FROM PYTHON SOURCE LINES 123-125 While the block sizes of the above-defined PC is 2 (except for the root node), :code:`ns1` could have block size 4 since every pair of 4 aligned sum nodes in :code:`ns1` and 4 aligned child nodes are fully connected. To apply such change, we can use: .. GENERATED FROM PYTHON SOURCE LINES 125-128 .. code-block:: Python new_ns = juice.blockify(ns, sparsity_tolerance = 0.25, max_target_block_size = 32) .. GENERATED FROM PYTHON SOURCE LINES 129-130 There are two parameters to the function. :code:`max_target_block_size` specifies the maximum block size to be considered; :code:`sparsity_tolerance` specifies what fraction of pseudo-edges do we allow to add in order to increase the block size even if some pairs of parent and child node blocks are neither fully-connected nor unconnected. .. _sphx_glr_download_getting-started_tutorials_05_common_transformations.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 05_common_transformations.ipynb <05_common_transformations.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 05_common_transformations.py <05_common_transformations.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 05_common_transformations.zip <05_common_transformations.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_