Re: crm filter cleanup on productive system

Bill Yerazunis <[email protected]>
Newsgroups gmane.mail.spam.crm114
Message-ID <[email protected]>
   From: Ger Hobbelt <[email protected]>

   >> > 1) you have a retina: in the CRM114 implementation this is 8192 slots
   >> > (called the "retina") which each get the number of occurrences that a
   >> > 32-bit OSB hash feature occurred that _just happened_ to have the low
   >> > order 13 bits equal to the slot number (this number is likely to
   >> > change in the future, and the smallness of this number compared is one
   >> > reason why large texts tend to break the neural net; when all of the
   >> > slots have equal counts, there's nothing to learn!).
   >
   > I understood it like this:
   > We have 8192 starting points called a retina. Now we take a sentence or
   > question or just any data input, split it up and for each unit we
   > generate a 32bit OSB hash.

   Yup.

   Note that input has arbitrary length; after tokenization you end up
   with M hashes where theoretically (given current implementation): M e
   {0..max_int - 1}. In actual practice, you'll get anywhere between
   zero(0) and 500K hashes for generic systems and 0..20K hashes (plucked
   the latter number out of thin air, based on the input length limit
   default in mailfilter.cf, average word size guestimate in email and
   OSB-style word-to-hash expansion ratio).
   All those hashes are mapped onto the retina.

Yes.  Note that the hashes are not "dense" - you might have a dozen
instances of hash 4320 but none of either 4319 or 4321.


   > Now i dont understand this part with the low order 13 bits equal to the
   > slot number.

   Simple: the hashes are converted into retina slot indexes using the formula

      index = hash MOD retina_size

   and given a (default) retina size of 8192, that's the same as taking
   only the lower 13 bits of each hash value.

Yep.  Note that one of the things I'm working over on the NN is changing
that, so that we get better separability of features.

Consider, right now a feature is really of the form xxxx[0/1]NNN,
where the first 19 bits are _thrown away_.  Thus, any pair of 
features that differ only in the first 19 bits will not be separable
by any neuron, anywhere.

The fix is to keep the features separated.  Ideally, we'd have the 
retina be 2^32 features long, but that would simply not work at all
on X86, and work very slowly on X64.  

So, I'm working on methods such as:

    retina_slot = feature_hash MOD ( retina_size - neuron_number)

(and other ideas!) to cause a particular 32-bit feature to end up
on a different retina slot for each input neuron.

Will it work?  Who knows- neural networks are wierd.

   >> > 2) You then have a bunch (8 or 16, also likely to change) of summing
   >> > junctions (called "first layer neurons) which each have an independent
   >> > weight for all 8192 input slots (that's 64K input weights).  The
   >> > output of these summing junctions then is mapped by a nonlinear
   >> > function called a sigmoid, which looks like a tan(x) curve rotated
   >> > about the 45-degree line.
   >
   > After that retina is filled with the data, we connect each slot of these
   > 8192 with 8 or 16 junctions, we build a kind of network here. Each
   > connection has an own weight, at the beginning i assume the weight is
   > randomized to give it any reasonable start. The "first layer neurons"
   > are the first stage of "hidden units" and the 8192 retina slots are the
   > input units right ? Now how and where do you apply the first sigmoid
   > function ? You take all the data coming from the retina weight it by the
   > weight for the given path and put it together with the sigmoid function ?

   Well, the current implementation (see also: src/crm_neural_net.c) uses
   full size crossbars between the layers, i.e. you have layers and
   crossbars like this:

		  retina (8192)
   Win (xbar: 8192x8)
		  first (8)
   Whid (xbar: 8x16)
		  hidden (16)
   Wout (xbar: 16x2)
		  output (2)

   with (default) sizes in parentheses.

   (Note: default sizes can be adjusted using the crm114 '-s' or '-S'
   commandline argument; the conversion factor is a little wicked
   though: first_layer_size =
   (int)sqrt((int)(sparse_spectrum_file_length / 1024)); which means
   you'd have to spec '-S 16' for the default, which is
   first_layer_size==8)

Don't assume those values are optimal.  I'm playing with them.

   And see crm_neural_net.c for the sigmoid function, which is here (for
   one layer):

		       nn->delta_output_layer[neuron] =
			       (nn->delta_output_layer[neuron] //  target - actual
				-  nn->output_layer[neuron])
			       * (1.0 - nn->output_layer[neuron]) // 1 - actual
			       * nn->output_layer[neuron];       // actual

   which is, when looking at it with a wee droppa Smirnov assistance,
   similar to a tan(x+pi/2)

Well, arctan (x+pi/2).  And, that's not just the
sigmoid function, that's the entire update rule.

   And, yes, it might not be immediately detectable in the source as
   it is. Alas.

There's actually a good reason for that funky formula.  Remember
I mentioned there's calculus involved?

The reason is that gradient descent uses the local derivative of
the error function at each point to decide which way and how
far to adjust each weight.  

See line 1432: The derivative of the sigmoid we use (specifically,
the "logistic" sigmoid) is just (1 - (sigmoid(x)) / sigmoid(x).  
Multiply this result times the amount of error and that tells you 
how much to correct each weight in the huge weight arrays.

Of course, this is like using Newton's method- if the 
function varies fast enough underneath you, Newton's method goes unstable.


   >> > 4) One more layer, with just two summing-junction neurons and sigmoids
   >> > gives us the output - the [0]th neuron is the "in class" signal, and
   >> > the [1]th neuron gives the "out of class" signal.
   >
   > if i understand right these are the output units, which in this case can
   > produce yes or no.

   yup, on a per document basis. The CSS databases are collections of
   trained documents. (See also: crm_neural_net.c)

   >> > Training is a bit harried; you have to do a gradient descent from
   >> > the desired output to the mapped inputs; there's some calculus
   >> > involved, as well as a bit of luck (convergence is NOT gauranteed!)
   >> > You also have to initialize with small random numbers because
   >> > otherwise, the standard training algorithms will be "stuck on center"
   >> > forever and you get no training at all.
   >
   > it would be nice if you could also explain this if you got some
   > freetime, i know its complicated
   >
   > What kind of network have you implemented ? i feel its a kind of pattern
   > associator network with 2 extra hidden layers. therefore for learning
   > you use some kind of delta or hebb rule learning ?

   See crm_neural_net.c: allegedly a Kohonen network, no Hebb training,
   but I have to take that one on faith myself until I take the time to
   read through certain dusty volumes on my shelf again.

Well, some folks claim that it's Kohonen (note that Kohonen himself
says "well, I prefer to to use Kohonen for the SOM (Self-Organizing
Map) network").  So, call it what you will.  If you can find a better
term for it, please let me know.

   How the training works _exactly_ is beyond my forte right now (it's in
   those dusty volumes but I'd rather not reach for that upper shelf for
   fear of giving myself brainingitis), but it kinda sorta comes down to
   the digital equivalent of a nice physics show, where you hide a couple
   of magnets under a flat piece of paper, then sprinkle iron dust on
   top: by jittering the paper the iron filings clump together and show
   the field strength / lines as brown on white.
   (That's why you need the (continual) injection of (small) random
   values; it's the equivalent of jittering the paper to make the iron
   dust move.)

No, not really.  The initial condition of small random values is
theoretically all that's needed.  I just have found that THIS
PARTICULAR system works better on text with a little bit more than
that, kind of like a Boltzmann machine than a pure neural net
(although I suppose this particular implementation has elements of
both.)

What's really happening is that the errors are being back-propagated
through the system, by apportioning in radio of the strength of the
incoming signal (essentially, view the retina with a document on it as
one set of boundary conditions), and the output neurons as the other
set of boundary conditions.  The derivative of the sigmoid is just
1-sigmoid / sigmoid, so the change at each interior point is
easy to calculate.

The hard part is that it's not a monotonic surface; finding the global 
minimum instead of a local is not gauranteed.


   (And an attempt to partially answer my personal exercise 3b: for one
   [implicit assumption in the code], the width of the retina limits the
   number of distinguishable features in the input, as the 'index = hash
   MOD retina' mapping function mixes features which produce an identical
   *index*. Since you don't know which features are significant and which
   aren't, there's no way to tell if a significant feature will mix with
   other [in]significant features, where the occurrence of such an
   insignificant feature can, in a later classify run, inadvertently
   trigger a neuron as if it were the significant feature.
   Worst case here is when two (or more) significant features map onto a
   the same index, where those features are significant for detecting
   different classes.

yep.  That's why I'm thinking very hard of how to change that.

Maybe something like a narrower retina, but more variations (i.e. 64
input neurons, retina of 1024, and the retina cells are nonuniform.

That is, for hash H, and input-level neuron N, and retina width R,
the cell C that hash goes into varies with the neuron number (and
given the odd prime sequence P[N] = 3, 5, 7, 11, 13, 17, ...) something
like:

    R = ( H + ( H >> log2(R) ) * P[N] ) mod C

but be warned, I haven't tested this, I just keep mulling it over
and thinking about the ramifications on the subway.  Aliasing CAN be
worse, but you have 63 out of 64 neurons that will be able to 
differentiate between any two random 32-bit featurecodes.

(note- the above actually only gives 20 bits of significance.
I'm working on how to fix it for a true 32-bit significance that
isn't horrible to express or calculate.

The rough rule of thumb for neural nets is for N different relatively
non-crazy, relatively linearly separable categories you need some
small multiple of that many neurons in the input and hidden layers.
Since the number of retina x input weights dominates this
calculation, we need to try to minimize them but without loss
of the discriminatory power of a NN.

   Given the small(?) value of 8192, one /must/ assume several features
   of varying significance are mixed into the same retina index, and that
   implies that the risk a neuron will be inadvertently fired (misfire)
   is rather 'large', for a (yet undetermined) amount of large. I.e. it's
   a game of trail & fail to see if the given retina size (*and* the
   MODULO hash mapping function there!) are 'sensitive' enough to keep
   the amount of misfires acceptable for your expected input set. Ergo:
   will the NN learn the right thing despite these setbacks? Testing will
   give an indication of the answer, but no guarantee.
   Which says it all: you got to test this one with your own input
   collection in order to be able to say something reasonably 'solid'.
   Public corpuses can help to set this thing up, but the real tuning has
   to happen based on your own data set. But that last bit is just [my]
   opinion.)

No, it's also truth.  NNs are not gauranteed to work for all possible
input configurations.

   Oh, and by the way: both GerH and vanilla releases have two bugs
   lurking in that NN code.

Can you post a diff?


   So far, my two cents. Signing off.


   PS: You may want to inspect crm_neural_net.c, but chances are high
   your first impression is 'uhhhhhh?' (at least that was mine ;-)) )

I tried really, really hard to document that code well.  *sigh*.

Well, at least pull the paper from SRI and see if that helps.  Note
that the paper also has some typoes in it.  :(

     - Bill Yerazunis

------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.