SYN@PTICS®
Neural and Adaptive Systems

 DISTRIBUTED NEURAL OBJECTS
WITH JAVA AND CORBA
Luca Marchese
Copyright note: all the contents of this site are intellectual property of Luca Marchese. Total or partial reproduction on every kind of media must be authorized by the author.



INTRODUCTION

While anything's living around Internet world is very popular, some promising technologies like neural networks stay often closed in reserch centers and universities. In this article I try to celebrate a marriage between a software implementation of an artificial neural network and two Internet strongly related technologies like Java and CORBA. While I have not space to explain the details of the neural learning algorithm I can divide it in functional blocks and explain the general behavior at this level.
I like to put more attention on the Java implementation aspects of the algorithm than on mathematical ones: you can find anything about them on neural networks specialized books. This project is diveded in two subtasks:

a) a Java 1.02 compliant program that enables the neural network to learn from examples files and save synaptic files (don't warry you'll understand later!)for specific tasks.

b) a Java/CORBA client-server application where the server object is a neural engine that can load a task-related synaptic file (see the task a) and the client is an application/applet that can invoke his services through the Object Request Broker.
 
 

WHAT'S A NEURAL NETWORK?

An artificial neural network is a structural semplified simulation of brain that is composed of single units called neurons. The biological neuron is mathematically view as a device with more inputs(x[n]) and one output(y) and a transfer function:
y = f(x[1] + x[2] + ... + x[n])
(see also fig.1).

In a brain and in a nervous system there are a lot of neurons interconnected between themselves(output -> input) and these connections are called synapses. These connections have a "conductivity" value that influences the signal transfer between neurons.
Artificial neural networks are semplified models in witch neurons can works. One tipical model is called feed-forward due to the fact that signals flow in a single direction from the global input to the global output(see fig.2).

The network is composed of four layers of neurons where the outputs of every n-layer neuron is connected to an input of every (n+1)-layer neuron.
You can see this model like a black-box with n inputs and m outputs. The behavior of the network when it answers to a question is described follow:

- inputs values are applied - signals propagate to next layers through synaptic connections - output values are got as response to input stimulus

The output response values are determined by the input stimuli and the values of the synaptic connections. In order to determine the outputs you must calculate the neurons activation for any layer proceding from input to output. For neuron j of layer m, supposing that layer m-1 has 10 neurons, I can write:
 

A[j][m] = sum(from k=1 to k=10) {y[k][m-1] * w([j][m])([k][m-1])}
   where A[j][m] is the activation of the neuron
   w([j][m])([k][m-1]) is the value of the connection
                                     between the neuron j of the layer m
                                    and the neuron k of the layer m-1

The output of the neuron is simply a function of his activation:
        y[j][m] = f(A[j][m])

where f() is normally a sigmoid function:

 O = 1/(1 + exp(-A))

where O = output of the neuron
            A = activation of the neuron
The values of the synaptic connections are the know-how of the network, such as the ability to produce correct responses to stimuli. These values are not programmed but "learned" from database of known correct associations of stimulus-response. This process called "supervidsed learning" is commonly performed on a feed-forward neural network, using the "backpropagation" algorithm. More generally the algorithm cicles on the examples (input-output associations) and for any input calculates the output with the actual synaptic values and, after, the difference between the output and the desired output of the example. Now the synaptic values are modified in order to obtain a lower error for the example. This process is repeated for any example a lot of times called "epochs", waiting the global error (the maximum error considering all examples) reachs a desired value commonly called "target"(see fig.3).

I must underline the fact that neural networks need inputs normalized in the range 0.0 -> 1.0 and the outputs are in the same range. It means that you must map the ranges of the input and output variables of the task in this range:
this operation is usually called normalization. In order to obtain the output variables(the answers) in the original range you must perform the inverse operation(denormalization). I have no space here to explain the details of the learning algorithm but I want remark some aspect of neural neural networks that make them so useful.
While the programmed systems can answer only to precise questions (think to a database), neural networks can answer to fuzzy or noisy questions. It is like to say they extract the important features of the answer-questions associations used in learning and they can answer sufficiently correctly to questions not available in the learning database. This characteristic enables neural networks to perform well in tasks like forecast, classification, pattern recognition. I can speak about credit-risk task for banks as an example for all. In this task, some characterics of the person that requires the credit are the inputs, while the risk is the output. This is a tipical task where a client-server solution would be useful.
 
 

