Skip to content

Commit

Permalink
Fixed ordering of values to keras convention
Browse files Browse the repository at this point in the history
  • Loading branch information
tqml committed Mar 4, 2020
1 parent ecfc73c commit 6f74b3c
Show file tree
Hide file tree
Showing 17 changed files with 16,358 additions and 16,294 deletions.
30 changes: 30 additions & 0 deletions net/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Neural Network Training

The training can be done with either Pytorch or Keras, but Pytorch is recommended because of the unreliable
API of Tensorflow (the foundation of Keras)

Make sure you install all requirements:

````shell script
pip install -r requirements.txt
````

To train the network simply run in a terminal:

```shell script

python train_torch.py
python quantize.py

```

or use the Jupyter notebook to train the network.

## Quantisiation

For quantisation fixed point quantisation has been used.

| Network | Accuracy |
|----------------------|---------:|
| Network: | 0.9832 |
| Quantised Network: | 0.9349 |
116 changes: 3 additions & 113 deletions net/extract_net_parameters.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
import numpy as np
import os
import torch
import keras
import shutil

# The line below is needed so that torch.load() works as expected
from train_torch import LeNetV2, ConvBN, LinearRelu, Flatten

# Chose if you want to use the training parameters from Keras or Torch
from train_keras import load_keras
from train_torch import save_torch_model_weights, load_torch

EXTRACT_FROM_KERAS = True
EXTRACT_FROM_TROCH = True

EXPORT_DIR = 'np'

SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))

KERAS_SAVE_DIR = 'keras'
KERAS_CONFIG_FILE = os.path.join(KERAS_SAVE_DIR, 'model_config.json')
KERAS_WEIGHTS_FILE = os.path.join(KERAS_SAVE_DIR, 'weights.h5')

TORCH_SAVE_DIR = os.path.join(SCRIPT_PATH, 'torch')
TORCH_SAVE_FILE = os.path.join(TORCH_SAVE_DIR, 'LeNet.pth')
TORCH_STATES_SAVE_FILE = os.path.join(TORCH_SAVE_DIR, 'LeNetStates.pth')


def extract(cleanup=True, extract_keras=EXTRACT_FROM_KERAS, extract_torch=EXTRACT_FROM_TROCH):
# Clean up and create dirs
Expand All @@ -45,107 +37,5 @@ def extract(cleanup=True, extract_keras=EXTRACT_FROM_KERAS, extract_torch=EXTRAC
save_torch_model_weights(tmodel)


def save_torch_model_weights(tmodel):
tmodel.eval() # Put in eval mode
for key, weights in tmodel.state_dict().items():
weights = weights.numpy()
vals = weights.flatten(order='C')
np.savetxt(os.path.join(EXPORT_DIR, 't_{}.txt'.format(key)), vals,
header=str(weights.shape))


def load_torch(filepath=TORCH_SAVE_FILE):
from train_torch import get_lenet_model

# Create a model instance, make sure that save data and source code is in sync
# model = get_lenet_model()
# model.load_state_dict(torch.load(TORCH_STATES_SAVE_FILE))

# ToDo: Better way would be the line below but it doesnt work for me :(
model = torch.load(filepath)

return model


def load_keras() -> keras.Model:
if not os.path.exists(KERAS_CONFIG_FILE) or not os.path.exists(KERAS_WEIGHTS_FILE):
raise RuntimeError("There is no trained model data! (or the model might have the wrong filename?)")

# Reload the model from the 2 files we saved
with open(KERAS_CONFIG_FILE) as json_file:
json_config = json_file.read()

model = keras.models.model_from_json(json_config)
model.load_weights(KERAS_WEIGHTS_FILE)
return model


def _read_np_tensor(weight_file):
with open(weight_file) as f:
init_line = f.readline()

# assume the first line is a comment
assert init_line[0] == '#'
p1 = init_line.find('(')
p2 = init_line.find(')')
dims = [int(ds) for ds in init_line[p1 + 1:p2].split(sep=',') if len(ds) > 0]

return np.loadtxt(weight_file).reshape(dims)


def reorder(x):
co, ci, h, w, = x.shape
x_ = np.zeros(shape=(h, w, ci, co), dtype=x.dtype)

for hx in range(h):
for wx in range(w):
for cix in range(ci):
for cox in range(co):
x_[hx, wx, cix, cox] = x[cox, cix, hx, wx]
return x_


def read_np_torch(ordering='BCHW', target_dtype=None):
d = {
'cn1.b': _read_np_tensor('np/t_0.0.bias.txt'),
'cn1.k': _read_np_tensor('np/t_0.0.weight.txt'),
'cn2.b': _read_np_tensor('np/t_3.0.bias.txt'),
'cn2.k': _read_np_tensor('np/t_3.0.weight.txt'),
'fc1.b': _read_np_tensor('np/t_7.0.bias.txt'),
'fc1.w': _read_np_tensor('np/t_7.0.weight.txt'),
'fc2.b': _read_np_tensor('np/t_9.0.bias.txt'),
'fc2.w': _read_np_tensor('np/t_9.0.weight.txt'),
}

if ordering is 'BCHW':
pass
elif ordering is 'BHWC':
k1 = np.moveaxis(d['cn1.k'], [0, 1], [3, 2])
k2 = np.moveaxis(d['cn2.k'], [0, 1], [3, 2])

# k1 = reorder(d['cn1.k'])
# k2 = reorder(d['cn2.k'])

assert k1[1, 2, 0, 4] == d['cn1.k'][4, 0, 1, 2]
assert k2[1, 2, 3, 4] == d['cn2.k'][4, 3, 1, 2]

d['cn1.k'] = k1
d['cn2.k'] = k2
d['fc1.w'] = np.moveaxis(d['fc1.w'], 0, 1)
d['fc2.w'] = np.moveaxis(d['fc2.w'], 0, 1)



else:
raise NotImplementedError('Expected ordering to be "BCHW" or "BHWC" but is: {}'.format(ordering))

if target_dtype is not None:
d_old = d
d = {}
for key, values in d_old.items():
d[key] = values.astype(target_dtype)
return d


if __name__ == '__main__':
extract()
Binary file added net/final_weights/cn1.b.npy
Binary file not shown.
Binary file added net/final_weights/cn1.k.npy
Binary file not shown.
Binary file added net/final_weights/cn2.b.npy
Binary file not shown.
Binary file added net/final_weights/cn2.k.npy
Binary file not shown.
Binary file added net/final_weights/fc1.b.npy
Binary file not shown.
Binary file added net/final_weights/fc1.w.npy
Binary file not shown.
Loading

0 comments on commit 6f74b3c

Please sign in to comment.