ART2 demo

Adaptive Resonance Theory Neural Networks by Aman Ahuja | github.com/amanahuja | twitter: @amanqa

Overview

In this example:

  • We'll use 10x10 binary ASCII blocks to demonstrate ART2
  • Yes, this is the same data we used for ART1

In [1]:
%load_ext autoreload

In [2]:
%autoreload 2

In [6]:
import os
import numpy as np
from IPython.display import Image

In [7]:
# make sure we're in the root directory

pwd = os.getcwd()
if pwd.endswith('ipynb'):
    os.chdir('..')
    
#print os.getcwd()

ART2 Architecture


In [10]:
Image("data/architecture_art2.png", width=500)


Out[10]:

Mini ART2 tests

From the book


In [11]:
from ART2 import ART2

# This is my data! 
idata = np.array([0.8, 0.6])

nn = ART2(n=len(idata), m=2, rho=0.9, theta=0.1)
nn.start_logging(to_file=False, to_console=True)
nn.learning_trial(idata = idata)
nn.stop_logging()


    INFO:Start Logging
    INFO:Starting Learning Trial.
   DEBUG:input pattern: [ 0.8  0.6]
   DEBUG:theta: 0.1
   DEBUG:zero'ing activations
    INFO:Updating F1 activations
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.  0.]
   DEBUG:	wi : [ 0.8  0.6]
   DEBUG:	pi : [ 0.  0.]
   DEBUG:	xi : [ 0.799992  0.599994]
   DEBUG:	qi : [ 0.  0.]
   DEBUG:	vi : [ 0.799992  0.599994]
    INFO:Updating F1 activations
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.799992  0.599994]
   DEBUG:	wi : [ 8.79992  6.59994]
   DEBUG:	pi : [ 0.799992  0.599994]
   DEBUG:	xi : [ 0.79999927  0.59999945]
   DEBUG:	qi : [ 0.799992  0.599994]
   DEBUG:	vi : [ 8.79991927  6.59993945]
    INFO:candidate selection loop iter start
   DEBUG:	yj: [ 6.99993  6.99993]
   DEBUG:	picking J = 0
    INFO:	Reset is False: Candidate is good.
    INFO:Updating F1 activations
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.79999927  0.59999945]
   DEBUG:	wi : [ 8.79999273  6.59999455]
   DEBUG:	pi : [ 0.79999927  0.59999945]
   DEBUG:	xi : [ 0.79999927  0.59999945]
   DEBUG:	qi : [ 0.799992  0.599994]
   DEBUG:	vi : [ 8.79991927  6.59993946]
    INFO:Weight update using first-pattern shortcut
   DEBUG:Tji[J]: [ 7.99999273  5.99999455]
   DEBUG:Bij[J]: [ 7.99999273  5.99999455]
    INFO:Stop Logging.

F2 activations $y_j$

Cluster unit activations are:

$$y_j = \sum_{i}{b_{ij}}{p_i}$$

given by

np.dot(art2.Bij.T, art2.pi)


In [12]:
print nn.Bij.T
print 
print nn.Tji


[[ 7.99999273  5.99999455]
 [ 5.          5.        ]]

[[ 7.99999273  5.99999455]
 [ 0.          0.        ]]

In [13]:
nn.start_logging()

# second pattern
idata = np.array([0.6, 0.8])