A CUP OF COFFEE NEURONS

In this article you'll see the development of a neural network software simulation in Java and a CORBA-applet based client server solution for neural services. The first program is composed of two classes contained in the files backprop.java and training.java. The class backprop is the core of the neural network and has all the methods to perform the learning process reading from a file containing the examples related to a particular task. The examples file is in ascii format and the examples are inserted like follow:
0.01   //input 1 of example 1
0.40   //input 2 of example 1
0.30   //output 1 of example 1
0.90   //output 2 of example 1
0.51   //input 1 of example 2
0.10   //input 2 of example 2
0.10   //output 1 of example 2
0.40   //output 2 of example 2
...and so on for any example.
And now I can go inside the class "backprop"(listing 1). The constructor build the network with specified(by the parameters) number of inputs, outputs and neurons in the two hidden layers. It builds also the synaptics matrix for any couple of layers(3 matrixes). The learning process is running on a separate thread and can be started/stopped/paused/resumed by other objects using the public interface methods startLearn(), stopLearn(), pauseLearn(), resumeLearn(). You can see inside the startLearn() the "start()" method of the "learningThread" and inside the run() method(that's the body of learningThread) the call to the learn() method that is the core of the learning process. I want you note the "implements Runnable" at the declaration of the class and the "throws InterruptedException" at the learn() method declaration. The Runnable interface is necessary in order to have multithread capability inside the object and the code invoking the learn() method must be informad to manage this possible exception. Because of Java 1.1 thread specification is not strongly defined and in order to guarantee correct execution in more environments, I use not-preemptive multithread managment. You can see that the threads leaves cpu to other threads using "sleep(time)" and I substitute the "pause()" method with a "while(condition){sleep(time)}" code. The "resume()" method is substituted simply by a method that updates the condition flag. Some private methods invoked by "learn()" complete the learning process: exec() executes the network for any examples and backpropagation() updates the synaptic values in function of the difference between obtained output and desired output. The "startLearn()" public method must be invoked with the parameters specifing the examples file, the number of examples to consider, the target error and a learning coefficient "epsilon".These parameters will be passed to the "learn()" method. When the target is reached, the network has his know-how in the synaptic values that can be saved on file(saveNet(filename)) in order to be reloaded after(loadNet(filename)).This feature can be useful for interrupt and restart a long learning process from a middle point instead from the random initialization of the synaptic values.You'll see it'll be used, also, by the CORBA server in the next section. If you want reload a saved network you must use the alternative constructor that loads a synaptic file with the same name of the network(the only one parameter passed). If you want continue a learning process on the loaded network you must disable the random initialization of synapses performed by "weightStarter()", setting to false the "randomInit" flag. The "training" class(listing 2) is the multiframe/multinetwork learning consolle with GUI. It enables you to the following actions:

1) Create/destroy a network (an instance of backprop.class). Necessary textfields are number of inputs, outputs, neurons in the hidden layers and an identifier name of the network. If the "LOADNET" Checkbox is setted these fields are not necessary but it's required only to set the name of the network that is used by the second constructor of "backprop" class to load a network from a file with the same name. The name of the network is labeled as "TASKID".

2) Start/pause/resume/stop a learning process. To start a learning process it is necessary to fill the textfields related with the name of the examples-file, the target error, the learning coefficient(epsilon), the number of the examples (EXAMPLES) and the number of the epochs before a pause(STEP). If you start a learning on a loaded network the error will start from the error previously reached by it.

3) Enable/disable the neural network to save itself automatically every an epochs number step. The "AUTOSAVE" Checkbox enables/disables this feature and "SAVESTEP" textfield must contain the number of epochs between any saving. The network will be saved on a file with the same name of the network, such as "TASKID".

4) Create a new consolle-frame (an instance of training.class) in order to manage simultaneusly more neural networks learning processes.

5) Perform the execution of the network at the actual status of learning, reading input from and writing output to the files indicated in the "<-IN OUT->" fields. This action is performed pressing the "TEST" button.

The "training" class implements the Runnable interface in order to have a thread(body of run()) dedicated to monitoring the status of the "learningThread" in the "backprop" instance. The event managing is in Java1.02 style and performed by the "action()" method. The textfields related to net creation and learning start are setted to "not-editable" when these actions are respectively performed and performing, in order to avoid incongruent data on the frame. To start the program is sufficient to run the training.class that is a main class having a main() method. This program thanks to the not-preemptive multithread managing is running well also in the Java1.02 virtual machine of ADK beta3 from IBM under Windows 3.1.

