Skip to content

Commit 86edd92

Browse files
committed
Format with YAPF
Google style, with 92-char line length * 80 is arbitrarily small * 130 is ridiculous * 90-ish is recommended by Raymond Hettinger
1 parent 2b0e93a commit 86edd92

File tree

10 files changed

+96
-58
lines changed

10 files changed

+96
-58
lines changed

demo.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88

99
from morph._models import EasyMnist
1010

11+
1112
def main():
1213
my_model = EasyMnist()
1314
# do one pass through the algorithm
1415
modified = morph.once(my_model)
1516

16-
print(modified) # proof that the thing wasn't tampered with
17+
print(modified) # proof that the thing wasn't tampered with
1718

1819
my_dataloader = DataLoader(TensorDataset(torch.randn(2, 28, 28)))
1920

@@ -23,4 +24,4 @@ def main():
2324

2425

2526
if __name__ == '__main__':
26-
main() # TODO: add commandline arguments?
27+
main() # TODO: add commandline arguments?

morph/_models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
import torch.nn as nn
33
import torch.nn.functional as F
44

5+
56
class EasyMnist(nn.Module):
7+
68
def __init__(self):
79
super().__init__()
810
self.linear1 = nn.Linear(784, 1000)
@@ -13,7 +15,7 @@ def forward(self, x_batch: torch.Tensor):
1315
"""Simple ReLU-based activations through all layers of the DNN.
1416
Simple and effectively deep neural network. No frills.
1517
"""
16-
_input = x_batch.view(-1, 784) # shape for our linear1
18+
_input = x_batch.view(-1, 784) # shape for our linear1
1719
out1 = F.relu(self.linear1(x_batch))
1820
out2 = F.relu(self.linear2(out1))
1921
out3 = F.relu(self.linear3(out2))

morph/layers/sparse.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
_ZERO_TENSOR = torch.tensor(0.)
55

6+
67
def sparsify(tensor: torch.Tensor, threshold: float = 0.0) -> torch.Tensor:
78
"""Sparsify a `tensor` with `0.0` for all values that do not meet the `threshold`.
89
Defaults to rejecting negative numbers.
@@ -18,6 +19,7 @@ def sparsify(tensor: torch.Tensor, threshold: float = 0.0) -> torch.Tensor:
1819
"""
1920
return tensor.where(tensor > threshold, _ZERO_TENSOR)
2021

22+
2123
def percent_waste(layer: nn.Module) -> float:
2224
"""Computes the number of sparse neurons in a weight matrix,
2325
given the supplied layer.

morph/layers/widen.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from ..nn.utils import layer_has_bias
77

8+
89
# NOTE: should factor be {smaller, default at all}?
910
# TODO: Research - is there a better type for layer than nn.Module?
1011
def widen(layer: nn.Module, factor=1.4, in_place=False) -> nn.Module:
@@ -29,24 +30,24 @@ def widen(layer: nn.Module, factor=1.4, in_place=False) -> nn.Module:
2930
# we know that layer.weight.size()[0] is the __output__ dimension in the linear case
3031
output_dim = 0
3132
if isinstance(layer, nn.Linear):
32-
output_dim = layer.weight.size()[0] # FIXME: switch to layer.out_features?
33-
input_dim = layer.weight.size()[1] # FIXME: switch to layer.in_features?
33+
output_dim = layer.weight.size()[0] # FIXME: switch to layer.out_features?
34+
input_dim = layer.weight.size()[1] # FIXME: switch to layer.in_features?
3435
# TODO: other classes, for robustness?
3536
# TODO: Use dictionary look-ups instead, because they're faster?
3637
else:
3738
raise ValueError('unsupported layer type:', type(layer))
38-
39+
3940
logging.debug(f"current dimensions: {(output_dim, input_dim)}")
40-
41-
new_size = round(factor * output_dim + .5) # round up, not down, if we can
42-
41+
42+
new_size = round(factor * output_dim + .5) # round up, not down, if we can
43+
4344
# We're increasing layer width from output_dim to new_size, so let's save that for later
4445
size_diff = new_size - output_dim
4546
# make the difference even, because it's easier to surrond the old weights
4647
if size_diff % 2 == 1: size_diff += 1
47-
48-
with torch.no_grad():
49-
48+
49+
with torch.no_grad():
50+
5051
expanded_weights = _expand_bias_or_weight(layer.weight, size_diff)
5152
expanded_bias = _expand_bias_or_weight(layer.bias, size_diff)
5253

@@ -58,7 +59,9 @@ def widen(layer: nn.Module, factor=1.4, in_place=False) -> nn.Module:
5859
layer.out_features = new_size
5960
layer.weight = p_weights
6061
layer.bias = p_bias
61-
logging.warning('Using experimental "in-place" version. May have unexpected affects on activation.')
62+
logging.warning(
63+
'Using experimental "in-place" version. May have unexpected affects on activation.'
64+
)
6265
return layer
6366
else:
6467
print(f"New shape = {expanded_weights.shape}")
@@ -67,6 +70,7 @@ def widen(layer: nn.Module, factor=1.4, in_place=False) -> nn.Module:
6770
l.bias = p_bias
6871
return l
6972

73+
7074
def _expand_bias_or_weight(t: nn.Parameter, increase: int) -> torch.Tensor:
7175
"""Returns a tensor of shape `t`, with padding values drawn from a Guassian distribution
7276
with \mu = `torch.mean(layer.weight, dim=0)` and \sigma = `torch.std(layer.weight, dim=0)`.
@@ -88,19 +92,19 @@ def _expand_bias_or_weight(t: nn.Parameter, increase: int) -> torch.Tensor:
8892
# take the std and mean so we can sample from that normal distribution
8993
std = torch.std(t, dim=0)
9094
mean = torch.mean(t, dim=0)
91-
95+
9296
# We sandwich the existing tensor between new tensors with tensor.cat(t_0, t_1, ... t_n)
9397
# the data takes the following shape (all at the same dimension)
9498
# [samples * (increase // 2), t.data, more_samples * (increase // 2)],
9599