nn.learning_trial(idata = idata)
nn.stop_logging()


    INFO:Start Logging
    INFO:Starting Learning Trial.
   DEBUG:input pattern: [ 0.6  0.8]
   DEBUG:theta: 0.1
   DEBUG:zero'ing activations
    INFO:Updating F1 activations
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.  0.]
   DEBUG:	wi : [ 0.6  0.8]
   DEBUG:	pi : [ 0.  0.]
   DEBUG:	xi : [ 0.599994  0.799992]
   DEBUG:	qi : [ 0.  0.]
   DEBUG:	vi : [ 0.599994  0.799992]
    INFO:Updating F1 activations
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.599994  0.799992]
   DEBUG:	wi : [ 6.59994  8.79992]
   DEBUG:	pi : [ 0.599994  0.799992]
   DEBUG:	xi : [ 0.59999945  0.79999927]
   DEBUG:	qi : [ 0.599994  0.799992]
   DEBUG:	vi : [ 6.59993945  8.79991927]
    INFO:candidate selection loop iter start
   DEBUG:	yj: [ 9.59989527  6.99993   ]
   DEBUG:	picking J = 0
    INFO:	Reset is False: Candidate is good.
    INFO:Updating F1 activations
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.59999945  0.79999927]
   DEBUG:	wi : [ 6.59999455  8.79999273]
   DEBUG:	pi : [ 0.59999945  0.79999927]
   DEBUG:	xi : [ 0.59999945  0.79999927]
   DEBUG:	qi : [ 0.599994  0.799992]
   DEBUG:	vi : [ 6.59993946  8.79991927]
    INFO:Entering Resonance phase with J = 0
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.89199283  6.10799445]
   DEBUG:Bij[J]: [ 7.89199283  6.10799445]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.59999945  0.79999927]
   DEBUG:	wi : [ 6.59999455  8.79999273]
   DEBUG:	pi : [ 7.702793    6.29719428]
   DEBUG:	xi : [ 0.59999945  0.79999927]
   DEBUG:	qi : [ 0.77420724  0.6329306 ]
   DEBUG:	vi : [ 8.34207183  7.12930526]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78982492  6.21016235]
   DEBUG:Bij[J]: [ 7.78982492  6.21016235]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.76020259  0.64968469]
   DEBUG:	wi : [ 8.20202593  7.29684689]
   DEBUG:	pi : [ 7.77104502  6.23883081]
   DEBUG:	xi : [ 0.74713007  0.66467648]
   DEBUG:	qi : [ 0.77979024  0.62603927]
   DEBUG:	vi : [ 8.54503249  6.92506922]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.77968377  6.22564332]
   DEBUG:Bij[J]: [ 7.77968377  6.22564332]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77690338  0.6296184 ]
   DEBUG:	wi : [ 8.36903376  7.09618397]
   DEBUG:	pi : [ 7.77861877  6.23269738]
   DEBUG:	xi : [ 0.76272485  0.64672172]
   DEBUG:	qi : [ 0.78038808  0.62529388]
   DEBUG:	vi : [ 8.56660564  6.89966055]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.77910867  6.22945251]
   DEBUG:Bij[J]: [ 7.77910867  6.22945251]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77880721  0.62726191]
   DEBUG:	wi : [ 8.38807215  7.0726191 ]
   DEBUG:	pi : [ 7.78000502  6.23376917]
   DEBUG:	xi : [ 0.76450712  0.64461387]
   DEBUG:	qi : [ 0.78038999  0.6252915 ]
   DEBUG:	vi : [ 8.56840698  6.8975289 ]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.7795927   6.23178351]
   DEBUG:Bij[J]: [ 7.7795927   6.23178351]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77896629  0.62706435]
   DEBUG:	wi : [ 8.38966294  7.07064347]
   DEBUG:	pi : [ 7.78059972  6.23566951]
   DEBUG:	xi : [ 0.76465608  0.64443716]
   DEBUG:	qi : [ 0.7803203   0.62537846]
   DEBUG:	vi : [ 8.56785909  6.8982218 ]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78013649  6.23388195]
   DEBUG:Bij[J]: [ 7.78013649  6.23388195]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77891594  0.6271269 ]
   DEBUG:	wi : [ 8.38915936  7.07126898]
   DEBUG:	pi : [ 7.78103878  6.23762065]
   DEBUG:	xi : [ 0.76460893  0.64449311]
   DEBUG:	qi : [ 0.78024204  0.62547611]
   DEBUG:	vi : [ 8.56702929  6.89925417]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78062373  6.23590085]
   DEBUG:Bij[J]: [ 7.78062373  6.23590085]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77884042  0.62722069]
   DEBUG:	wi : [ 8.38840416  7.07220686]
   DEBUG:	pi : [ 7.78140177  6.23953145]
   DEBUG:	xi : [ 0.76453821  0.644577  ]
   DEBUG:	qi : [ 0.78016277  0.62557497]
   DEBUG:	vi : [ 8.56616595  6.90032668]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78104387  6.23786137]
   DEBUG:Bij[J]: [ 7.78104387  6.23786137]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.7787619   0.62731817]
   DEBUG:	wi : [ 8.38761901  7.07318167]
   DEBUG:	pi : [ 7.78170139  6.2413934 ]
   DEBUG:	xi : [ 0.76446469  0.64466419]
   DEBUG:	qi : [ 0.78008343  0.62567391]
   DEBUG:	vi : [ 8.56529895  6.90140331]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78139893  6.23976867]
   DEBUG:Bij[J]: [ 7.78139893  6.23976867]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77868306  0.62741603]
   DEBUG:	wi : [ 8.3868306   7.07416029]
   DEBUG:	pi : [ 7.7819421   6.24320783]
   DEBUG:	xi : [ 0.76439086  0.64475172]
   DEBUG:	qi : [ 0.7800041  0.6257728]
   DEBUG:	vi : [ 8.56443187  6.90247974]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78169224  6.24162582]
   DEBUG:Bij[J]: [ 7.78169224  6.24162582]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77860421  0.62751387]
   DEBUG:	wi : [ 8.38604214  7.07513873]
   DEBUG:	pi : [ 7.78212723  6.24497711]
   DEBUG:	xi : [ 0.76431703  0.64483924]
   DEBUG:	qi : [ 0.77992481  0.62587162]
   DEBUG:	vi : [ 8.56356514  6.90355545]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78192713  6.24343551]
   DEBUG:Bij[J]: [ 7.78192713  6.24343551]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.7785254   0.62761165]
   DEBUG:	wi : [ 8.38525399  7.07611652]
   DEBUG:	pi : [ 7.78225982  6.24670361]
   DEBUG:	xi : [ 0.76424324  0.6449267 ]
   DEBUG:	qi : [ 0.77984556  0.62597037]
   DEBUG:	vi : [ 8.5626988  6.9046304]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78210678  6.24520029]
   DEBUG:Bij[J]: [ 7.78210678  6.24520029]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77844662  0.62770936]
   DEBUG:	wi : [ 8.3844662   7.07709361]
   DEBUG:	pi : [ 7.78234272  6.24838962]
   DEBUG:	xi : [ 0.76416948  0.6450141 ]
   DEBUG:	qi : [ 0.77976634  0.62606905]
   DEBUG:	vi : [ 8.56183287  6.90570458]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78223419  6.24692253]
   DEBUG:Bij[J]: [ 7.78223419  6.24692253]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77836788  0.627807  ]
   DEBUG:	wi : [ 8.38367877  7.07807   ]
   DEBUG:	pi : [ 7.78237865  6.25003727]
   DEBUG:	xi : [ 0.76409575  0.64510144]
   DEBUG:	qi : [ 0.77968716  0.62616766]
   DEBUG:	vi : [ 8.56096732  6.90677799]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.7823122   6.24860449]
   DEBUG:Bij[J]: [ 7.7823122   6.24860449]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77828917  0.62790457]
   DEBUG:	wi : [ 8.3828917   7.07904571]
   DEBUG:	pi : [ 7.78237015  6.25164861]
   DEBUG:	xi : [ 0.76402206  0.64518871]
   DEBUG:	qi : [ 0.77960801  0.62626619]
   DEBUG:	vi : [ 8.56010216  6.90785065]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78234349  6.25024832]
   DEBUG:Bij[J]: [ 7.78234349  6.25024832]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.7782105   0.62800207]
   DEBUG:	wi : [ 8.38210498  7.08002072]
   DEBUG:	pi : [ 7.78231964  6.25322556]
   DEBUG:	xi : [ 0.7639484   0.64527592]
   DEBUG:	qi : [ 0.7795289   0.62636466]
   DEBUG:	vi : [ 8.55923739  6.90892257]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78233061  6.25185603]
   DEBUG:Bij[J]: [ 7.78233061  6.25185603]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77813186  0.62809951]
   DEBUG:	wi : [ 8.38131861  7.08099506]
   DEBUG:	pi : [ 7.78222941  6.25476993]
   DEBUG:	xi : [ 0.76387478  0.64536307]
   DEBUG:	qi : [ 0.77944982  0.62646307]
   DEBUG:	vi : [ 8.55837299  6.90999374]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78227596  6.25342953]
   DEBUG:Bij[J]: [ 7.78227596  6.25342953]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77805326  0.62819687]
   DEBUG:	wi : [ 8.38053258  7.08196872]
   DEBUG:	pi : [ 7.78210163  6.25628345]
   DEBUG:	xi : [ 0.76380119  0.64545017]
   DEBUG:	qi : [ 0.77937078  0.6265614 ]
   DEBUG:	vi : [ 8.55750896  6.91106417]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78218182  6.25497065]
   DEBUG:Bij[J]: [ 7.78218182  6.25497065]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77797469  0.62829417]
   DEBUG:	wi : [ 8.37974689  7.08294171]
   DEBUG:	pi : [ 7.78193833  6.25776776]
   DEBUG:	xi : [ 0.76372764  0.6455372 ]
   DEBUG:	qi : [ 0.77929177  0.62665967]
   DEBUG:	vi : [ 8.5566453   6.91213388]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78205033  6.25648109]
   DEBUG:Bij[J]: [ 7.78205033  6.25648109]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77789615  0.6283914 ]
   DEBUG:	wi : [ 8.37896153  7.08391404]
   DEBUG:	pi : [ 7.78174145  6.25922438]
   DEBUG:	xi : [ 0.76365411  0.64562417]
   DEBUG:	qi : [ 0.77921279  0.62675787]
   DEBUG:	vi : [ 8.55578201  6.91320286]
    INFO:learning iter start
    INFO:Updating Weights
   DEBUG:Tji[J]: [ 7.78188354  6.25796247]
   DEBUG:Bij[J]: [ 7.78188354  6.25796247]
    INFO:Updating F1 activations with J = 0
   DEBUG:	--- debug values --- 
   DEBUG:	ui : [ 0.77781765  0.62848857]
   DEBUG:	wi : [ 8.37817651  7.08488571]
   DEBUG:	pi : [ 7.78151284  6.26065479]
   DEBUG:	xi : [ 0.76358062  0.64571109]
   DEBUG:	qi : [ 0.77913384  0.626856  ]
   DEBUG:	vi : [ 8.55491907  6.91427112]
    INFO:Stop Logging.
