My least favorite part of JSON…

I love how simple the JSON spec is. I never enjoyed reading through all the XML closures, etc. JSON just feels more programming so you don’t have to shift your brain as much as you do with XML.

However, I hate that ” is the only quoting character you can use. I’ve come to love python’s equal tolerance for ‘c’ and “c”.

I like that JSON’s simple but wish it was simply more accommodating.

Posted in code, frustration, uncategorized | Comments Off on My least favorite part of JSON…

Training Neural Nets with CouchDB – part 3

Hopefully you’ve been following parts 1 and 2 and I didn’t leave anyone too confused by my approach.

Please visit my posts for a far better recap then I can provide here (DRY); In part 1, I introduced the overall project discussed the django layout and focused on the jquery I/O part. My goal in part 2 was to show some of the underlying mechanics of how we triggered a neuron as well as queried couchdb for info.

I know we honed in on some serious specifics but now that we’ve got those specifics I’d like to step back and put together the pieces.

If you check out a copy of the interface (which doesn’t have the NN backend) you can get a sense of the I/O process. In the full application here’s the process;

(0) When a user clicks anywhere on the page that’s sent to our django URL and (1) django records the location then (2) queries our neural net for a guess. (Step 6) This guess will be sent back to the page to move the second coordinate box, and in the sample is set to be equal to the click location. However, before returning the guess, (3,4) the difference between the guess and the actual click is sent to the network so it can train for next time. Also, (5) the input nodes need to be set to the click location so that next time the net can base it’s output on your previous click.

Here’s the relevant code;

#get the clicked coordinates
click_X = int(request.POST[‘X’])
click_Y = int(request.POST[‘Y’])

#Figure out what the net would have guessed
guess_X = int(get_output(“output_x”))
guess_Y = int(get_output(“output_y”))

#Find the error and propagate that back to the net
error_X = float(click_X) – float(guess_X)
error_Y = float(click_Y) – float(guess_Y)
back_prop(“output_x”, error_X)
back_prop(“output_y”, error_Y)

#Set the inputs for next time
set_input_weight(“input_x”, “static”, request.POST[‘X’])
set_input_weight(“input_y”, “static”, request.POST[‘Y’])

#return the guess to jQuery
return HttpResponse( “{ “X”: %s, “Y”: %s}” % (guess_X, guess_Y) )

Now I know you only know how a neuron is defined and have no idea of our neural net structure but I think that process will be very illustrative.

Since our net needs to predict X and Y coordinates we need to have two output nodes which I’ve named “output_x” and “output_y” and similarly we have “input_x” and “input_y” in order to inject the coordinate values into the network. You can see the keyword “static” trick that we discussed previously being used.

Neural Nets are typically called “Feed Forward Neural Nets” because you stimulate node “A” and then things cascade A -> B ->C and you can read the output at “C”.

However, programtically this can be a royal pain.

  • In some situations you’d need a clock to sync with so you can ensure that you’re reading the n’th output of C and not the n+1 (e.g. if the input to A was controlled via a separate thread then things could shift underneath you before you read the values).
  • You could also build this communication via a messaging service. Node “A” could broadcast its output at a given time and then use a pub/sub model so interested nodes could be alerted as events progressed.

The last approach probably scales the best if you had a ready queuing mechanism then I’d go this way for larger networks. This is more apparent when you realize that “A,B & C” aren’t necessarially single nodes.

Neural nets are commonly built with layers, each of which typically contains multiple nodes all of which are connected to all of the nodes in the previous and subsequent layers.

So in my case “A” is the first layer containing “input_x” and “input_y” and “C” is the output layer containing “output_x” and “output_y”. Layer B would have many nodes all receiving the output from both nodes in layer A. (As an aside you can have more complicated layering systems, for example “output_x” might also have a direct link from “input_x” to further augment it’s correlation and it is legal for a layer to only have a single node.)

So you’ve the “API” for our neural net and part 2 covers the underlying mathematical (and procedural) mechanics so I should be able to wrap up next time by discussing how to get this thing off the ground and see how it works!

Posted in code, couchdb, python | Comments Off on Training Neural Nets with CouchDB – part 3

You get what you pay for…

If you read this post on the site as opposed to via RSS you may have noticed the Theme change (and now be wondering why I changed it back).

The trial them was ASCII-one and other then not being able to figure out how to remove some of my sidebar contents I thought it was spectacular.

However, a friend informed me that he was unable to post a comment and I can only ascribe this to the update (or truthfully it could have been the migration to WordPress 2.7-RC1).

So I thought I’d switch back to the old one for now and test things out and give things time to bake.

