Skip to content

Commit 58c08b1

Browse files
author
Robert Muchsel
authored
ConvTranspose2d: Allow pad=0, pad=2 (#111)
* ConvTranspose2d: Allow pad=0, pad=2 * Changes for AI87 * README: Small improvements * Allow 32-bit output for intermediate layers (with warning) * Optimize Conv1d simulation
1 parent 9e06876 commit 58c08b1

File tree

100 files changed

+2278
-297
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+2278
-297
lines changed

.github/linters/.python-lint

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ignored-classes = ModelProto
77
max-line-length = 99
88
[DESIGN]
99
max-locals=100
10-
max-statements=1200
10+
max-statements=1500
1111
min-public-methods=1
1212
max-branches=150
1313
max-module-lines=5000

.pylintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ignored-classes = ModelProto
77
max-line-length = 99
88
[DESIGN]
99
max-locals=100
10-
max-statements=1200
10+
max-statements=1500
1111
min-public-methods=1
1212
max-branches=150
1313
max-module-lines=5000

README.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# MAX78000 Model Training and Synthesis
22

3-
_February 19, 2021_
3+
_March 2, 2021_
44

55
The Maxim Integrated AI project is comprised of four repositories:
66

@@ -204,7 +204,7 @@ Windows/MS-DOS is not supported for training networks at this time. *This includ
204204

205205
### Upstream Code
206206

207-
Change to the project root and run the following commands. Use your GitHub credentials when prompted.
207+
Change to the project root and run the following commands. Use your GitHub credentials if prompted.
208208

209209
```shell
210210
$ cd $AI_PROJECT_ROOT
@@ -318,6 +318,10 @@ $ source bin/activate
318318

319319
Branches and updates for `ai8x-synthesis` are handled similarly to the [`ai8x-training`](#Repository Branches) project.
320320

321+
**Installation is now Complete**
322+
323+
With the installation of Training and Synthesis projects completed it is important to remember to activate the proper Python virtual environment when switching between projects. If scripts begin failing in a previously working environment, the cause might be that the incorrect virtual environment is active or that no virtual environment has been activated.
324+
321325
### Embedded Software Development Kit (SDK)
322326

323327
The MAX78000 SDK is a git submodule of ai8x-synthesis. It is checked out automatically to a version compatible with the project into the folder `sdk`.
@@ -688,7 +692,7 @@ The MAX78000 hardware does not support arbitrary network parameters. Specificall
688692
* `ConvTranspose2d`:
689693

690694
* Kernel sizes must be 3×3.
691-
* Padding must be 1 *(Note: hardware supports additional padding modes, but there is no direct equivalent in PyToch)*.
695+
* Padding can be 0, 1, or 2.
692696
* Stride is fixed to [2, 2]. Output padding is fixed to 1.
693697

694698
* A programmable layer-specific shift operator is available at the output of a convolution, see [`output_shift` (Optional)](#output_shift \(Optional\)).
@@ -1456,13 +1460,9 @@ Example:
14561460

14571461
##### `kernel_size` (Optional)
14581462

1459-
2D convolutions:
1460-
1461-
​ This key must be `3x3` (the default) or `1x1`.
1462-
1463-
1D convolutions:
1464-
1465-
​ This key must be `1` through `9`.
1463+
* For `Conv2D`, this key must be `3x3` (the default) or `1x1`.
1464+
* For `Conv1D`, this key must be `1` through `9`.
1465+
* For `ConvTranspose2D`, this key must be `3x3` (the default).
14661466

14671467
Example:
14681468
`kernel_size: 1x1`
@@ -1477,6 +1477,7 @@ This key must be `1` or `[1, 1]`.
14771477

14781478
* For `Conv2d`, this value can be `0`, `1` (the default), or `2`.
14791479
* For `Conv1d`, the value can be `0`, `1`, `2`, or `3` (the default).
1480+
* For `ConvTranspose2d`, this value can be `0`, `1` (the default), or `2`. *Note that the value follows PyTorch conventions and effectively adds* `(kernel_size – 1) – pad` *amount of zero padding to both sizes of the input, so “0” adds 2 zeros each and “2” adds no padding.*
14801481
* For `Passthrough`, this value must be `0` (the default).
14811482

14821483
##### `max_pool` (Optional)

README.pdf

2.99 KB
Binary file not shown.

izer/checkpoint.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def load(
2929
verbose=False,
3030
no_bias=None,
3131
conv_groups=None,
32+
bypass=None,
3233
):
3334
"""
3435
Load weights and biases from `checkpoint_file`. If `arch` is not None and does not match
@@ -76,7 +77,7 @@ def load(
7677

7778
for _, k in enumerate(checkpoint_state.keys()):
7879
# Skip over non-weight layers
79-
while seq < len(operator) and operator[seq] == opn.NONE:
80+
while seq < len(operator) and (operator[seq] == opn.NONE or bypass[seq]):
8081
seq += 1
8182

8283
operation, parameter = k.rsplit(sep='.', maxsplit=1)

izer/cmsisnn.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ def create_net( # pylint: disable=too-many-arguments,too-many-locals,too-many-b
6262
legacy_test=False,
6363
):
6464
"""
65-
Create the CMSIS NN network.
65+
Create the CMSIS-NN network.
6666
"""
6767
wprint('CMSIS-NN code generation is unsupported.')
6868

6969
if output_width[-1] != 8:
70-
wprint('CMSIS network generator does not currently support `output_width` that is not 8. '
71-
'Forcing to 8 bit.') # FIXME: Support 32-bit output
70+
wprint('CMSIS-NN network generator does not currently support `output_width` that '
71+
'is not 8. Forcing to 8 bit.') # FIXME: Support 32-bit output
7272
output_width[-1] = 8
7373

7474
input_dim_str = [None] * layers
@@ -83,7 +83,7 @@ def create_net( # pylint: disable=too-many-arguments,too-many-locals,too-many-b
8383
if quantization[ll] is None:
8484
quantization[ll] = 8 # Set default
8585
elif quantization[ll] != 8: # FIXME: Support quantization
86-
eprint('CMSIS network generator does not currently support `quantization` != 8.')
86+
eprint('CMSIS-NN network generator does not currently support `quantization` != 8.')
8787

8888
if output_shift[ll] is None:
8989
output_shift[ll] = 0 # Set default

izer/commandline.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ def get_parser():
123123
help="start processing before first FIFO push (default: false)")
124124
group.add_argument('--slow-load', type=int, metavar='N', default=0,
125125
help="slow down FIFO loads (default: 0)")
126+
group.add_argument('--debug-new-streaming', action='store_true', default=True,
127+
help="modify streaming equation (default: false)")
126128

127129
# RISC-V
128130
group = parser.add_argument_group('RISC-V')
@@ -155,7 +157,8 @@ def get_parser():
155157
group.add_argument('--log-pooling', action='store_true', default=False,
156158
help="log unpooled and pooled data between layers in CSV format "
157159
"(default: false)")
158-
group.add_argument('--log-last-only', action='store_false', dest='verbose_all', default=True,
160+
group.add_argument('--log-last-only', '--verbose-all',
161+
action='store_false', dest='verbose_all', default=True,
159162
help="log data for last layer only (default: all layers)")
160163
group.add_argument('--log-filename', default='log.txt', metavar='S',
161164
help="log file name (default: 'log.txt')")
@@ -200,6 +203,8 @@ def get_parser():
200203
help="do not force `bias_group` to use an active group (default: false)")
201204
group.add_argument('--kernel-format', default='{0:4}', metavar='S',
202205
help="print format for kernels (default: '{0:4}')")
206+
group.add_argument('--debug-snoop', action='store_true', default=False,
207+
help="insert snoop register debug code (default: False)")
203208

204209
# RTL sim
205210
group = parser.add_argument_group('RTL simulation')

izer/compute.py

Lines changed: 91 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ def conv2d(
102102
nweight[:, :, 0::dilation[0], 0::dilation[1]] = weight
103103
weight = nweight
104104

105-
h = (data.shape[1] - weight.shape[3] + 1) // stride[0] # Resulting output height
106-
w = (data.shape[2] - weight.shape[2] + 1) // stride[1] # Resulting output width
105+
h = (data.shape[1] - weight.shape[3]) // stride[0] + 1 # Resulting output height
106+
w = (data.shape[2] - weight.shape[2]) // stride[1] + 1 # Resulting output width
107107

108108
view = as_strided(data,
109109
shape=(h, w, data.shape[0], weight.shape[2], weight.shape[3]),
@@ -177,57 +177,114 @@ def conv1d(
177177
bias,
178178
input_size,
179179
output_size,
180-
out_channels,
181180
kernel_size,
182181
stride,
183182
pad,
184183
dilation,
184+
fractional_stride=1,
185+
output_pad=0,
185186
groups=1,
186-
debug=False,
187+
debug=False, # pylint: disable=unused-argument
187188
):
188189
"""
189190
Compute a 1D convolution.
190191
191192
Note that all PyTorch numbers are ordered (C, L)
192193
"""
194+
assert data.shape == tuple(input_size)
193195
in_channels = input_size[0]
196+
out_channels = output_size[0]
194197

195198
weight = weight.reshape(out_channels, input_size[0] // groups, -1)
196199
data = data.reshape(input_size[0], -1)
197200

198201
output = np.full(shape=(output_size[0], output_size[1]),
199202
fill_value=np.nan, dtype=np.int64)
200203

201-
# Compute 1D convolution
202-
if debug:
203-
debug_print('k,c,x,src_offs,wt_offs,weight,data,acc')
204-
for k in range(out_channels):
205-
out_offs = 0
206-
for x in range(-pad, input_size[1] - dilation * (kernel_size - 1) + pad, stride):
207-
val = np.int64(0)
208-
for c in range(in_channels // groups):
209-
dc = c if groups == 1 else c + k * (in_channels // groups)
210-
for w in range(kernel_size):
211-
src_offs = x + w * dilation
212-
if 0 <= src_offs < input_size[1]:
213-
val += weight[k][c][w] * data[dc][src_offs]
214-
stats.true_macc += 1
215-
if debug:
216-
debug_print(
217-
f'{k},{c},{x},{src_offs},{w},{weight[k][c][w]},'
218-
f'{data[dc][src_offs]},{val}'
219-
)
220-
221-
if bias is not None:
222-
val += bias[k]
223-
if debug:
224-
debug_print(
225-
f'+bias {bias[k]} --> output[{k}][{out_offs}] = {val}',
226-
)
227-
output[k][out_offs] = val
228-
out_offs += 1
229-
230-
return output.reshape((output_size))
204+
# Stretch data for fractionally-strided convolution
205+
if fractional_stride > 1:
206+
ndata = np.zeros((data.shape[0],
207+
data.shape[1] * fractional_stride - 1),
208+
dtype=data.dtype)
209+
ndata[:, 0::fractional_stride] = data
210+
data = ndata
211+
212+
# Create zero padding around data
213+
if pad or output_pad:
214+
data = np.pad(data, pad_width=((0, 0), (pad, pad + output_pad)),
215+
mode='constant', constant_values=0)
216+
217+
if dilation > 1:
218+
# Stretch weights for dilation
219+
nweight = np.zeros((weight.shape[0], weight.shape[1],
220+
(kernel_size - 1) * dilation + 1),
221+
dtype=weight.dtype)
222+
nweight[:, :, 0::dilation] = weight
223+
weight = nweight
224+
225+
ll = (data.shape[1] - weight.shape[2]) // stride + 1 # Resulting output length
226+
227+
view = as_strided(data,
228+
shape=(ll, data.shape[0], weight.shape[2]),
229+
strides=((data.strides[1] * stride,
230+
data.strides[0], data.strides[1])),
231+
writeable=False)
232+
233+
if groups > 1:
234+
nweight = np.zeros((weight.shape[0], in_channels, weight.shape[2]),
235+
dtype=weight.dtype)
236+
for i in range(weight.shape[0]):
237+
for j in range(in_channels // groups):
238+
nweight[i, i * (in_channels // groups) + j, :] = weight[i, j, :]
239+
weight = nweight
240+
241+
output = np.tensordot(view, weight, axes=((1, 2), (1, 2))).transpose(1, 0)
242+
243+
# Apply bias
244+
if bias is not None:
245+
for k in range(out_channels):
246+
output[k] += bias[k]
247+
248+
assert output.shape == tuple(output_size[:2]), \
249+
f'Shape mismatch: NumPy result {output.shape} vs expected {tuple(output_size[:2])}.'
250+
251+
return output
252+
253+
254+
def convtranspose1d(
255+
data,
256+
weight,
257+
bias,
258+
input_size,
259+
output_size,
260+
kernel_size,
261+
stride,
262+
pad,
263+
dilation,
264+
fractional_stride,
265+
output_pad,
266+
groups=1,
267+
debug=False,
268+
):
269+
"""
270+
Compute a transposed 1D convolution.
271+
"""
272+
273+
return conv1d(
274+
data,
275+
weight,
276+
bias,
277+
input_size,
278+
output_size,
279+
kernel_size,
280+
stride,
281+
dilation * (kernel_size - 1) - pad,
282+
dilation,
283+
fractional_stride=fractional_stride,
284+
output_pad=output_pad,
285+
groups=groups,
286+
debug=debug,
287+
)
231288

232289

233290
def linear(

0 commit comments

Comments
 (0)