# bookmark: py 264 example 5.8 # try slow learning? skipping # spanning tree test skipping # ASCII character recog?

[Load data]

  • Data is a series of png images
  • pixelated drawings of letters

In [14]:
# data directory
data_dir = 'data'
print os.listdir(data_dir)

# ASCII data file
data_file = 'ASCII_01.txt'


['lettericons', 'ASCII_01.txt', 'architecture_art2.png']

In [16]:
with open(os.path.join(data_dir, data_file), 'r') as f: 
    raw_data = f.read()
    
# Get data into a usable form here
data = [d.strip() for d in raw_data.split('\n\n')]
data = [d for d in data if d is not '']

data = [d.replace('\n', '') for d in data]

# print the data
data


Out[16]:
['XXXXXX...XX...XX...XXXXXX',
 'XXXXXX...X....XX...XXXXXX',
 '.XXXXX...XX...XX...XXXX.X',
 'XXX.XX...XX...XX...XX.XXX',
 'X...X.X.....X.....X.X...X',
 'XX..X...X.......X.X.X...X',
 'X...XXX.X...X...X...X..XX',
 'X..XXXX.X.......X.X.X...X',
 'X...X.X.X...X...X.X.X...X',
 'X...X.X..X..X...X.X.X...X',
 'X...XXX.X...X...X.X.X...X',
 '.XXXXX....X....X.....XXXX',
 '..X.XX....X....X....XXXXX',
 '.XXX.X..XXX...X.X..XX.X.X',
 '..XXXX....X....X.......XX',
 '.XXXXX...XX...XX...XXXXXX',
 '..XXXX....XX...X.....X.XX',
 'XXXXXX..XXX...XXX..XXXXXX',
 'XXX..X...XX...XX...X.XXX.',
 'X.X.XX...XX...XX...X.XXX.',
 'X..XX.X.X...X...X.XXX...X',
 '..X..X...XX...XX...X.XXX.',
 '..XXXX....X....XX......XX',
 '...XXXX...X.....X....XXXX',
 '..XXX.X...X....XX....XXXX',
 '...XXX....X....X....X.XXX',
 '...XXXX...X....XX...XX.XX']