96100
new_values = torch.normal(mean, std).unsqueeze(0)
97-
101+
98102
for _ in range(increase // 2 - 1):
99103
new_values = torch.cat((torch.normal(mean, std).unsqueeze(0), new_values))
100-
104+
101105
new_values = torch.cat((new_values, t.data))
102-
106+
103107
for _ in range(increase // 2):
104108
new_values = torch.cat((new_values, torch.normal(mean, std).unsqueeze(0)))
105-
109+
106110
return new_values

morph/nn/_morph_net.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,22 @@
22
import torch.nn as nn
33
from torch.utils.data import DataLoader
44

5+
56
class Morph(nn.Module):
67
"""An encapsulation of the benefits of MorphNet, namely:
78
1. automatically shrinking and widening, to produce a new architecture w.r.t. layer widths
89
2. Training of the network, to match (or beat) model performance
910
3.
1011
"""
11-
12+
1213
@classmethod
1314
def shrink_out(cls, child_layer):
1415
new_out = int(child_layer.out_features * percent_waste(child_layer))
1516
return nn.Linear(child_layer.in_features, new_out)
16-
17+
1718
def __init__(self, net: nn.Module, epochs: int, dataloader: DataLoader):
1819
super().__init__()
19-
self.layers = nn.ModuleList([
20-
Morph.shrink_out(c) for c in net.children()
21-
])
20+
self.layers = nn.ModuleList([Morph.shrink_out(c) for c in net.children()])
2221

2322
def run_training(self):
2423
"""Performs the managed training for this instance"""

morph/nn/morph.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import torch.nn as nn
22

3+
34
def once(net: nn.Module, experimental_support=False) -> nn.Module:
45
"""Runs an experimental implementation of the MorphNet algorithm on `net`
56
producing a new network:

morph/nn/shrink.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
11
import torch
22
import torch.nn as nn
33

4-
5-
64
#################### HELPERS ####################
75

6+
87
def _group_layers_by_algo(children_list):
98
"""Group the layers into how they will be acted upon by my implementation of the algorithm:
109
1. First child in the list
1110
2. Slice of all the child, those that are not first nor last
1211
3. Last child in the list
1312
"""
14-
13+
1514
list_len = len(children_list)
16-
15+
1716
# validate input in case I slip up
1817
if list_len < 1:
1918
raise ValueError('Invalid argument:', children_list)
20-
19+
2120
if list_len <= 2:
22-
return children_list # interface?
21+
return children_list # interface?
2322

24-
2523
first = children_list[0]
2624
middle = children_list[1:-1]
2725
last = children_list[-1]
28-
26+
2927
return first, middle, last

morph/nn/utils.py

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,109 @@
11
import torch.nn as nn
22

3+
34
def layer_has_bias(layer: nn.Module) -> bool:
45
return not layer.bias is None
56

7+
68
def make_children_list(children_or_named_children):
79
"""Receives `nn.Module.children()` or `nn.Module.named_children()`.
810
Returns: that generator collected as a list
911
"""
1012
return [c for c in children_or_named_children]
1113

14+
1215
#################### NEW LAYERS ####################
1316

14-
def new_layer(base_layer: nn.Module, type_name: str, in_dim: int, out_dim: int) -> nn.Module:
17+
18+
def new_layer(base_layer: nn.Module, type_name: str, in_dim: int,
19+
out_dim: int) -> nn.Module:
1520

1621
has_bias = layer_has_bias(base_layer)
1722

1823
if layer_is_linear(type_name):
1924
return nn.Linear(in_dim, out_dim, bias=has_bias)
20-
25+
2126
if layer_is_conv2d(type_name):
22-
return nn.Conv2d(in_dim, out_dim, kernel_size=base_layer.kernel_size,
23-
stride=base_layer.stride, bias=has_bias)
27+
return nn.Conv2d(
28+
in_dim,
29+
out_dim,
30+
kernel_size=base_layer.kernel_size,
31+
stride=base_layer.stride,
32+
bias=has_bias)
2433

2534
raise ValueError('User got around type check ;)')
2635

36+
2737
def new_input_layer(base_layer: nn.Module, type_name: str, out_dim: int) -> nn.Module:
2838
has_bias = layer_has_bias(base_layer)
29-
39+
3040
if layer_is_linear(type_name):
3141
return nn.Linear(base_layer.in_features, out_features=out_dim, bias=has_bias)
32-
42+
3343
if layer_is_conv2d(type_name):
34-
return nn.Conv2d(base_layer.in_channels, out_channels=out_dim,
35-
kernel_size=base_layer.kernel_size, stride=base_layer.stride, bias=has_bias)
44+
return nn.Conv2d(
45+
base_layer.in_channels,
46+
out_channels=out_dim,
47+
kernel_size=base_layer.kernel_size,
48+
stride=base_layer.stride,
49+
bias=has_bias)
50+
3651

3752
def new_output_layer(base_layer: nn.Module, type_name: str, in_dim: int) -> nn.Module:
3853
has_bias = layer_has_bias(base_layer)
39-
54+
4055
if layer_is_linear(type_name):
4156
return nn.Linear(in_dim, base_layer.out_features, bias=has_bias)
42-
57+
4358
if layer_is_conv2d(type_name):
44-
return nn.Conv2d(in_dim, base_layer.out_channels,
45-
kernel_size=base_layer.kernel_size, stride=base_layer.stride, bias=has_bias)
59+
return nn.Conv2d(
60+
in_dim,
61+
base_layer.out_channels,
62+
kernel_size=base_layer.kernel_size,
63+
stride=base_layer.stride,
64+
bias=has_bias)
4665

4766

4867
def redo_layer(layer: nn.Module, new_in=None, new_out=None) -> nn.Module:
4968
if new_in is None and new_out is None:
50-
return layer
51-
69+
return layehr
70+
5271
_type = type_name(layer)
5372
if not type_supported(_type):
5473
raise ValueError('Unsupported layer type:', _type)
55-
56-
if new_in is not None and new_out is not None:
74+
75+
received_new_input = new_in is not None
76+
received_new_output = new_out is not None
77+
78+
if received_new_input and received_new_output:
5779
return new_layer(layer, _type, new_in, new_out)
58-
59-
if new_in is not None:
80+
81+
if received_new_input:
6082
# we need a new input dim, but retain the same output dim
6183
return new_output_layer(layer, _type, new_in)
62-
63-
if new_out is not None:
84+
85+
if received_new_output:
6486
# we need a new output dim, but retain the same input dim
6587
return new_input_layer(layer, _type, new_out)
6688

89+
6790
#################### TYPE HELPERS ####################
6891

92+
6993
def layer_is_conv2d(name: str):
7094
return name == 'Conv2d'
7195

96+
7297
def layer_is_linear(name: str):
7398
return name == 'Linear'
7499

100+
75101
def type_name(o):
76102
'''Returns the simplified type name of the given object.
77103
Eases type checking, rather than any(isinstance(some_obj, _type) for _type in [my, types, to, check])
78104
'''
79105
return type(o).__name__
80106

107+
81108
def type_supported(type_name: str) -> bool:
82-
return type_name in ['Conv2d', 'Linear']
109+
return type_name in ['Conv2d', 'Linear']

morph/nn/utils_test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import torch.nn as nn
21
import unittest
2+
import torch.nn as nn
33

44
from .utils import new_input_layer, new_output_layer
55

6+
67
class TestLayer(unittest.TestCase):
8+
79
def test_new_input_layer_only_touches_output_Linear(self):
810
test = new_input_layer(nn.Linear(5, 4), 'Linear', 7)
911
expected = nn.Linear(5, 7)
@@ -25,8 +27,7 @@ def test_new_output_layer_only_touches_output_Linear(self):
2527
"The output dimensions should be unchanged")
2628

2729
def test_new_output_layer_only_changes_input_Conv2d(self):
28-
test = new_output_layer(
29-
nn.Conv2d(3, 12, kernel_size=3, stride=1), 'Conv2d', 6)
30+
test = new_output_layer(nn.Conv2d(3, 12, kernel_size=3, stride=1), 'Conv2d', 6)
3031
expected = nn.Conv2d(6, 12, 3, 1)
3132

3233
self.assertEqual(expected.in_channels, test.in_channels,
@@ -39,8 +40,7 @@ def test_new_output_layer_only_changes_input_Conv2d(self):
3940
"The padding aspect shoud be the same")
4041

4142
def test_new_input_layer_only_changes_output_Conv2d(self):
42-
test = new_input_layer(
43-
nn.Conv2d(3, 12, kernel_size=3, stride=1), 'Conv2d', 16)
43+
test = new_input_layer(nn.Conv2d(3, 12, kernel_size=3, stride=1), 'Conv2d', 16)
4444
expected = nn.Conv2d(3, 16, 3, 1)
4545

4646
self.assertEqual(expected.in_channels, test.in_channels,

setup.cfg

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
[metadata]
2-
description-file = README.md
2+
description-file = README.md
3+
4+
[yapf]
5+
based_on_style = google
6+
column_limit = 92

0 commit comments

Comments
 (0)