alexlenail / NN-SVG

Publication-ready NN-architecture schematics.
http://alexlenail.me/NN-SVG/
MIT License
4.49k stars 579 forks source link

feature request: "Being able to upload weights and biases to the web interface" #32

Open marjanin opened 4 years ago

marjanin commented 4 years ago

Thank you for the great package. I was wondering if you can enable uploading weights and biases (as matrices, either in python's numpy format or Mathworks' MATLAB, or simple txt, etc.) so that when we use "Edge width proportional to edge weights" feature, it actually represents the uploaded ANN structure. Thanks

alexlenail commented 4 years ago

Glad you like it! This is a great feature request, but sadly, I don't have the bandwidth to add features right now. I may circle back and add this some day, but not any day soon. You're also welcome to submit a PR, and we could work through getting this feature added.

marjanin commented 4 years ago

Thank you Alexander, I am not as proficient in Java as I am on Python and thankfully, I found a python code that (with slight modifications) can fulfill the feature I needed (not as aesthetically pleasing as your solution, however). Here I am sharing it with you just in case it becomes handy one day: https://stackoverflow.com/questions/29888233/how-to-visualize-a-neural-network https://github.com/miloharper/visualise-neural-network Again, great work! Best, Ali

On Wed, Apr 15, 2020 at 2:32 PM Alexander Lenail notifications@github.com wrote:

Glad you like it! This is a great feature request, but sadly, I don't have the bandwidth to add features right now. I may circle back and add this some day, but not any day soon. You're also welcome to submit a PR, and we could work through getting this feature added.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://urldefense.com/v3/__https://github.com/alexlenail/NN-SVG/issues/32*issuecomment-614290966__;Iw!!LIr3w8kk_Xxm!_N1pU6w3I03g5PjkRhDbp1F9A4Izd5o1QGGqMII3x2f6E1LZtqscxLybR1Inr5g$, or unsubscribe https://urldefense.com/v3/__https://github.com/notifications/unsubscribe-auth/AEHSZN7RCQQ6ZVEIGH26RKTRMYRXVANCNFSM4MI3IVXQ__;!!LIr3w8kk_Xxm!_N1pU6w3I03g5PjkRhDbp1F9A4Izd5o1QGGqMII3x2f6E1LZtqscxLybnwRm4dE$ .

-- Ali Marjaninejad ​PhD Candidate​, Provost Fellow and Research Enhancement Fellow, Biomedical Engineering Department, University of Southern California, 3601 Watt Way, Los Angeles, California 90089 Email: marjanin@usc.edu; a.marjaninezhad@gmail.com

quiquegurdiel commented 10 months ago

@alexlenail thank you for the great work.

I support the suggestion. I think being able to upload weights in FCNN can be particularly informative. Maybe just uploading a simple txt that contains the matrices.

quiquegurdiel commented 10 months ago

I succeeded into producing what seems to be a correct graphical representation of the weights. I had to harcode all weights values into the js code so the solution is very ugly code-wise but the result is amazing. nn

The input layer has some geometrical meaning here and some structure is visible now. Thanks again!

quiquegurdiel commented 9 months ago

I develop a little here the workaround used to obtain that representation. Suppose you are working with keras and want to train a [16,12,10,1] network (the default in the web interface).

import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras import models
from tensorflow.keras import optimizers
#model definition
X_input = layers.Input((16,1))
X = layers.Dense(units=12,activation='relu')(X_input)
X = layers.Dense(units=10,activation='relu')(X)
X = layers.Dense(units=1,activation='sigmoid')(X)
model = models.Model(inputs=X_input,outputs=X)
#model compilation
optimizer = optimizers.Adam()
loss_fn = tf.keras.losses.binary_crossentropy
model.compile(optimizer, loss_fn)

#...
#here you might want to train the model
#...

#weights extraction
all_weights=[]
for layer_name in ['dense','dense_1','dense_2']:
    weights=model.get_layer(layer_name).get_weights()
    weights=np.abs(weights[0].flatten())    #take the absolute value and flatten
    weights=weights/np.max(weights)     #weight normalization by layer
    all_weights=np.append(all_weights,weights)
#save the values in a txt file
np.savetxt('all_weights.txt',all_weights,newline=',',fmt='%f')

This will be enough to obtain the weight values in a txt file. This weight values are ordered and it can be tested easily this ordenation is the one you require in the next block. Now we are ready to harcode this weight values in the js code. We have to edit the FFCN.js file.

// harcode the weights values into a js array
const myWeigths = [ "HERE YOU SHOULD COPY THE CONTENT OF all_weights.txt" ]
// initialise a "global" counter
var count=0
// define a function that read a weight value and increases the counter
function readWeigth() {
    aux = myWeigths[count]
    count = count+1
    return aux
}
// edit the line in wich the weights of the graph are defined as follows (just look for "randomWeight()" and change to readWeigth()")
graph.links = pairWise(graph.nodes).map((nodes) => nodes[0].map(left => nodes[1].map(right => {return right.node_index >= 0 ? {'id':left.id+'-'+right.id, 'source':left.id,'target':right.id,'weight':readWeigth()} : null }))); 

It turns out the function is called sequentially in the same order we saved the weights on the txt file. Then you open index.html with your web explorer and play with the interface in order to produce your representation.

Most likely the network arquitecture you want to represent is different to the default, so you have to edit the default arquitecture in index.html. That's straightforward.

Credits to @Jur314 for helping with the js.