forked from hemalshahX/kerasify
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkerasify.py
More file actions
180 lines (136 loc) · 5.32 KB
/
Copy pathkerasify.py
File metadata and controls
180 lines (136 loc) · 5.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import numpy as np
import struct
LAYER_DENSE = 1
LAYER_CONVOLUTION2D = 2
LAYER_FLATTEN = 3
LAYER_ELU = 4
LAYER_ACTIVATION = 5
LAYER_MAXPOOLING2D = 6
LAYER_INPUT = 7
LAYER_MERGE = 8
ACTIVATION_LINEAR = 1
ACTIVATION_RELU = 2
ACTIVATION_SOFTPLUS = 3
def write_floats(file, floats):
"""
Writes floats to file in 1024 chunks. prevents memory explosion
writing very large arrays to disk when calling struct.pack().
"""
step = 1024
written = 0
for i in np.arange(0, len(floats), step):
remaining = min(len(floats) - i, step)
written += remaining
file.write(struct.pack('=%sf' % remaining, *floats[i:i + remaining]))
assert written == len(floats)
def write_strings(file, strings):
"""
Writes strings to file keeping to 4-byte aligned.
"""
file.write(struct.pack('I', len(strings)))
for string in strings:
write_string(file, string)
def write_string(file, string):
"""
Writes strings to file keeping to 4-byte aligned.
"""
length = len(string)
# Round length up to the nearest multiple of 4.
size = (length + 3 % 4)
file.write(struct.pack('I', size))
file.write(struct.pack('%ds' % size, string))
def export_model(model, filename):
with open(filename, 'wb') as f:
def write_activation(activation):
if activation == 'linear':
f.write(struct.pack('I', ACTIVATION_LINEAR))
elif activation == 'relu':
f.write(struct.pack('I', ACTIVATION_RELU))
elif activation == 'softplus':
f.write(struct.pack('I', ACTIVATION_SOFTPLUS))
else:
assert False, 'Unsupported activation type: %s' % activation
# Sequential models hide the Input layer within the first layer's
# inbound nodes and these do not appear in the layer list.
layers = []
layer_map = {}
for layer in model.layers:
for node in layer.inbound_nodes:
for inbound_layer in node.inbound_layers:
#TODO(hemalshah): Handle dependent layers recursively.
if inbound_layer.name not in layer_map:
layer_map[inbound_layer.name] = inbound_layer
layers.append(inbound_layer)
layer_map[layer.name] = layer
layers.append(layer)
num_layers = len(layers)
f.write(struct.pack('I', num_layers))
write_strings(f, model.input_names)
write_strings(f, model.output_names)
for layer in layers:
layer_type = type(layer).__name__
name = layer.name
write_string(f, name)
inbound_layer_names = []
for node in layer.inbound_nodes:
for inbound_layer in node.inbound_layers:
inbound_layer_names.append(inbound_layer.name)
write_strings(f, inbound_layer_names)
if layer_type == 'Dense':
weights = layer.get_weights()[0]
biases = layer.get_weights()[1]
activation = layer.get_config()['activation']
f.write(struct.pack('I', LAYER_DENSE))
f.write(struct.pack('I', weights.shape[0]))
f.write(struct.pack('I', weights.shape[1]))
f.write(struct.pack('I', biases.shape[0]))
weights = weights.flatten()
biases = biases.flatten()
write_floats(f, weights)
write_floats(f, biases)
write_activation(activation)
elif layer_type == 'InputLayer':
f.write(struct.pack('I', LAYER_INPUT))
elif layer_type == 'Merge':
assert layer.concat_axis == -1, ('Only concatenation along batch '
'dimensions implemented')
assert layer.mode == 'concat', 'Only concatenation implemented'
f.write(struct.pack('I', LAYER_MERGE))
elif layer_type == 'Convolution2D':
assert layer.border_mode == 'valid', ('Only border_mode=valid is '
'implemented')
weights = layer.get_weights()[0]
biases = layer.get_weights()[1]
activation = layer.get_config()['activation']
# The kernel is accessed in reverse order. To simplify the C side we'll
# flip the weight matrix for each kernel.
weights = weights[:, :, ::-1, ::-1]
f.write(struct.pack('I', LAYER_CONVOLUTION2D))
f.write(struct.pack('I', weights.shape[0]))
f.write(struct.pack('I', weights.shape[1]))
f.write(struct.pack('I', weights.shape[2]))
f.write(struct.pack('I', weights.shape[3]))
f.write(struct.pack('I', biases.shape[0]))
weights = weights.flatten()
biases = biases.flatten()
write_floats(f, weights)
write_floats(f, biases)
write_activation(activation)
elif layer_type == 'Flatten':
f.write(struct.pack('I', LAYER_FLATTEN))
elif layer_type == 'ELU':
f.write(struct.pack('I', LAYER_ELU))
f.write(struct.pack('f', layer.alpha))
elif layer_type == 'Activation':
activation = layer.get_config()['activation']
f.write(struct.pack('I', LAYER_ACTIVATION))
write_activation(activation)
elif layer_type == 'MaxPooling2D':
assert layer.border_mode == 'valid', ('Only border_mode=valid is '
'implemented')
pool_size = layer.get_config()['pool_size']
f.write(struct.pack('I', LAYER_MAXPOOLING2D))
f.write(struct.pack('I', pool_size[0]))
f.write(struct.pack('I', pool_size[1]))
else:
assert False, 'Unsupported layer type: %s' % layer_type