WHAT'S CORBA?

CORBA is the Common Object Request Broker Architecture developed by the OMG (Object Management Group) in order to have a new client server environment in witch objects distributed on different computers in a network can interact. In this dream environment objects(read also instances if you like) written in any OOP language can remotely invoke methods on objects residing on an other computer in the network, passing them parameters and obtaining results. This is really possible because the request of a service is not directly object to object performed, but is transported by a "virtual bus" called ORB or Object Request Broker (fig.4).

In a CORBA distributed objects environment there are server objects and clients performing method invokation on them. It is possible also that servers and clients invert temporaneusly their roles through the use of "callbacks" but I'll not speak about them in this article. In order to obtain an open environment where objects written in different languages can interact, CORBA defines an Interface Description Language(IDL) that enables you to describe the external interface of your objects indipendently by the language you have written them. When you build a server object you must define in a file his IDL interface and after generate from it two "pseudo objects" called "Skeleton" and "Stub" using the tool provided by the CORBA development environments available. The Skeleton must stay with the server object on a server computer while the Stub must stay with the client program in the client computer. Skeleton is a Java class that unmarshals the arguments for the server object and brings together the Java and CORBA object models. Skeleton can make it because it is a Java class that implements the CORBA.Object interface(the root CORBA object). The Stub is a Java class that provides marshaling functions for the argument passed by the client.
 
 

WHAT CORBA CAN DO HERE?

In the next section I describe the realization of a CORBA server object that implement a neural network with only execution capability(not learning). This object loads a synaptic file related to a task and previously created with the "training" program before descripted. Then the execution of the neural network can be invoked on the object, located in an HTTP server, as a method by an applet client. You can see an application of a similar project in an Intranet of a Credit Institute where the CORBA server object resides on the HTTP server and browsers on distributed PC can request his services in a applet. The updating of the neural network know-how in order to satisfy new statistical data, can be made rebuilding the synaptic file only on the server.This operation can be preformed by a neural-networks expert with specific task experience. The task-example that I describe in this article is a toy task where the neural network is trained to recognize profiles of 5 values, classifing them on 5 classes:
mountain, valley, positive slope, negative slope, plane.
ex: the profile 0.3, 0.6, 0.8, 0.5, 0.2 is a hill.
while the profile 0.1, 0.4, 0.8, 0.3, 0.1 is a mountain.
 
 

IMPLEMENTATION OF A
CORBA NEURAL SERVER

In this section you can see the developing steps of a CORBA client-server application entirely written in Java. I must write the following source files:

1) The IDL interface "neur.idl" containing the CORBA interface of the server object "ann.class".

2) The server object "ann.java" containing the method that performs the execution of the neural network

3) The main server "annserv.java" instantiating the server object "ann.class" registering it to the ORB.

4) The client applet "nnclient.java" invoking the method on the remote server object "ann.class". This client has also code to be an application: it is sufficient to comment/decomment some lines/methods in order to have an applet or an application.

5) The HTML file "ann.html" containing the applet (this is necessary only for the applet mode).
 

When I'll arrive to the end of the development process there will be more than five files involved in the client-server application behavior, but the other ones will be created by the development tools provided by the CORBA development kit. In this phase of the project I use the JDK 1.1 from Sun as Java development environment and Visibroker 3.1 from Visigenic as CORBA development kit under Windows95. Now I can explain the development process step by step:

1) Write the IDL file "neur.idl" with the interface of the server object(listing 3). This define only one method that perform the execution of the neural network.

2) Run the Visibroker program that creates some important Java classes from the IDL file:

prompt> idl2java "neur.idl" -no_comments -no_tie
 

This program will create the following files:
The Skeleton : "neurpack.neurImplBase.java" (server)
The Stub: "neurpack._st_neur.java" (client)
The Interface: "neurpack.neur.java" (server)
The Holder: "neurpack.neurHolder.java" (client)
The Helper: "neurpack.neurHelper.java" (client)
The Example: "neurpack._example_neur.java" (server example)
 