I know most of you don’t post comments here anyway so it likely doesn’t matter. I actual prefer it that way believe it or not. Well I don’t mean I don’t like the feedback and input but I get most of it via twitter and that’s just fine with me.

Personally I’d love it if WP just allowed pingbacks and no comments except via twitter. I mean that every post page should have a list of the times it was twittered and / or posted.

I just don’t think every WP should have to maintain it’s own user authentication system, and judging by the constant “new user registrations” which look like spammers to me, I’d be happy not to.

Posted in uncategorized | 1 Comment

Training Neural Nets with CouchDB – part 2

It’s always nice to have a little encouragement especially when trying to work through some tough posts. I really prefer white boards and pictures but I find these too hard to make for blogging so I try to let the words shape the images in your mind.

So let’s get started with your first exercise… picture or graph the output of tanh() from [-1,1]. For those who will skip the process of pulling out their graphing calculator, you’ll get a sinusoidal curve, i.e. shaped like an “S”, with asymptotes at y=-1 and y=1.

So, I know that’s neat and all but what does it have to do with couchdb? Well it doesn’t per say but it represents our “trigger” function for our neurons. We’ll use this to convert a nodes input to its output, and let’s call this function sigmoid().

The input to this function is actually the weight our node attributes to a specific input. So let’s say I’m a node, N, and I have an input, I. That input will be a value, numeric in this case, and I’ll assign it a weight, W. That weight will correlate with my “trust” in that input (after an appropriate training process). But the key part now is that the output, O, of N will be; O = I * sigmoid(W).

If you play around and graph some of this, you’ll see that if I don’t “trust” I, and W approaches 0 then even if I is a very big number O will be near 0 also.

Before we get into this business of trust let me give you two functions;

def sigmoid(x):
return tanh(float(x))

def slope_sigmoid(y):
return 1.0-y*y

Let me comment on that slope function there. The slope tells us how “drastic” a small change will make our output and we’ll use this function in order to adjust our weights appropriately. This is important because if we’re at the center of our sigmoid (x=.5) and want to reinforce the weight then we may only need to move it by +.01 but if we’re at an extreme on our curve (e.g. x = -.8) then we may need to adjust the weight by -.1 (i.e. 10 times as much) in order to achieve a noticeable change.

OK, let’s talk about that mythic “trust” factor and in order to do that let’s talk about neural nets. NN’s are build by collecting Neurons, connecting outputs to inputs (not usually circular but they can be) and then stimulating an input layer with a set of values and reading an output layer to see what it produced.

Here’s, in psuedo python, is how I represented a neuron;

class neuron():

name = “”

inputs = []

It’s relatively a simple structure. Neuron’s have a name (which are forced to be unique) and a set of inputs (which is actually a list of dictionaries). An important thing to clarify is that I never actually had to define this class, since CouchDB doesn’t demand a schema; Let’s make this a bit more concrete with three examples;

>>> nn[‘input_x’]
<Document u’input_x’@u’82302167′ {u’inputs’: [{u’node’: u’static’, u’weight’: u’474′}], u’increment’: 0}>
>>> nn[‘1′]
<Document u’1’@u’2027135756′ {u’inputs’: [{u’node’: u’input_x’, u’weight’: 1}, {u’node’: u’input_y’, u’weight’: -1}], u’increment’: 0}>
>>> nn[‘output_x’]
<Document u’output_x’@u’1458836188′ {u’inputs’: [{u’node’: u’1′, u’weight’: 1}, {u’node’: u’2′, u’weight’: 9.536375211640632e+179}, {u’node’: u’3′, u’weight’: -194411155905.33661}], u’increment’: 0}>

Hopefully that shows up ok on your browser. The variable “nn” is a link to the “neural_net” database on my couchdb server;