Helper functions


In [26]:
def format_output(raw):
    out = "{}\n{}\n{}\n{}\n{}".format(
        raw[:5],
        raw[5:10],
        raw[10:15],
        raw[15:20],
        raw[20:25],
    )
    return out

from collections import Counter
import numpy as np

def preprocess_data(data): 
    """
    Convert to numpy array
    Convert to 1s and 0s
    
    """
    # Get useful information from first row
    if data[0]: 
        irow = data[0]

        # get size
        idat_size = len(irow)

        # get unique characters
        chars = False
        while not chars: 
            chars = get_unique_chars(irow, reverse=True)
        char1, char2 = chars

    outdata = []
    idat = np.zeros(idat_size, dtype=bool)

    #convert to boolean using the chars identified
    for irow in data:
        assert len(irow) == idat_size, "data row lengths not consistent"
        idat = [x==char1 for x in irow]
        # note: idat is a list of bools
        idat =list(np.array(idat).astype(int))
        outdata.append(idat)
    
    outdata = np.array(outdata)
    return outdata.astype(int)

def get_unique_chars(irow, reverse=False):
    """
    Get unique characters in data
    Helper function
    ---- 
    reverse:   bool
        Reverses order of the two chars returned
    """
    chars = Counter(irow)
    if len(chars) > 2: 
        raise Exception("Data is not binary")
    elif len(chars) < 2: 
        # first row doesn't contain both chars
        return False, False

    # Reorder here?
    if reverse: 
        char2, char1 = chars.keys()
    else: 
        char1, char2 = chars.keys()
    
    return char1, char2