3) Write the server object "ann.java". This class must extend the Skeleton class "neurpack.neurImplBase.class" that implements the Interface "neurpack.neur.class" and must contain the body of the method defined in it(listing 4).
The contructor of this class is the same that one present in the "backprop.class" for load the neural network from file. The constructor loads from a file the number of inputs,outputs, hidden neurons of the two hidden levels and the value of any synaptic connection.
So this class is a part of the "backprop.class" with only the execution function adapted in the input/output. The parameter of the "perform()" method is the input array of float. In Java arrays are passed by reference also if they are arrays of primitive types (passed by value). So the client that invoked the method on this remote object, has the float outputs array attribute updated concordly to the response of the neural network.

4) Write the main server class that does the following(listing 5):
a) initialize the ORB
b) initialize the BOA
c) instantiate an "ann" object
d) export the "ann" object to the ORB
e) wait for requests from clients
The CORBA.ORB class is a run time part of VisiBroker implementing in Java the functions specified by OMG in the CORBA::ORB interface. The CORBA.BOA is the Basic Object Adapter providing services that the "ann" server-object can access. This pseudo-object is directly created by the ORB and his service "obj_is_ready(server-object)" exports the server-object to the ORB.

5) Write the applet/application "nnclient.java" that can invokes the method "perform()" on the server object "ann.class". This class must simply extend the Applet(or Frame)class(listing 6). The CORBA related operations are the ORB initialization and the binding to the server objectusing the bind() method of the "neurpack.neurHelper" object.
The CORBA interface object returned by the bind() method is then used to invoke the perform() method on the remote server-object. In order to have an application instead of an applet I've inserted the "main()" method and the "nnclient()" constructor. The source code is explained on the applet/application tranforming.

6) Write the HTML file "nnclient.html" that simply contain the applet (listing 7).

7) Compile all the files (the global procedure is shown in fig.5)

HOW TO RUN THE CLIENT-SERVER APPLICATION

You can test well the application also in a single computer. You must do the following actions:

1) be sure your client is compiled as an application.
2) copy the server related files on a directory and the client related files on an other(or simply copy all the files on the same). Be sure at this step that a copy of neurpack directory is under both the server and the client directory(really you could remove some files in anyone because of server OR client related).
3) start the Visibroker OSAgent: this program provides fault-tolerant location services and must be running on at least one machine in the LAN environment.
4) go to the server directory and start the server:
prompt> vbj annserv
5) go to the client directory and start the client:
prompt> vbj nnclient
6) the frame of the client will appear.
7) fill the 5 input fields with float values in the range 0.0 1.0 so that they describe a shape like hill, valley, negative pendence or positive pendence
8) press the "RUN" button and see the result on the 5 output fields that have the following means:
mountain - valley - positive_slope - negative_slope - plane
 
 

HOW TO RUN THE CLIENT-SERVER APPLET

In order to test the client(applet)/server system on a real HTTP connection a single machine you need to do the following:

1) be sure your client is compiled as an applet.
2) install the CORBA client-server classes and the "neurpack" package on the HTTP server in a directory.
3) install the "nnclient.html" in the same directory.
4) start the Visibroker OSAgent.
5) start the Visibroker "IIOP GateKeeper" that behaves like a proxy enabling the applet to invoke an object server on a host other than the one from witch the applet originated.In this case it behaves also like an HTTP server:
prompt> gatekeeper -ORBbackCompat true
(start in the same directory where is the html file).
The "-ORBbackCompat true" option is necessary to have compatibility between gatekeeper 3.0 and previous versions of Visibroker(ex: Visibroker 2.5 on Netscape Communictor 4.0)
6) from the server dirctory start the main server program:
prompt> vbj annserv
7) from the client directory run the browser and load the URL of the Web page "ann.html":
http://YOUR_MACHINE:15000/ann.htm (15000 is the default port of gatekeeper)
8) fill the 5 input fields with float values in the range 0.0 1.0 so that they describe an altimetric profile.
9) press the "RUN" button and see the result on the 5 output fields that have the following means:
mountain - valley - positive_slope - negative_slope - plane


CONCLUSION

While this program is not trivial it locates in the toys-programs class due to many choices made in order to semplify the description of the global behavior and put the attention to the topic arguments: a neural engine in Java that shows how Java can match well sophisticated tasks and a CORBA client-server solution that shows a beat of the good marriage Java-CORBA.

 NOTE: the listing are not actually published but may be them will be available for downlaod with compiled classes in future.
 
 



[ HOME ]