try:
server = couchdb.Server(‘http://127.0.0.1:5984’)
nn = server[‘neural_net’]
len(nn)
except couchdb.client.ResourceNotFound:
server.create(‘neural_net’)
nn = server[‘neural_net’]
len(nn)

I’ve printed out three neuron nodes; The first node, ‘input_x’, is part of the input layer and you’ll see it has list ‘inputs’ with a single dictionary element { ‘node’: ‘…’, ‘weight’: ‘…’ }. I’ve opted to use the name “static” as a keyword to represent an input which doesn’t point to another node and use the ‘weight’ as the actual input value. The second node ‘1’ is more of a typical neuron which would be considered a “second level neuron”. This takes two inputs, one from ‘input_x’ and one from ‘input_y’. The output of “1” will be;

for input in nn[‘1’][‘inputs’]

output += get_output(inputs[‘node’]) * sigmoid(input[‘weight’])

Note I used a function, called “get_output” to find the output value of a node. If the node is static, as ‘input_x’ is, then we could simply dereference it and get the “weight” value but if the input is another “pure” neuron then it may have some calculations to do.You can see how this would work in practice by examining the final node, ‘output_x’. In this case we have to query many nodes just like node “1” and allow it to do it’s calculation before we can output our values. So a call to “get_output(“output_x'”) actually recurses to the various nodes in turn.

Let me take a moment to diverge from “what I did” to talk about “what I almost did”. I’d intended for “get_output()” to be a CouchDB view and take advantage of quick, asynchronous, lookups. However, if this was done as a view then I’d need the emit function to reference the database and I don’t think this is allowed, i.e. I’d need a map function something like;

Note this won’t, and to the best of my knowledge can’t, work;

function(doc) {
if ( doc[‘inputs’].length > 0 ) {
for ( i in doc[‘inputs’] ) {
emit( doc[‘_id’], “_view/getoutput(doc[‘inputs’][i])” );
}
}
}

The broken part of that view is the value part of the emit function (remember emit produces key/value pairs). However, since we’re on the topic of couchdb views here’s one way we can build a view to see what inputs a node has;

function(doc) {
if ( doc[‘inputs’].length > 0 ) {
for ( i in doc[‘inputs’] ) {
emit( doc[‘_id’], doc[‘inputs’][i] );
}
}
}

I also wanted a reduce function to combine the value parts to a single key (so it matched my “data structure” so here’s the reduce;

function(keys, values, rereduce) {
return values
}

The great part of couchdb is that you can input these views in it’s code window and get immediate feedback on what’s being produced! Now I’ll show you the sad part of my design, here’s how to query and act on the view;

#This loop gives us all the inputs to node: name
for input_nodes in db.view(“/nnodes/inputs”, group=True)[name]:
#This loop gives us all the input nodes to node: name
for in_node in input_nodes.value:
if u’static’ in in_node[‘node’]:
output += float(in_node[‘weight’])
else: #Not a static input
output += get_output(in_node[‘node’]) * sigmoid(in_node[‘weight’])

What’s sad to me is that it would be less code to query the documents directly;

node = db[str(name)]
for in_node in node[‘inputs’]:
if u’static’ in in_node[‘node’]:
output += float(in_node[‘weight’])
else: #Not a static input
output += get_output(in_node[‘node’]) * sigmoid(in_node[‘weight’])

You’ll see that I used the “group=True” parm that I mentioned in my previous post. This just made things match my conceptual model but I wish the python library didn’t force me to dereference .key and .value to get them (it should turn them into a dictionary instead). I’ll also mention that several times I got confused trying [‘value’] instead of .value (something that wouldn’t matter in javascript but the former seems more “pythonic”).

I think this is a clear example that I’ve got more to learn about views and better ways to represent my data structures. Here’s a great example which I think will find a lot of analogous fits so read it often.

Back to my situation though, I’d thought maybe each node could store an array called “output_history” which could then be queried with an “increment” value (which would make it a simple emit() process). However, this was much more complicated then it was worth for an initial pass and, since if the value didn’t exist, it would still have to be calculated via a non-Map/Reduce function (because it would have to reference the database).

Before I get into much more detail let me show you the code so you can take a moment to look it over and formulate some thoughts.

I’ll be back with post 3 to try and tie it all together (including a step back to revisit the overall connections, talk more about Neural Nets and my impressions of couchdb).

Posted in code, couchdb, python | 1 Comment

Book Meme

Time for a little bit of nonsense.

I was following the news that Pownce is dead and started reading some of Leah Culver’s blog entries, which I usually try to check in every so often but don’t have in my feed for some reason. Loh and behold I found that she’s been playing with CouchDB too!

It’s always rewarding to know that someone who’s made such a professional impact is exploring things the same as I am (although I’m sure her learning curve is faster then mine ;> ).

In one of her posts I stumbled across the “book meme“. I don’t really listen to music like I should or enjoy a lot of the “fill in this questionnaire” memes that go around, but books… now that I can get into!

So here’s mine;

“If the yeast is active, it will have at least doubled its volume with a frothy head.” – Caveman Chemistry by Kevin M Dunn.


Book meme:

– Grab the nearest book.
– Open it to page 56.
– Find the fifth sentence.
– Post the text of the sentence in your journal along with these instructions.
– Don’t dig for your favorite book, the cool book, or the intellectual one: pick the CLOSEST.

Posted in uncategorized | 2 Comments