5959
6060 .sidebar-link .active {
6161 color : # fff ;
62- background-color : # 007bff ;
62+ background-color : # 33bbff ;
6363 border-radius : 4px ;
6464 }
65+ .sidebar-link .subsection {
66+ color : # 777 ;
67+ }
68+ .sidebar-link .subsection .active {
69+ color : # fff ;
70+ }
6571
6672
6773 details {
129135 }
130136 </ style >
131137 < script >
132- document . addEventListener ( "DOMContentLoaded" , function ( ) {
133- const sidebarLinks = document . querySelectorAll ( '.sidebar-link' ) ;
134-
135- function removeActiveClasses ( ) {
136- sidebarLinks . forEach ( link => link . classList . remove ( 'active' ) ) ;
137- }
138-
139- function addActiveClass ( link ) {
140- removeActiveClasses ( ) ;
141- link . classList . add ( 'active' ) ;
142- }
143-
144- const options = {
145- root : null ,
146- rootMargin : '0px' ,
147- threshold : 0.2
148- } ;
138+ document . addEventListener ( "DOMContentLoaded" , function ( ) {
139+ const sidebarLinks = document . querySelectorAll ( '.sidebar-link' ) ;
140+ const sections = document . querySelectorAll ( 'section' ) ;
141+
142+ function removeActiveClasses ( ) {
143+ sidebarLinks . forEach ( link => link . classList . remove ( 'active' ) ) ;
144+ }
145+
146+ function addActiveClass ( link ) {
147+ removeActiveClasses ( ) ;
148+ if ( link ) link . classList . add ( 'active' ) ;
149+ }
150+
151+ function getClosestSection ( ) {
152+ let minDistance = Infinity ;
153+ let closestSection = null ;
154+ const scrollY = window . scrollY ;
155+ sections . forEach ( section => {
156+ const offset = Math . abs ( section . offsetTop - scrollY - 100 ) ; // Adjust for fixed navbar offset
157+ if ( offset < minDistance ) {
158+ minDistance = offset ;
159+ closestSection = section ;
160+ }
161+ } ) ;
162+ return closestSection ;
163+ }
164+
165+ function updateActiveSection ( ) {
166+ const section = getClosestSection ( ) ;
167+ if ( section ) addActiveClass ( document . querySelector ( `.sidebar-link[href="#${ section . id } "]` ) ) ;
168+ }
169+ window . addEventListener ( "scroll" , updateActiveSection ) ;
170+ sidebarLinks . forEach ( link => { link . addEventListener ( "click" , function ( event ) {
171+ event . preventDefault ( ) ;
172+ const targetId = this . getAttribute ( "href" ) . substring ( 1 ) ;
173+ const targetSection = document . getElementById ( targetId ) ;
174+
175+ if ( targetSection ) { window . scrollTo ( {
176+ top : targetSection . offsetTop - 80 ,
177+ behavior : "smooth"
178+ } ) ; }
179+ } ) ; } ) ;
180+ window . addEventListener ( "load" , updateActiveSection ) ;
181+ } ) ;
182+ </ script >
149183
150- const observerCallback = ( entries , observer ) => {
151- entries . forEach ( entry => {
152- const id = entry . target . getAttribute ( 'id' ) ;
153- const link = document . querySelector ( `.sidebar-link[href="#${ id } "]` ) ;
154184
155- if ( entry . isIntersecting ) {
156- addActiveClass ( link ) ;
157- }
158- } ) ;
159- } ;
160-
161- const observer = new IntersectionObserver ( observerCallback , options ) ;
162-
163- document . querySelectorAll ( 'section' ) . forEach ( section => {
164- observer . observe ( section ) ;
165- } ) ;
166- } ) ;
167- </ script >
168185</ head >
169186
170187< body >
174191 < li class ="nav-item "> < a class ="sidebar-link " href ="#setup "> 1. Setup</ a > </ li >
175192 < li class ="nav-item "> < a class ="sidebar-link " href ="#quickstart "> 2. Quickstart</ a > </ li >
176193 < li class ="nav-item "> < a class ="sidebar-link " href ="#gnn-builders "> 3. GNN Builders</ a > </ li >
177- < li class ="nav-item ps-md-3 text-secondary "> < a class ="sidebar-link small p-1 subsection " href ="#modelbuilder "
178- style ="color: #777777; "> 3.1. ModelBuilder</ a > </ li >
179- < li class ="nav-item ps-md-3 text-secondary "> < a class ="sidebar-link small p-1 subsection " href ="#fastbuilder "
180- style ="color: #777777; "> 3.2. FastBuilder</ a > </ li >
181- < li class ="nav-item ps-md-3 text-secondary "> < a class ="sidebar-link small p-1 subsection " href ="#neuralang "
182- style ="color: #777777; "> 3.3. Neuralang</ a > </ li >
183- < li class ="nav-item ps-md-3 text-secondary "> < a class ="sidebar-link small p-1 subsection " href ="#debugging "
184- style ="color: #777777; "> 3.4. Debugging</ a > </ li >
194+ < li class ="nav-item ps-md-3 "> < a class ="sidebar-link small p-1 subsection " href ="#modelbuilder "> 3.1. ModelBuilder</ a > </ li >
195+ < li class ="nav-item ps-md-3 "> < a class ="sidebar-link small p-1 subsection " href ="#fastbuilder "> 3.2. FastBuilder</ a > </ li >
196+ < li class ="nav-item ps-md-3 "> < a class ="sidebar-link small p-1 subsection " href ="#neuralang "> 3.3. Neuralang</ a > </ li >
197+ < li class ="nav-item ps-md-3 "> < a class ="sidebar-link small p-1 subsection " href ="#debugging "> 3.4. Debugging</ a > </ li >
185198 < li class ="nav-item "> < a class ="sidebar-link " href ="#training "> 4. Training</ a > </ li >
186- < li class ="nav-item ps-md-3 text-secondary "> < a class ="sidebar-link small p-1 subsection " href ="#create-data "
187- style ="color: #777777; "> 4.1. Create data</ a > </ li >
188- < li class ="nav-item ps-md-3 text-secondary "> < a class ="sidebar-link small p-1 subsection " href ="#node-classification "
189- style ="color: #777777; "> 4.2. Node classification</ a > </ li >
190- < li class ="nav-item ps-md-3 text-secondary "> < a class ="sidebar-link small p-1 subsection " href ="#graph-classification "
191- style ="color: #777777; "> 4.3. Graph classification</ a > </ li >
199+ < li class ="nav-item ps-md-3 "> < a class ="sidebar-link small p-1 subsection " href ="#create-data "> 4.1. Create data</ a > </ li >
200+ < li class ="nav-item ps-md-3 "> < a class ="sidebar-link small p-1 subsection " href ="#node-classification "> 4.2. Node classification</ a > </ li >
201+ < li class ="nav-item ps-md-3 "> < a class ="sidebar-link small p-1 subsection " href ="#graph-classification "> 4.3. Graph classification</ a > </ li >
192202 </ ul >
193203 </ nav >
194204
@@ -218,12 +228,12 @@ <h1 class="text-center">JGNN</h1>
218228 < p class ="text-center "> < em > Resource efficient machine learning and graph neural networks in native Java.</ em >
219229 </ p >
220230
221- < p > Graph Neural Networks (GNNs) are getting more and more popular as a machine learning paradigm ,
231+ < p > Graph Neural Networks (GNNs) are getting more and more popular,
222232 for example to make predictions
223233 based on relational information, or to perform inference on small datasets. JGNN is a library that
224- provides cross-platform implementations of this paradigm without the need for dedicated
225- hardware or firmware; create highly portable models that fit and are trained in
226- a few megabytes of memory.
234+ provides cross-platform implementations of this paradigm and traditional neural networks
235+ without the need for dedicated hardware or firmware; create highly portable models that fit and
236+ are trained in a few megabytes of memory.
227237 </ p >
228238
229239 < p >
@@ -448,34 +458,56 @@ <h1>3. GNN Builders</h1>
448458 Use this builder to maintain model definitions in one place (e.g., packed in one string
449459 variable, or in one file) and avoid weaving symbolic expressions in Java code.</ li >
450460 </ ul >
451- In this section we cover these three builder classes and summarize debugging mechanisms that
452- check the integrity of constructed models, visualize their data flow, and monitor specific
461+ In this section we cover these three builder classes. We also summarize debugging mechanisms for
462+ checking the integrity of constructed models, visualize their data flow, and monitor specific
453463 data at runtime.</ p >
454464
465+ < section id ="modelbuilder ">
455466 < h3 id ="modelbuilder "> 3.1. ModelBuilder</ h3 >
456- < p > This is the base model builder class; it offers a wide breadth of functionalities that other builders extend.
457- Before looking at how to use it, though, we need to see what JGNN models look like under the hood.
458- Models are collections of < code class ="language-java "> NNOperation</ code > instances, each representing a numerical computation with
459- specified inputs and outputs of
460- JGNN's < code > Tensor</ code > type. Tensors will be covered later; for now, it suffices to think of them as
461- numerical vectors, which are sometimes endowed with matrix dimensions.
467+ < p > This is the base model builder class; it offers a wide breadth of functionalities that other builders extend. Models
468+ take tensors as input and outputs. Tensors will be covered later; for now, it suffices to think of them as
469+ numerical vectors, which are sometimes endowed with matrix dimensions. The models themselves are built from Java classes
470+ that indicate sub-operations. However, this can be too verbose many lines of code are needed to declare even simple expressions,
471+ making models cumbersome to read and maintain - hence the need for
472+ builders that construct the models from concise symbolic expressions.</ p >
473+ < p > To create a model with the < code class ="language-java "> ModelBuilder</ code > class,
474+ instantiating the builder, use a method chain to declare an input variable
475+ with the < code class ="language-java "> .var(String)</ code > method, parse an expression with the
476+ < code class ="language-java "> .operation(String)</ code > method, and finally declare which symbol holds
477+ outputs with the < code class ="language-java "> .out(String)</ code > method.
478+ The first and last of these methods can be called multiple times
479+ to declare several inputs and outputs. Inputs need to be only one symbol, but a whole expression
480+ for evaluation can be declared in outputs. Obtain the created model's instance with the < code class ="language-java "> .getModel()</ code > method.
462481 </ p >
482+
463483 < p >
464- This guidebook does not list operation classes, as they are rarely used directly and can be found the Javadoc, namely
465- < a href ="https://mklab-iti.github.io/JGNN/javadoc/mklab/JGNN/nn/inputs/package-summary.html " target ="_blank "> nn.inputs</ a > ,
466- < a href ="https://mklab-iti.github.io/JGNN/javadoc/mklab/JGNN/nn/activations/package-summary.html " target ="_blank "> nn.activations</ a > ,
467- and
468- < a href ="https://mklab-iti.github.io/JGNN/javadoc/mklab/JGNN/nn/pooling/package-summary.html " target ="_blank "> nn.pooling</ a > .
469- Create models in pure Java like the example computes, where the expression
470- < code class ="language-rust "> y=log(2*x+1)</ code > does not have any trainable parameters.
471- After defining models, run them with the method < code class ="language-java "> Tensor Model.predict(Tensor...)</ code > .
472- This takes as input one or more comma-separated tensors that match the model's
473- inputs (in the same order) and computes a list of output tensors. If inputs are dynamically created,
474- an overloaded version of the same method supports an array list of input tensors
475- < code class ="language-java "> Tensor Model.predict(ArrayList<Tensor>)</ code > .
484+ After defining models, use them to make predictions like below.
485+ The prediction method takes as input one or more comma-separated tensors that match the model's
486+ inputs (in the same order) and computes a list of output tensors. If inputs are dynamically created,
487+ an overloaded version of the same method supports passing an array list of input tensors instead.
476488 </ p >
477489
478- < pre > < code class ="language-java "> Variable x = new Variable();
490+ < pre > < code class ="language-java "> ModelBuilder modelBuilder = new ModelBuilder()
491+ .var("x")
492+ .operation("y = log(2*x+1)")
493+ .out("y");
494+ Model model = modelBuilder.getModel();
495+ System.out.println(model.predict(Tensor.fromDouble(2)));
496+ </ code > </ pre >
497+
498+ < details > < summary > Equivalent Java implementation without the builder.</ summary >
499+ < p > Under the hood, JGNN models are collections of < code class ="language-java "> NNOperation</ code > instances, each representing a numerical computation with
500+ specified inputs and outputs of
501+ JGNN's < code class ="language-java "> Tensor</ code > type. This guidebook does not list operation classes, as they are rarely used directly and can be found the Javadoc, namely
502+ < a href ="https://mklab-iti.github.io/JGNN/javadoc/mklab/JGNN/nn/inputs/package-summary.html " target ="_blank "> nn.inputs</ a > ,
503+ < a href ="https://mklab-iti.github.io/JGNN/javadoc/mklab/JGNN/nn/activations/package-summary.html " target ="_blank "> nn.activations</ a > ,
504+ and
505+ < a href ="https://mklab-iti.github.io/JGNN/javadoc/mklab/JGNN/nn/pooling/package-summary.html " target ="_blank "> nn.pooling</ a > .
506+ Create models in pure Java like the example below, where the expression
507+ < code class ="language-rust "> y=log(2*x+1)</ code > does not have any trainable parameters.
508+ </ p >
509+
510+ < pre > < code class ="language-java "> Variable x = new Variable();
479511Constant c1 = new Constant(Tensor.fromDouble(1)); // holds the constant "1"
480512Constant c2 = new Constant(Tensor.fromDouble(2)); // holds the constant "2"
481513NNOperation mult = new Multiply()
@@ -490,27 +522,8 @@ <h3 id="modelbuilder">3.1. ModelBuilder</h3>
490522 .addInput(x)
491523 .addOutput(y);
492524System.out.println(model.predict(Tensor.fromDouble(2))); // one-element input
493- </ code > </ pre >
494-
495- < p > Judging by the fact that several lines of code are needed to declare even simple expressions,
496- pure Java code for creating full models tends to be cumbersome to read and maintain - hence the need for
497- builders that construct the models from concise symbolic expressions. Let us recreate the above example
498- with the < code class ="language-java "> ModelBuilder</ code > class.
499- After instantiating the builder, use a method chain to declare an input variable
500- with the < code class ="language-java "> .var(String)</ code > method, parse an expression with the
501- < code class ="language-java "> .operation(String)</ code > method, and finally declare which symbol holds
502- outputs with the < code class ="language-java "> .out(String)</ code > method.
503- The first and last of these methods can be called multiple times
504- to declare several inputs and outputs. Inputs need to be only one symbol, but a whole expression
505- for evaluation can be declared in outputs.
506- </ p >
507-
508- < pre > < code class ="language-java "> ModelBuilder modelBuilder = new ModelBuilder()
509- .var("x")
510- .operation("y = log(2*x+1)")
511- .out("y");
512- System.out.println(model.predict(Tensor.fromDouble(2)));
513- </ code > </ pre >
525+ </ code > </ pre >
526+ </ details >
514527
515528 < details > < summary > Differences between expression parsing and Neuralang.</ summary >
516529 < p >
@@ -723,22 +736,24 @@ <h3 id="modelbuilder">3.1. ModelBuilder</h3>
723736
724737 < p > Model definitions have so far been too simple to be employed in practice;
725738 we need trainable parameters, which are created inline with the < code > matrix</ code >
726- and < code > vector</ code > functions. There is equivalent Java code for this, but its usage
727- is discouraged to keep model definitions simple.
739+ and < code > vector</ code > Neuralang functions. Do not use equivalent Java code, because
740+ it is better to keep model definitions simple.
728741 Additionally, there may be constants and configuration hyperparameters. Of these, constants reflect
729- untrainable tensors and set with < code class ="language-java "> ModelBuilder .const(String, Tensor)</ code > .
742+ untrainable tensors and set in a builder with < code class ="language-java "> .const(String, Tensor)</ code > .
730743 Both numbers in the last snippet's symbolic definition are internally parsed into constants.
731744 </ p >
732745 < p >
733746 On the other hand, configuration hyperparameters are numerical values used by the parser and
734- set with < code class ="language-java "> ModelBuilder .config(String, double)</ code > . Provide another
747+ set for a builder with < code class ="language-java "> .config(String, double)</ code > . Provide another
735748 configuration's name as the second argument to copy its value.
736749 On the other hand, hyperparameters can be used as arguments to dimension sizes and regularization.
737- Retrieve previously set hyperparameters though
738- < code class ="language-java "> ModelBuilder .getConfigOrDefault(String, double)</ code > , where the second argumement may be ommitted.
750+ Retrieve previously set builder hyperparameters though
751+ < code class ="language-java "> .getConfigOrDefault(String, double)</ code > , where the second argumement may be ommitted.
739752 This is mostly useful for bringing into code hyperparameters declared in Neuralang scripts.
740753 </ p >
754+ </ section >
741755
756+ < section id ="fastbuilder ">
742757 < h3 id ="fastbuilder "> 3.2. FastBuilder</ h3 >
743758 < p > The < code class ="language-java "> FastBuilder</ code > class for building GNN architectures extends the generic
744759 < code class ="language-java "> ModelBuilder</ code > with common graph neural network operations. The main difference
@@ -945,8 +960,9 @@ <h3 id="fastbuilder">3.2. FastBuilder</h3>
945960 for each feature dimension, aggregates feature values across all nodes.
946961 </ p >
947962 </ details >
963+ </ section >
948964
949-
965+ < section id =" neuralang " >
950966 < h3 id ="neuralang "> 3.3. Neuralang</ h3 >
951967
952968 < p > Neuralang scripts consist of functions that declare machine learning
@@ -1095,8 +1111,9 @@ <h3 id="neuralang">3.3. Neuralang</h3>
10951111 values denoted with < code class ="language-java "> ?</ code > from an example input.
10961112 For faster completion of the model, we provide a dataless list of node identifiers as input.</ p >
10971113 </ details >
1114+ </ section >
10981115
1099-
1116+ < section id =" debugging " >
11001117 < h3 id ="debugging "> 3.4. Debugging</ h3 >
11011118 < p > JGNN offers high-level tools for debugging
11021119 architectures. Here we cover what diagnostics to run, and how to make
@@ -1153,6 +1170,7 @@ <h3 id="debugging">3.4. Debugging</h3>
11531170 < p > Some tensor or matrix methods do not
11541171 correspond to numerical operations but
11551172 are only responsible for naming dimensions.
1173+ </ section >
11561174 Functionally, such methods are largely decorative,
11571175 but they cab improve debugging by throwing errors for
11581176 incompatible non-null names. For example,
@@ -1292,7 +1310,7 @@ <h3 id="debugging">3.4. Debugging</h3>
12921310 monitors the outcome of matrix multiplication:
12931311 </ p >
12941312 < pre > < code class ="language-java "> builder.operation("h = relu(monitor(x@matrix(features, 64)) + vector(64))")</ code > </ pre >
1295-
1313+ </ section >
12961314 </ section >
12971315
12981316 < section id ="training ">
@@ -1309,6 +1327,7 @@ <h1>4. Training</h1>
13091327 (reach out with requests for helper classes for other kinds of predictive tasks
13101328 in the project's GitHub issues).</ p >
13111329
1330+ < section id ="create-data ">
13121331 < h3 id ="create-data "> 4.1. Create data</ h3 >
13131332 < p > JGNN contains dataset classes that automatically download and load
13141333 datasets for out-of-the-box experimentation. These datasets can be found
@@ -1447,7 +1466,8 @@ <h3 id="create-data">4.1. Create data</h3>
14471466long predictedClassId = prediction.argmax();
14481467System.out.println(classIds.get(predictedClassId));</ code > </ pre >
14491468
1450-
1469+ </ section >
1470+ < section id ="node-classification ">
14511471 < h3 id ="node-classification "> 4.2. Node classification</ h3 >
14521472 < p >
14531473 Node classification models can be backpropagated by considering a list of node indeces and desired
@@ -1468,11 +1488,10 @@ <h3 id="node-classification">4.2. Node classification</h3>
14681488 nodes.range(trainSplit, validationSplit));
14691489 </ code > </ pre >
14701490
1491+ </ section >
14711492
1472-
1493+ < section id =" graph-classification " >
14731494 < h3 id ="graph-classification "> 4.3. Graph classification</ h3 >
1474-
1475-
14761495 < p > Most neural network architectures are designed with the idea
14771496 of learning to classify nodes or samples. However, GNNs also
14781497 provide the capability to classify entire graphs based on
@@ -1605,6 +1624,7 @@ <h3 id="graph-classification">4.3. Graph classification</h3>
16051624 }
16061625}</ code > </ pre >
16071626 </ section >
1627+ </ section >
16081628
16091629 </ div >
16101630 < script src ="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js "> </ script >
0 commit comments