In [27]:
# Examine one

print format_output(data[0])


XXXXX
X...X
X...X
X...X
XXXXX

DO


In [24]:
from ART2 import ART2

In [28]:
from collections import defaultdict

# create network

input_row_size = 25
max_categories = 10
rho = 0.20

network = ART2(n=input_row_size, m=max_categories, rho=rho)

# preprocess data
data_cleaned = preprocess_data(data)

# shuffle data? 
np.random.seed(1221)
np.random.shuffle(data_cleaned)

# learn data array, row by row
for row in data_cleaned:
    network.learn(row)

print
print "n rows of data:         ", len(data_cleaned)
print "max categories allowed: ", max_categories
print "rho:                    ", rho

print "n categories used:      ", network.n_cats
print


# output results, row by row
output_dict = defaultdict(list)

for row, row_cleaned in zip (data, data_cleaned): 
    pred = network.predict(row_cleaned)
    output_dict[pred].append(row)

for k,v in output_dict.iteritems():
    print "category: {}, ({} members)".format(k, len(v))
    print '-'*20
    for row in v: 
        print format_output(row)
        print
    print 
#   \  print "'{}':{}".format(
#         row, 
#         network.predict(row_cleaned))


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-28-8c0ce12645e7> in <module>()
     18 # learn data array, row by row
     19 for row in data_cleaned:
---> 20     network.learn(row)
     21 
     22 print

AttributeError: 'ART2' object has no attribute 'learn'