diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa84fd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +weights +venv diff --git a/README.md b/README.md index e838884..a28dfdb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,17 @@ production ready to use in real device. It can be easily extended to be used wit different neural net structure. ## Requirements -Python 3.5, Tensorflow 1.4.0, Keras 2.1.3 +Python 3.10, libraries listed in requirements.txt + +## Installation +Open powershell in your working directory and paste these commands: +``` +git clone https://github.com/ZFTurbo/Verilog-Generator-of-Neural-Net-Digit-Detector-for-FPGA.git +cd Verilog-Generator-of-Neural-Net-Digit-Detector-for-FPGA +python3.10 -m venv venv +./venv/Scripts/Activate.ps1 +pip3.10 install -r requirements.txt +``` ## How to run: * python r01_train_neural_net_and_prepare_initial_weights.py diff --git a/a00_common_functions.py b/a00_common_functions.py index b83dffa..34afa04 100644 --- a/a00_common_functions.py +++ b/a00_common_functions.py @@ -29,8 +29,8 @@ def show_resized_image(P, w=1000, h=1000): def load_mnist_data(type='channel_last'): from keras.datasets import mnist - from keras.utils import np_utils - + from keras.utils import to_categorical + # input image dimensions nb_classes = 10 img_rows, img_cols = 28, 28 @@ -51,8 +51,8 @@ def load_mnist_data(type='channel_last'): print(X_test.shape[0], 'test samples') # convert class vectors to binary class matrices - Y_train = np_utils.to_categorical(y_train, nb_classes) - Y_test = np_utils.to_categorical(y_test, nb_classes) + Y_train = to_categorical(y_train, nb_classes) + Y_test = to_categorical(y_test, nb_classes) return X_train, Y_train, X_test, Y_test @@ -69,11 +69,11 @@ def save_history(history, path, columns=('loss', 'val_loss')): def prepare_image_from_camera(im_path): img = cv2.imread(im_path) - print('Read image: {} Shape: {}'.format(im_path, img.shape)) + # print('Read image: {} Shape: {}'.format(im_path, img.shape)) # Take central part of image with size 224х224 img = img[8:-8, 48:-48] - print('Reduced shape: {}'.format(img.shape)) + # print('Reduced shape: {}'.format(img.shape)) # Convert to grayscale with human based formulae https://samarthbhargav.wordpress.com/2014/05/05/image-processing-with-python-rgb-to-grayscale-conversion/ # Divider here is 16 for easier implementation of division in verilog for FPGA. @@ -95,8 +95,8 @@ def prepare_image_from_camera(im_path): # Check dynamic range min_pixel = output_image.min() max_pixel = output_image.max() - print('Min pixel: {}'.format(min_pixel)) - print('Max pixel: {}'.format(max_pixel)) + # print('Min pixel: {}'.format(min_pixel)) + # print('Max pixel: {}'.format(max_pixel)) # Rescale dynamic range if needed (no Verilog implementation, so skip) if 0: diff --git a/r01_train_neural_net_and_prepare_initial_weights.py b/r01_train_neural_net_and_prepare_initial_weights.py index 3e050a3..9564520 100644 --- a/r01_train_neural_net_and_prepare_initial_weights.py +++ b/r01_train_neural_net_and_prepare_initial_weights.py @@ -10,6 +10,10 @@ import random +epochs = 20 +optimizer = 'Adam' +learning_rate = 0.003 + gpu_use = 0 os.environ["KERAS_BACKEND"] = "tensorflow" os.environ["CUDA_VISIBLE_DEVICES"] = "{}".format(gpu_use) @@ -178,12 +182,10 @@ def evaluate_generator_train(X_test, Y_test, batch_size): Y_train = np.concatenate((Y_train, np.zeros((Y_train.shape[0], 1))), axis=1) Y_test = np.concatenate((Y_test, np.zeros((Y_test.shape[0], 1))), axis=1) - optimizer = 'Adam' - learning_rate = 0.001 if optimizer == 'SGD': - optim = SGD(lr=learning_rate, decay=1e-6, momentum=0.9, nesterov=True) + optim = SGD(learning_rate=learning_rate, decay=1e-6, momentum=0.9, nesterov=True) else: - optim = Adam(lr=learning_rate) + optim = Adam(learning_rate=learning_rate) model.compile(optimizer=optim, loss='categorical_crossentropy', metrics=['accuracy']) if continue_training == 1: print('Continue training. Loading weights from: {}'.format(cache_model_path)) @@ -197,19 +199,17 @@ def evaluate_generator_train(X_test, Y_test, batch_size): ModelCheckpoint(cache_model_path, monitor='val_loss', save_best_only=True, verbose=0), ] - history = model.fit_generator(generator=batch_generator_train(X_train, Y_train, batch_size, 'train'), - epochs=2000, - steps_per_epoch=200, - validation_data=batch_generator_train(X_test, Y_test, batch_size, 'valid'), - validation_steps=200, - verbose=2, - max_queue_size=20, - callbacks=callbacks) - - save_history(history, final_model_path, columns=('acc', 'val_acc')) - score = model.evaluate_generator(generator=evaluate_generator_train(X_test, Y_test, batch_size, 'valid'), - steps=X_test.shape[0] // batch_size, - max_queue_size=1) + history = model.fit(batch_generator_train(X_train, Y_train, batch_size, 'train'), + epochs=epochs, + steps_per_epoch=200, + validation_data=batch_generator_train(X_test, Y_test, batch_size, 'valid'), + validation_steps=200, + verbose=2, + callbacks=callbacks) + + save_history(history, final_model_path, columns=('accuracy', 'val_accuracy')) + score = model.evaluate(evaluate_generator_train(X_test, Y_test, batch_size), + steps=X_test.shape[0] // batch_size) print('Test score:', score[0]) print('Test accuracy:', score[1]) model.load_weights(cache_model_path) @@ -235,5 +235,5 @@ def evaluate_generator_train(X_test, Y_test, batch_size): print('Accuracy: {:.2f}%'.format(100*accuracy / len(pred_answers))) ''' -Accuracy: 97.39% +Accuracy after 2000 epochs: 97.39% ''' \ No newline at end of file diff --git a/r05_verilog_generator_neural_net_structure.py b/r05_verilog_generator_neural_net_structure.py index 1ffeea1..1f455c9 100644 --- a/r05_verilog_generator_neural_net_structure.py +++ b/r05_verilog_generator_neural_net_structure.py @@ -1254,8 +1254,8 @@ def TOP(directory, size, razmer, max_address_value, output_neurons_count, max_we for i in range(len(layers)): layer = layers[i] if 'Conv2D' in str(type(layer)): - mem = layer.output_shape[3]-1 - filt = layer.input_shape[3]-1 + mem = layer.output.shape[3]-1 + filt = layer.input.shape[3]-1 if (start == 0): file.write(" if ((TOPlvl=="+str(TOPlvl)+")&&(step=="+str(step)+")) nextstep = 1;\n") else: start = 0 @@ -1269,7 +1269,7 @@ def TOP(directory, size, razmer, max_address_value, output_neurons_count, max_we file.write(" conv_en = 1;\n") file.write(" mem = "+str(mem)+";\n") file.write(" filt = "+str(filt)+";\n") - file.write(" matrix = "+str(layer.input_shape[1])+";\n") + file.write(" matrix = "+str(layer.input.shape[1])+";\n") if 'GlobalMaxPooling2D' in str(type(layers[i+2])): file.write(" globmaxp_en = 1;\n") else: file.write(" globmaxp_en = 0;\n") @@ -1282,7 +1282,7 @@ def TOP(directory, size, razmer, max_address_value, output_neurons_count, max_we TOPlvl += 1 elif 'MaxPooling2D' in str(type(layer)): if not 'GlobalMaxPooling2D' in str(type(layer)): - for i in range(int(layer.input_shape[3]/4)): + for i in range(int(layer.input.shape[3]/4)): file.write(" if ((TOPlvl=="+str(TOPlvl)+")&&(STOP_maxp==0))\n") file.write(" begin\n") file.write(" memstartp = "+str(one)+"+"+str(i)+"*matrix2*((4 >> (num_conv >> 1)));\n") @@ -1301,8 +1301,8 @@ def TOP(directory, size, razmer, max_address_value, output_neurons_count, max_we file.write(" begin \n") file.write(" globmaxp_en = 0; \n") file.write(" nextstep = 1; \n") - file.write(" in_dense = "+str(layer.input_shape[1])+"; \n") - file.write(" out_dense = "+str(layer.output_shape[1])+"; \n") + file.write(" in_dense = "+str(layer.input.shape[1])+"; \n") + file.write(" out_dense = "+str(layer.output.shape[1])+"; \n") file.write(" end \n") step += 2 @@ -1541,9 +1541,9 @@ def convert_to_fix_point(arr1, bit): layer = model.layers[i] if 'Conv2D' in str(type(layer)): total_conv_layers_number += 1 - conv_inputs.append(layer.input_shape[1]) - conv_mem.append(layer.input_shape[3]) - conv_filt.append(layer.output_shape[3]) + conv_inputs.append(layer.input.shape[1]) + conv_mem.append(layer.input.shape[3]) + conv_filt.append(layer.output.shape[3]) w = layer.get_weights() conv_block_size_1 = len(w[0]) conv_block_size_2 = len(w[0][0]) @@ -1553,18 +1553,18 @@ def convert_to_fix_point(arr1, bit): max_weights_per_layer = max_weights_per_layer_1 elif 'MaxPooling2D' in str(type(layer)): if not 'GlobalMaxPooling2D' in str(type(layer)): - total_maxp_layers_number += int(layer.input_shape[3]/4) + total_maxp_layers_number += int(layer.input.shape[3]/4) elif 'Dense' in str(type(layer)): w = layer.get_weights() total_dense_layers_number += 1 - dense_inputs.append(layer.input_shape[1]) - dense_outputs.append(layer.output_shape[1]) + dense_inputs.append(layer.input.shape[1]) + dense_outputs.append(layer.output.shape[1]) max_address_value += len(layer.get_weights()[0][0]) * len(w[0]) max_weights_per_layer_1 = int(len(w[0][0]) * len(w[0])/(conv_block_size_1*conv_block_size_2)) + 1 if max_weights_per_layer_1 > max_weights_per_layer: max_weights_per_layer = max_weights_per_layer_1 if i == len(model.layers) - 1: - output_neurons_count = layer.output_shape[1] + output_neurons_count = layer.output.shape[1] max_input_image_size = max(conv_inputs) steps_count = 2 + (total_conv_layers_number*2) + (total_dense_layers_number*2) + 1 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..85f68d9 Binary files /dev/null and b/requirements.txt differ diff --git a/weights/keras_model_low_weights_digit_detector.h5 b/weights/keras_model_low_weights_digit_detector.h5 deleted file mode 100644 index 79ae9be..0000000 Binary files a/weights/keras_model_low_weights_digit_detector.h5 and /dev/null differ diff --git a/weights/keras_model_low_weights_digit_detector.h5.csv b/weights/keras_model_low_weights_digit_detector.h5.csv deleted file mode 100644 index e5a314b..0000000 --- a/weights/keras_model_low_weights_digit_detector.h5.csv +++ /dev/null @@ -1,113 +0,0 @@ -,acc,loss,val_acc,val_loss -0,0.14480000004172325,2.332716575860977,0.3657000002264976,1.940880570411682 -1,0.5096999994665384,1.5004599249362947,0.6249000035226345,1.1573940351605416 -2,0.6917000043392182,1.0036688259243964,0.7458000001311302,0.8244462838768959 -3,0.7473000010848045,0.8241036903858184,0.7950999954342842,0.6666760271787644 -4,0.785299996137619,0.7105176268517971,0.8117999941110611,0.6336127550899983 -5,0.8019999942183494,0.6574664333462715,0.8300999948382377,0.5492963694781064 -6,0.817699992954731,0.621597159653902,0.8526999947428703,0.5030765601992607 -7,0.8275999954342842,0.5890815941244364,0.8517999947071075,0.5084334528446197 -8,0.8433999961614609,0.5281209848821163,0.857999994456768,0.4760124896466732 -9,0.8442999964952469,0.52149852655828,0.8676999953389167,0.44864600598812104 -10,0.8503999933600426,0.5145990862697363,0.8675999963283538,0.44688226595520975 -11,0.8629999929666519,0.4660138565301895,0.8769999933242798,0.4221752982214093 -12,0.8620999932289124,0.470705124810338,0.8805999964475631,0.4040695134550333 -13,0.8655999946594238,0.4533840284496546,0.8880999943614006,0.37315953217446807 -14,0.8661999940872193,0.4592504046857357,0.892599995136261,0.3593304694443941 -15,0.8794999948143959,0.4121225866302848,0.8913999941945076,0.3651063744351268 -16,0.8751999923586845,0.43371115751564504,0.8989999976754188,0.34171108704060316 -17,0.886699997484684,0.40090336129069326,0.8974999976158142,0.34770245127379895 -18,0.8844999945163727,0.3971354412287474,0.9010999971628189,0.346512359008193 -19,0.8849999961256981,0.3963772598654032,0.901999996304512,0.32660636559128764 -20,0.8867999947071076,0.3837300253659487,0.9122999960184097,0.30710811603814364 -21,0.8926999959349632,0.3731368577852845,0.9078999957442284,0.3082481313124299 -22,0.8937999945878983,0.3658948715031147,0.9012999966740608,0.3317734618857503 -23,0.890299996137619,0.39109805822372434,0.9089999970793724,0.318887062817812 -24,0.9024999982118607,0.33675482150167224,0.9108999967575073,0.3098191745392978 -25,0.8958999952673912,0.36182733993977306,0.9186999985575676,0.2866941334679723 -26,0.9039999973773957,0.3430688890442252,0.9132999956607819,0.2968542552553117 -27,0.899999994635582,0.34679223500192163,0.920699996650219,0.2738042222894728 -28,0.9008999961614609,0.3392597429081798,0.9183999979496003,0.2711991260200739 -29,0.905999995470047,0.3187558839842677,0.9228999960422516,0.2595774453133345 -30,0.9051999968290328,0.3252930263243616,0.9223999962210655,0.27255827525630594 -31,0.907299996316433,0.3176384773105383,0.9216999977827072,0.27490714119747284 -32,0.9063999971747398,0.3245595881342888,0.9316999968886376,0.24394322481006384 -33,0.9102999970316887,0.31437698274850845,0.9241999962925911,0.2549916139058769 -34,0.9084999969601631,0.31468543846160174,0.9298999956250191,0.24417812775820494 -35,0.9096999970078469,0.30900180131196975,0.9246999967098236,0.2576153626292944 -36,0.9117999964952469,0.30438628379255533,0.9261999949812889,0.2583180397748947 -37,0.9113999956846237,0.30020493514835833,0.928399997651577,0.23957732137292623 -38,0.9167999961972236,0.28512523978948595,0.9240999975800515,0.25242267139256 -39,0.9101999974250794,0.2996239547803998,0.9322999984025955,0.23439424199983477 -40,0.918999999165535,0.2820792306959629,0.92759999781847,0.24631707645952702 -41,0.9213999956846237,0.26844542991369963,0.9320999988913536,0.23713302221149207 -42,0.9153999948501587,0.2961079835519195,0.9330999979376793,0.23046575279906392 -43,0.9160999968647957,0.28141010394319893,0.9286999955773354,0.24296756317839027 -44,0.9227999964356423,0.26615199809893964,0.9319999957084656,0.22649294950067997 -45,0.9219999971985817,0.270990860722959,0.9310999983549118,0.23347077134996652 -46,0.9175999942421913,0.27431231886148455,0.9406999969482421,0.20919407103210688 -47,0.9203999951481819,0.2739733869768679,0.9373999971151352,0.2096912495419383 -48,0.9193999955058098,0.2707438086345792,0.9393999990820885,0.207667807424441 -49,0.9208999970555305,0.2695534597709775,0.9360999971628189,0.22460849283263087 -50,0.9194999960064888,0.2776785035803914,0.9326000002026558,0.23272963535040617 -51,0.9217999970912933,0.25866919798776505,0.9380999964475631,0.21163134153932334 -52,0.9175999984145164,0.2612895669788122,0.9371000000834465,0.21325067438185216 -53,0.9188999986648559,0.2702373833023012,0.9429999965429307,0.1966700266767293 -54,0.9319999971985817,0.2340214175824076,0.9416999965906143,0.19071207840926946 -55,0.9261999952793122,0.2564167821779847,0.9413999956846237,0.2076547955814749 -56,0.9309999966621398,0.23571158461272718,0.941699996292591,0.20360792850144208 -57,0.924599996805191,0.25228555329144003,0.9394999983906746,0.20631139900535345 -58,0.9274999964237213,0.2366632217168808,0.9332999965548515,0.22291755659505724 -59,0.9284999963641166,0.2495058481581509,0.9393999981880188,0.20075991143472494 -60,0.9271999961137771,0.24663682278245688,0.9428999960422516,0.19365881813690067 -61,0.9229999962449074,0.2567033608444035,0.9398999986052513,0.20746710017323494 -62,0.9286999946832657,0.24215635284781456,0.9371999976038933,0.2147757281549275 -63,0.9284999966621399,0.24129647597670556,0.9385999971628189,0.2083776726014912 -64,0.9330999973416328,0.2322425721026957,0.9422999975085259,0.20303289166651667 -65,0.9269999969005585,0.24707445442676546,0.9369999969005585,0.21578125387430191 -66,0.9315999990701676,0.23854061368852852,0.9441999971866608,0.1887903433572501 -67,0.9280999982357026,0.24643137523904443,0.9421999979019166,0.20218531328253447 -68,0.9316999983787536,0.23088546209037303,0.9349999976158142,0.22004522326402365 -69,0.9295999953150749,0.2407047502323985,0.9428999954462052,0.19458124835509807 -70,0.9290999987721443,0.24287387907505034,0.9397999975085258,0.20189521454274653 -71,0.930499997138977,0.2370672501809895,0.9446999976038932,0.18993815986439586 -72,0.9327999979257584,0.23447497623041272,0.9426999974250794,0.19636906949803234 -73,0.9263999968767166,0.23995254658162593,0.9474999982118607,0.17938992579467594 -74,0.9352999973297119,0.2185019730217755,0.9445999976992607,0.19245103249326348 -75,0.9346999952197075,0.22136791477911175,0.9481000000238419,0.18109421845525503 -76,0.9362999972701073,0.21728788467124105,0.9375999969244003,0.2065681700501591 -77,0.937299997806549,0.21818352488800882,0.9470999982953071,0.18214992865920066 -78,0.9360999971628189,0.21092526479624213,0.9450999972224235,0.18346170762553812 -79,0.9320999965071678,0.22914187690243126,0.9494999986886978,0.17210238488391041 -80,0.9297999975085258,0.2329116986505687,0.9498999959230423,0.1701709069032222 -81,0.9315000003576279,0.22486743313260377,0.9524000000953674,0.161642564246431 -82,0.9382999986410141,0.20666892854496838,0.9425999993085861,0.182600562190637 -83,0.9366999986767769,0.22227641992270947,0.9464999973773957,0.17944465924054384 -84,0.9327999955415726,0.22943209510296583,0.9441999986767768,0.1831274047587067 -85,0.937599996626377,0.20832004267722368,0.9449999958276749,0.1805387006048113 -86,0.9416999977827072,0.20026189532130956,0.9460999995470047,0.18613601623103024 -87,0.936799997985363,0.2145126561820507,0.9533999979496002,0.1653504073061049 -88,0.9375999963283539,0.21247202087193728,0.9452999994158745,0.1872996025066823 -89,0.9327999973297119,0.22139025243930519,0.9460999968647957,0.18036706981249154 -90,0.9361999991536141,0.2060837645456195,0.950499999821186,0.16860484106466175 -91,0.9372999969124794,0.22412634030915796,0.9460999983549118,0.18898268716409802 -92,0.9415999990701676,0.2013957654684782,0.9491000005602837,0.1722827635053545 -93,0.936599996984005,0.21638908384367825,0.9439999970793724,0.1925447213742882 -94,0.9428999984264373,0.19933335797861218,0.9428999990224838,0.19462450494989753 -95,0.9364999958872795,0.21260569581761957,0.9478000000119209,0.17150656652636825 -96,0.937499997317791,0.2011501393467188,0.9495999988913536,0.17399185378104448 -97,0.9389999982714653,0.21122252950444817,0.942899999320507,0.1825796721689403 -98,0.9405999994277954,0.20876008285209535,0.9460999968647957,0.18288551620207727 -99,0.9347999981045723,0.21590894730761648,0.952199998497963,0.16483145479112862 -100,0.9363999968767166,0.20709685197100045,0.9524000003933907,0.16294661602936686 -101,0.9374999976158143,0.2075620036618784,0.946799995303154,0.19098302518948912 -102,0.942499997317791,0.19080870031379163,0.9476999986171722,0.17602290999144315 -103,0.9414999976754188,0.1999104794859886,0.946599999666214,0.17387369198724628 -104,0.9406999987363815,0.20018710697069764,0.950499997138977,0.16697491962462663 -105,0.9419999998807908,0.20334971852600575,0.9481999996304512,0.1723383666947484 -106,0.9369999971985817,0.21182444581761956,0.9477999991178513,0.1775572015810758 -107,0.9400999972224235,0.20136518388055266,0.9479999974370003,0.18246053057722747 -108,0.9377999979257584,0.21549792733043432,0.9454999962449073,0.18589407104067504 -109,0.9405999970436096,0.2061981282569468,0.947699998319149,0.18134062291122974 -110,0.9385999983549118,0.2018117493763566,0.9428999981284142,0.18089816082268953 -111,0.9383999979496003,0.21409924895502627,0.9506999990344047,0.16659923865459858 diff --git a/weights/keras_model_low_weights_digit_detector.h5.png b/weights/keras_model_low_weights_digit_detector.h5.png deleted file mode 100644 index dcb0d7f..0000000 Binary files a/weights/keras_model_low_weights_digit_detector.h5.png and /dev/null differ diff --git a/weights/keras_model_low_weights_digit_detector_rescaled.h5 b/weights/keras_model_low_weights_digit_detector_rescaled.h5 deleted file mode 100644 index a6df5f3..0000000 Binary files a/weights/keras_model_low_weights_digit_detector_rescaled.h5 and /dev/null differ diff --git a/weights/optimal_bit.pklz b/weights/optimal_bit.pklz deleted file mode 100644 index 8887f05..0000000 Binary files a/weights/optimal_bit.pklz and /dev/null differ