patternMinor
ANFIS network based on Sugeno model I
Viewed 0 times
sugenonetworkbasedanfismodel
Problem
I've been learning Common Lisp lately and I've implemented ANFIS network based on Sugeno model I.
Network layout and details can be read in these slides by Adriano Oliveira Cruz.
I use sigmoid as the fuzzy set membership function of each input (in layer 1)
\$
\mu(x) = \sigma(x) = \frac{1}{(1 + e^{b * (x - a)})}
\$
T-norm is a simple product (layer 2)
\$
w = \prod_i^n\mu(x_i)
\$
then those results are normalized in layer 3
\$
\overline{w_i} = \frac{w_i}{\sum_j^rw_j}
\$
which are used in layer 4 as a consequent of a rule which then outputs:
\$
\overline{w}f = \overline{w}*(px + qy + r)
\$
Final 5th layer just sums all the \$r\$ rules' consequents:
\$
\sum_i^r\overline{w_i}f_i
\$
Parameters \$a, b, p, q, r\$ are optimized using (online) gradient descent using this (for input dimension being 2):
\$
\delta = (t - o)
\$
\$
a_i^{(k+1)} \leftarrow a_i^{(k)} + \eta\delta\frac{\sum_{j \neq i}^r w_j(f_i - f_j)}{(\sum_j^rw_j)^2}\mu_i(y)b_i\mu_i(x)(1 - \mu_i(x))
\$
\$
b_i^{(k+1)} \leftarrow b_i^{(k)} - \eta\delta\frac{\sum_{j \neq i}^r w_j(f_i - f_j)}{(\sum_j^rw_j)^2}\mu_i(y)(x - a_i)\mu_i(x)(1 - \mu_i(x))
\$
\$
p_i^{(k+1)} \leftarrow p_i^{(k)} + \eta\delta\overline{w_i}x
\$
\$
q_i^{(k+1)} \leftarrow q_i^{(k)} + \eta\delta\overline{w_i}y
\$
\$
r_i^{(k+1)} \leftarrow r_i^{(k)} + \eta\delta\overline{w_i}
\$
where \$t\$ is expected and \$o\$ network output and \$k\$ is iteration. For batch gradient descent just add sum for all samples after \$\eta\$.
Parameters in code are stored as 2 arrays. One array for premise parameters \$a, b\$ for each rule and input dimension. So if dimension of input is \$n\$ and there are \$r\$ rules array length is \$2nr\$.
The other array is consequent parameters which are stored in this order: \$r, p, q\$ per rule and the length of array is \$3*r\$.
Here is the implementation:
```
(defclass anfis ()
((rules :initarg :rules :reader rules
:type (integer 1) :documentation "Number of rules.")
(input-dim :initarg :input-dim
Network layout and details can be read in these slides by Adriano Oliveira Cruz.
I use sigmoid as the fuzzy set membership function of each input (in layer 1)
\$
\mu(x) = \sigma(x) = \frac{1}{(1 + e^{b * (x - a)})}
\$
T-norm is a simple product (layer 2)
\$
w = \prod_i^n\mu(x_i)
\$
then those results are normalized in layer 3
\$
\overline{w_i} = \frac{w_i}{\sum_j^rw_j}
\$
which are used in layer 4 as a consequent of a rule which then outputs:
\$
\overline{w}f = \overline{w}*(px + qy + r)
\$
Final 5th layer just sums all the \$r\$ rules' consequents:
\$
\sum_i^r\overline{w_i}f_i
\$
Parameters \$a, b, p, q, r\$ are optimized using (online) gradient descent using this (for input dimension being 2):
\$
\delta = (t - o)
\$
\$
a_i^{(k+1)} \leftarrow a_i^{(k)} + \eta\delta\frac{\sum_{j \neq i}^r w_j(f_i - f_j)}{(\sum_j^rw_j)^2}\mu_i(y)b_i\mu_i(x)(1 - \mu_i(x))
\$
\$
b_i^{(k+1)} \leftarrow b_i^{(k)} - \eta\delta\frac{\sum_{j \neq i}^r w_j(f_i - f_j)}{(\sum_j^rw_j)^2}\mu_i(y)(x - a_i)\mu_i(x)(1 - \mu_i(x))
\$
\$
p_i^{(k+1)} \leftarrow p_i^{(k)} + \eta\delta\overline{w_i}x
\$
\$
q_i^{(k+1)} \leftarrow q_i^{(k)} + \eta\delta\overline{w_i}y
\$
\$
r_i^{(k+1)} \leftarrow r_i^{(k)} + \eta\delta\overline{w_i}
\$
where \$t\$ is expected and \$o\$ network output and \$k\$ is iteration. For batch gradient descent just add sum for all samples after \$\eta\$.
Parameters in code are stored as 2 arrays. One array for premise parameters \$a, b\$ for each rule and input dimension. So if dimension of input is \$n\$ and there are \$r\$ rules array length is \$2nr\$.
The other array is consequent parameters which are stored in this order: \$r, p, q\$ per rule and the length of array is \$3*r\$.
Here is the implementation:
```
(defclass anfis ()
((rules :initarg :rules :reader rules
:type (integer 1) :documentation "Number of rules.")
(input-dim :initarg :input-dim
Solution
There are lots of minor improvements possible to your code.
The biggest problems though is: unclear function interfaces.
I have no idea what
Either write comments for those, document the basic data structures somewhere or actually do it in Lisp code. Type declarations can document the interface and also help at runtime to find errors. Some compilers might even use them for compile-time type checking.
Using Clozure Common Lisp:
The biggest problems though is: unclear function interfaces.
(defun output-consequent-layer (anfis prev-output input)I have no idea what
anfis, prev-output or input actually is.Either write comments for those, document the basic data structures somewhere or actually do it in Lisp code. Type declarations can document the interface and also help at runtime to find errors. Some compilers might even use them for compile-time type checking.
Using Clozure Common Lisp:
? (defclass foo ()
((size :type (integer 0 200) :initarg :size)))
#
? (make-instance 'foo :size "ded")
> Error: The value "ded", derived from the initarg :SIZE, can not be used to set the value of the slot SIZE in #, because it is not of type (MOD 201).
> While executing: CCL::%SHARED-INITIALIZE, in process Listener(4).
> Type cmd-. to abort, cmd-\ for a list of available restarts.
> Type :? for other options.
1 >
? (defun foo (size)
(declare (type (integer 0 200) size))
(check-type size (integer 0 200))
size)
FOO
? (foo 300)
> Error: The value 300 is not of the expected type (INTEGER 0 200).
> While executing: FOO, in process Listener(4).
> Type cmd-. to abort, cmd-\ for a list of available restarts.
> Type :? for other options.
1 >
? (defmethod bar ((size integer)) size)
#
? (bar "def")
> Error: There is no applicable method for the generic function:
> #
> when called with arguments:
> ("def")Code Snippets
(defun output-consequent-layer (anfis prev-output input)? (defclass foo ()
((size :type (integer 0 200) :initarg :size)))
#<STANDARD-CLASS FOO>
? (make-instance 'foo :size "ded")
> Error: The value "ded", derived from the initarg :SIZE, can not be used to set the value of the slot SIZE in #<FOO #x302000D7267D>, because it is not of type (MOD 201).
> While executing: CCL::%SHARED-INITIALIZE, in process Listener(4).
> Type cmd-. to abort, cmd-\ for a list of available restarts.
> Type :? for other options.
1 >
? (defun foo (size)
(declare (type (integer 0 200) size))
(check-type size (integer 0 200))
size)
FOO
? (foo 300)
> Error: The value 300 is not of the expected type (INTEGER 0 200).
> While executing: FOO, in process Listener(4).
> Type cmd-. to abort, cmd-\ for a list of available restarts.
> Type :? for other options.
1 >
? (defmethod bar ((size integer)) size)
#<STANDARD-METHOD BAR (INTEGER)>
? (bar "def")
> Error: There is no applicable method for the generic function:
> #<STANDARD-GENERIC-FUNCTION BAR #x302000D3C9EF>
> when called with arguments:
> ("def")Context
StackExchange Code Review Q#79391, answer score: 4
Revisions (0)
No revisions yet.