From 66170ed3aefd3d0917272dfb32eeb1c62f812b25 Mon Sep 17 00:00:00 2001 From: Stephen Fox Date: Thu, 7 Feb 2019 09:02:55 -0500 Subject: [PATCH] Publicize percent_waste() and format with yapf --- README.md | 8 +++++- morph/layers/__init__.py | 2 +- morph/layers/sparsify.py | 16 ++++++++++++ morph/nn/shrink.py | 17 ------------- morph/nn/utils_test.py | 53 +++++++++++++++++++++++++++++++--------- setup.py | 4 +-- 6 files changed, 67 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 94c1e7a..3236c81 100755 --- a/README.md +++ b/README.md @@ -1 +1,7 @@ -A crafty implementation of Google's [MorphNet](https://arxiv.org/abs/1711.06798) (and derivative iterations) in PyTorch. \ No newline at end of file +A crafty implementation of Google's [MorphNet](https://arxiv.org/abs/1711.06798) (and derivative iterations) in PyTorch. + +This API is undergoing wild changes as it approaches release. +* Almost every change will be a breaking change. +* __Do not__ rely on the functions as they currently are + +Please feel free to look around, but bookmark which release tag it was. Master will be changing, viciously. \ No newline at end of file diff --git a/morph/layers/__init__.py b/morph/layers/__init__.py index f19d0c5..e035cd0 100644 --- a/morph/layers/__init__.py +++ b/morph/layers/__init__.py @@ -1,2 +1,2 @@ -from .sparsify import sparsify +from .sparsify import * from .widen import widen \ No newline at end of file diff --git a/morph/layers/sparsify.py b/morph/layers/sparsify.py index d24c9bf..01a518e 100644 --- a/morph/layers/sparsify.py +++ b/morph/layers/sparsify.py @@ -1,4 +1,5 @@ import torch +import torch.nn as nn _ZERO_TENSOR = torch.tensor(0.) @@ -16,3 +17,18 @@ def sparsify(tensor: torch.Tensor, threshold: float = 0.0) -> torch.Tensor: `torch.Tensor` of the same dimensions as `tensor` """ return tensor.where(tensor > threshold, _ZERO_TENSOR) + +def percent_waste(layer: nn.Module) -> float: + """Computes the number of sparse neurons in a weight matrix, + given the supplied layer. + + Return: percentage as a float. Multiply with the `n` of an `m` x `n` + weight matrix/tensor to determine how many neurons can be spared + """ + w = layer.weight + non_sparse_w = torch.nonzero(sparsify(w)) + non_zero_count = non_sparse_w.numel() // len(non_sparse_w[0]) + + percent_size = non_zero_count / w.numel() + + return percent_size \ No newline at end of file diff --git a/morph/nn/shrink.py b/morph/nn/shrink.py index ec8ab83..ad07d65 100644 --- a/morph/nn/shrink.py +++ b/morph/nn/shrink.py @@ -1,5 +1,3 @@ -from ..layers.sparsify import sparsify - import torch import torch.nn as nn @@ -29,18 +27,3 @@ def _group_layers_by_algo(children_list): last = children_list[-1] return first, middle, last - -def _percent_waste(layer: nn.Module) -> float: - """Computes the number of sparse neurons in a weight matrix, - given the supplied layer. - - Return: percentage as a float. Multiply with the `n` of an `m` x `n` - weight matrix/tensor to determine how many neurons can be spared - """ - w = layer.weight - non_sparse_w = torch.nonzero(sparsify(w)) - non_zero_count = non_sparse_w.numel() // len(non_sparse_w[0]) - - percent_size = non_zero_count / w.numel() - - return percent_size \ No newline at end of file diff --git a/morph/nn/utils_test.py b/morph/nn/utils_test.py index 73a9a50..61c71a1 100644 --- a/morph/nn/utils_test.py +++ b/morph/nn/utils_test.py @@ -3,27 +3,56 @@ from utils import new_input_layer, new_output_layer + class TestLayer(unittest.TestCase): - - def test_new_input_layer_only_touches_output(self): + def test_new_input_layer_only_touches_output_Linear(self): test = new_input_layer(nn.Linear(5, 4), 'Linear', 7) expected = nn.Linear(5, 7) - + self.assertEqual(expected.out_features, test.out_features, - "Changing the output dimension should be successful") - + "Changing the output dimension should be successful") + self.assertEqual(expected.in_features, test.in_features, - "The input dimensions should be unchanged") - - def test_new_output_layer_only_touches_output(self): + "The input dimensions should be unchanged") + + def test_new_output_layer_only_touches_output_Linear(self): test = new_output_layer(nn.Linear(5, 4), 'Linear', 7) expected = nn.Linear(7, 4) - + self.assertEqual(expected.in_features, test.in_features, - "Changing the input dimension should be successful") - + "Changing the input dimension should be successful") + self.assertEqual(expected.out_features, test.out_features, - "The output dimensions should be unchanged") + "The output dimensions should be unchanged") + + def test_new_output_layer_only_changes_input_Conv2d(self): + test = new_output_layer( + nn.Conv2d(3, 12, kernel_size=3, stride=1), 'Conv2d', 6) + expected = nn.Conv2d(6, 12, 3, 1) + + self.assertEqual(expected.in_channels, test.in_channels, + "The input dimension should be the same") + + self.assertEqual(expected.out_channels, test.out_channels, + "The output dimension should be the same") + + self.assertEqual(expected.padding, test.padding, + "The padding aspect shoud be the same") + + def test_new_input_layer_only_changes_output_Conv2d(self): + test = new_input_layer( + nn.Conv2d(3, 12, kernel_size=3, stride=1), 'Conv2d', 16) + expected = nn.Conv2d(3, 16, 3, 1) + + self.assertEqual(expected.in_channels, test.in_channels, + "The input dimension should be the same") + + self.assertEqual(expected.out_channels, test.out_channels, + "The output dimension should be the same") + + self.assertEqual(expected.padding, test.padding, + "The padding aspect shoud be the same") + if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/setup.py b/setup.py index 3689879..96ed333 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ name='morph-py', # How you named your package folder (MyLib) packages=['morph'], # Chose the same as "name" # Start with a small number and increase it with every change you make - version='0.0.2-alpha', + version='0.0.3-alpha', # Chose a license from here: https://help.github.com/articles/licensing-a-repository license='GNU', # Give a short description about your library @@ -19,7 +19,7 @@ # Provide either the link to your github or to your website url='https://github.com/stephenjfox/Morph.py', # I explain this later on - download_url='https://github.com/stephenjfox/Morph.py/archive/v0.0.2.tar.gz', + download_url='https://github.com/stephenjfox/Morph.py/archive/v0.0.3.tar.gz', keywords=[ 'machine learning', 'deep learning', 'nas', 'architecture', 'neural networks'