Monday, September 28, 2020

Everything is a Message

On further reflection, I like this generic-map structure so much that I'm going to use it for everything. Every message that is sent anywhere in the system will be of that form. In fact, I will call the basic data structure a "Message".

 

type Message map[string]interface{}

 

And all the different specific data types will just be defined as specializations of that type:

    

type Abstraction      Message

type Work_Description Message

 

The differences between the various specialized messages will be that they have different 'mandatory' fields, which will be filled in by their creation functions:

   

func New_Abstraction() (Abstraction) {
  return Abstraction { "type"    : "abstraction",
                       "id"      : 1,
                       "version" : 1,
                     }
}


Why use such a generic structure for everything? Because I want this system to be able to run forever, with different Abstractor types getting added to the system, with old Abstractor types getting upgraded -- all without ever needing to shut down to recompile all the code.

If you used 'normal' data structures, you would have to shut down and recompile every time a new data type were added to the system.

You might not even be able to get to all the code! At first every Abstractor in this system will be a goroutine and they will all be running in a single process. That would probably work well enough to use most of the computing resources of one large box. But later it would be easy to add a portal so that Abstractors running in a separate process, or even on a separate box could become part of the system, and then you would be running a single system across the internet.

The system gradually evolves, either because human programmers are adding new Abstractor types and new Abstraction types, or because we find some way to add those automatically. And there is never any need to stop anything while the system evolves. The new Abstractors just show up and start talking to the Bulletin Board, and everything else keeps working.

You could even add new fields to a given Abstraction type without damaging old Abstractors that use that type. They simply don't use the new fields, but can keep using the old fields the way they always have done.

Imagine this: 

You have a bunch of vision systems that are bulldozers -- or something -- collecting regolith from the surface of an asteroid. (Do asteroids have regolith, like the Moon?) And they keep getting into some kind of trouble in certain situations. They are having vision system failures once in a while that require expensive -- and slow -- human intervention. 

So the vision engineers spring into action. They take a look at the stored image sequences from when the bulldozers got into trouble and they say "Oh, I see what's happening. Wow, we never thought of that!" And they write some new Abstractors that will detect just that special trouble-making situation and respond to it. 

The new code gets transmitted to the bulldozers. The code gets launched as a separate process that knows how to use inter-process communication to become part of the running system. No need to shut anything down.

The upgraded bulldozers quit having that particular problem.


Or maybe, somehow, those new Abstractors get invented automatically.

Either way, we have a vision system that can change or add to the code it's using, adapting to new or unanticipated challenges, without ever shutting down.

Just like you!





Here's a complete little example program, showing Messages getting specialized into Abstractions and Work_Descriptions:


// start of code

package main

import (
         "os"
         "fmt"
       )

var fp=fmt.Fprintf


type Message map[string]interface{}

type Abstraction      Message
type Work_Description Message


func New_Abstraction() (Abstraction) {
  return Abstraction { "type"    : "abstraction",
                       "id"      : 1,
                       "version" : 1,
                     }
}


func New_Work_Description() (Work_Description) {
  return Work_Description { "type"    : "work_description",
                            "version" : 1,
                          }
}


func Print_Abstraction ( a Abstraction ) {
  fp ( os.Stdout, "Abstraction: |%#v|\n", a )
}


func Print_Work_Description ( wd Work_Description ) {
  fp ( os.Stdout, "Work_Description: |%#v|\n", wd )
}


func main () {
  a := New_Abstraction()
  Print_Abstraction ( a )

  wd := New_Work_Description()
  Print_Work_Description ( wd )
}

// end of code



And the output :

 

Abstraction: |main.Abstraction{"id":1, "type":"abstraction", "version":1}|
Work_Description: |main.Work_Description{"type":"work_description", "version":1}|


But if you try to pass an Abstraction into the Print_Work_Description() function, you get:

 

cannot use a (type Abstraction) as type Work_Description in argument to Print_Work_Description


Tuesday, September 22, 2020

An Architecture for Machine Vision

It has seemed to me almost axiomatic for some time that 'intelligence' can only be an emergent property of systems made of many independently operating actors, cooperating, competing, and communicating.

The ideal place to test that concept is in the realm of visual perception.

 

 

Machine Vision is not computer programming

In normal computer programming, the problem domain is completely understandable. If, for example, you are writing a web server, you can go learn all there is to know about the HTML 2.0 specification. HTML 2.0 is a finite logical system created by humans. So is the internet. So is the Transmission Control Protocol. Everything you will interact with as you write your code will be a finite logical system created by humans. You'll still have plenty of trouble getting it done, but at least you'll be able to tell yourself Look, this has to be possible.

But when you point a digital camera at the natural world, then start writing software to try understanding what it sees--you have now entered a whole new ballgame.

The difference is that the natural world is not a finite logical system.  You cannot write frozen logic to deal with input that has arbitrary variability. Of course you can try -- as I did for many years -- but what you will find is that you are forced to keep adding alternative pathways to your logic as ever more algorithm-breaking possibilities come to light (sorry) in your input until your code is so complex that every new feature breaks an old one and development grinds to a halt.

The architecture of normal computer programs--the set of techniques that underlay them all--consists of functions that generate results and that are connected to each other in a topology that is fixed at the time the program is written. For Machine Vision we will need something much more flexible.

The architecture we describe here will automatically adapt to significant changes in its inputs, and learn to improve its processing efficiency over time.



Abstractors

I will call the basic units of functionality in the Machine Vision architecture Abstractors. In normal programming, the fundamental units of logic are called functions, by analogy with mathematics. They are chunks of code that transform a set of inputs into a set of outputs. Abstractors have a more specific purpose: to creatively refine large quantities of data into smaller and more valuable representations--Abstractions

Most Abstractors can only function when an appropriate set of inputs become available--except for the lowest-level Abstractors in the vision system, which take a physical input (like light) and abstract it into images. These physical Abstractors are called Sensors. In special circumstances they may be controlled by higher-level Abstractors, but normally they simply operate on a timer. For example, creating a new image every forty milliseconds.

 

 

Abstractions are arbitrary Maps

In Go, it looks like this:

type Abstraction map[string]interface{}

A map using strings for keys and storing values that can be anything at all.

Abstractors that want to consume a particular type of Abstraction are written to understand its various fields and their datatypes.



The Bulletin Board

Unlike functions in a program, Abstractors are not connected to each other in a topology that is fixed when the code is written. Instead, Abstractors exchange Abstractions through a communications switchboard called the Bulletin Board.

When a new Abstractor starts running it registers with the Bulletin Board a function that will be used as a filter to determine what Abstractions will be of interest to it. Every time a new Abstraction is sent to the Bulletin Board, all such functions will be run. The new Abstraction will be sent to every Abstractor whose selector function returns a positive value.

Abstractors may register a new selector function with the Bulletin Board at any time, replacing the old one.

This breaks the fixed topology of standard programming. Abstractors that produce outputs do not know where they may end up. Abstractors that consume inputs do not know whence they come--only that they match the Abstractor's current criteria.

When an Abstractor starts up it also tells the Bulletin Board what type of Abstractions it is capable of creating.



Bottom-Up, and Top-Down

Initial activity in the system is bottom-up. It begins when one or more Sensors create images (or other sensory Abstractions) and send them to the Bulletin Board. These Abstractions will match the selection criteria of some Abstractors in the system, which will then receive them from the Bulletin Board and process them into higher-level Abstractions.

But as activity progresses, higher-level Abstractors may request specific work from lower-level Abstractors.

For example, imagine a system whose top-level task is to locate faint moving objects against a stellar background. It processes stacks of images and tries to locate the moving object in each image. The processing technique that it employs works if the asteroid is always reflecting approximately the same amount of light. 

But now it is trying to track an asteroid that is significantly elongated. As the object rotates, it sometimes presents its long axis to our system's sensor and the amount of light that it reflects is greatly reduced. Our tracker-Abstractor fails to find the object's location in several images of the stack. 

But Tracker wants to confirm the asteroid's position in those few images, or the quality of the Abstraction that it eventually posts will be significantly degraded. So Tracker calls for help.

To request assistance, Tracker issues a new kind of communication to the Bulletin Board: a description of work that he wants done -- what to look for, and where to look for it. The Bulletin Board matches this request with what it knows about what kind of work the other Abstractors around the system can do, and sends the request to all that look like they might be able to do the work. If any of those Abstractors decide to do the work, and if they succeed, the Tracker will incorporate their work into its Abstraction which will then be posted.

The work that Tracker initiated with its request is an example of top-down activity in the system.  Such requests may come all the way from the very topmost Abstractors whose Abstractions constitute the purpose of the system, and reach all the way to the bottommost Sensors.

The combination of data-driven bottom-up and goal-driven top-down action makes for chaotic--but meaningful--patterns of activity.



Positive and Negative Belief

In a standard computer program, a function will either produce a result or an error message. If there is no error, then you can trust the result. You can have that kind of perfect certainty when you're working with human logic: an HTTP server, a Kubernetes cluster, a file was opened or it wasn't.

When our code is pointed at the natural world, we can't have much of that kind of certainty. At the lowest levels we can -- when you are doing image processing operations -- an image goes in and a different kind of image comes out -- then, yes, you can be as certain of your result as any common program's function.

But as we approach the higher levels of actual vision -- in which the outer world is being meaningfully modeled -- abstracted into representations useful for further cognition -- from that point upward we can never again have perfect certainty.

Rather than just answers or error codes, Abstractions come with belief values attached. A belief can be positive or negative (disbelief), and a given Abstraction always has attached to it a value for both. Belief spans the range from 0 to 1, disbelief from 0 to -1. If a given Abstraction is merely uncertain, you will see a low belief number. But if there is actual contradictory evidence, you will see a nonzero disbelief number alongside the positive.

These values may be influenced by Abstractors other than the one that posted the original Abstraction. I.e., another Abstractor may come along and add some disbelief to a given Abstraction, because it is considering a kind of evidence that the original Abstractor did not -- and in that new view, something does not look right.



The Market

Higher-level Abstractors can request any amount of extra activity they want. If a given Abstractor becomes overloaded with work, I think there will at some point be a mechanism that allows more copies of it to be instantiated to share the load. With different experience, different settings, and different relationships, I think those new copies can have a distinct life of their own.

There may even be a way, someday, to create new Abstractors doing new types of processing, entirely from scratch, without human programmer intervention.

In short, we have a system here that can expand to fill up any amount of computational resources you care to provide. 

And that's a problem. We have finite resources, but a perceptual system that can expand without limit. And those resources are needed for other things besides visual perception! There is still higher-level cognition that the perceptual system is supposed to be supporting! That's the part that decides what the system should be doing, based on what it is seeing. It needs to have some compute power too.

We need a vision system that can somehow keep itself within some bounds of resource use, and yet handle new perceptual issues as they arise. We need a system that can quickly expand to use new resources if that is what is necessary to keep us alive, but which can then quickly 'learn' to solve that new perceptual issue more efficiently, freeing up computational power for other equally vital realms of cognition.

We need a system where overall efficiencies can arise as an emergent property of the interaction of many independent Abstractors.

We need a market.



The Abstractor Economy

And here I come to the end of what I know so far about this system. Everything up to this point I believe I know how to implement, but not this, not quite.

What provides the overall total resources that the system can use? Are those resources apportioned from the top down? But then how do the Sensors fire? Are they separate?

Is there a 'mainstream' of processing that happens without negotiation? Does the marketplace only affect top-down transaction in which a higher-level Abstractor requests specific work? But then how is that Abstractor compensated for the Abstraction that it posts.

Do Abstractors get compensated when one at a higher level uses its work? Do lower-level Abstractors 'bid' on work? Or do they do the work 'on consignment', hoping to be paid? Or both, at their discretion?

Do Abstractors have 'savings'? If they amass enough savings, is that what controls when they can reproduce?

If an Abstractor is 'thinking' about cost/benefit issues in this way, that implies a substantial amount of logic that is completely independent of its core processing logic -- the stuff it gets paid for. How is that logic implemented? And do different Abstractors have different 'styles' for this type of logic? Some being bigger risk-takers, hoping for greater rewards?

What happens when an Abstractor 'goes broke'? Can it ever function again?

Can it go on the dole and try to build up from there?

I can show one example of a system like this in action, based on our earlier example of an Abstractor trying to find a sequence of asteroid locations across a stack of images.

 

When Tracker discovers that it cannot detect the asteroid location in several of its images, it creates a work-request which it transmits to the Bulletin Board. That request specifies the type of work wanted, which is region-finding. The region found will be the asteroid in that image. It tells the prospective contractor a small bounding box in which it should look -- interpolating from the other images where it was able to locate the asteroid -- and it says about how big it should be.

Only one contractor manages to find the asteroid, and it is an exotic and expensive one. The problem is that the asteroid is reflecting so little light that normal grayvalue techniques cannot detect it. But this contractor succeeds by doing statistical analysis of the background noise. It discovers a region of just the right size in the right spot. The average grayvalue of that region is no greater than that of the background, but the standard deviation of its grayvalue distribution is three times greater than that of the typical background.

Tracker accepts its work, and pays the contractor. They form an alliance that lasts for hundreds of frames.

Eventually, however, another Abstractor and potential contractor notices the high prices that Tracker is paying for region detection in the problem images. This guy thinks "I can do that cheaper!" He could not bid on the initial solicitation because his technique did not work. But since then he has tried his technique again with many modifications -- spending his own savings to do so. He has discovered a set of modifications that allow it to work on the problem images, much more cheaply than the prices Tracker is paying.

Based on that research, the new contractor makes a bid on the work-request that Tracker submitted hundreds of frames ago. Seeing the lower-cost bid, Tracker tries out the new guy, and finds that it works well. Tracker switches contractors.

This kind of activity is going on all over the system. The net effect is to gradually reduce the overall resource consumption of the system, while maintaining effectiveness.



Next Steps

In the above description, I have one tiny little snippet of code. The next steps will be to make a lot more of those snippets, and finally to see how much of the behavior described above can be shown in a running system.

The ultimate goal is to show system-wide 'intelligent' behavior emerging from the chaotic interactions of these many independent Abstractors.

But, for now, leaving the Market behavior out of it. That still needs a lot of designing.

 

 

Tuesday, September 15, 2020

Vision for Asteroids

The best place in the solar system for our near-term future -- the next thousand years or so -- is the big strip between Mars and Jupiter where the asteroids live. It's a long way out there -- the near edge 18 light-minutes out from the Sun, and the far edge 27. For comparison, the Earth is only 8.3 light-minutes out.

And it's mighty thin out there. The Belt has a volume of something like 6000 cubic light-minutes, while the total mass of all the asteroids is about one two-thousandth that of the Earth. I think that probably means that you could fly through that belt one hundred times staring out your front window the whole time and never see a darned thing.

Which brings up the first vision task for the asteroids: finding one.

Our spacecraft will probably know where it's supposed to be going, but it would be just immensely better if it could locate its target visually while it's still distant, and correct it's own course without waiting for the hour round-trip message to Houston. Or maybe it won't know! Maybe we will want it to go prospecting for a rock that no one has ever seen before.

In either case, we will want to be able to detect our asteroid when it still looks like this:

Big sky.

Possible bogey. Zoom 2x.

Maybe...

Zoom 2x.

I see motion. Look near center of image.

Zoom 2x.


Motion detected! Calculating orbit.

Tally-ho! We have a rock.

So this gives us task number 1.


1. Detect and track faint moving objects against a nearly-unchanging stellar background.

 

But of course the stellar background won't always be unmoving. The spacecraft will sometimes have to change attitude, which will make the stellar background change slightly from frame to frame.

Which gives us task number 2.

 

2. Track a gradually moving stellar background.

 

What does that mean? To track the stellar background means you find each star -- or at least each obvious star -- in one frame. Then you find them all again in the next frame, and then for each star in frame n you figure out which one it is in frame n+1. So, for each star, you end up building a little history that says 'Here it entered the field of view in frame n, and then here it is in frame n+1, and here it is again in frame n+2... and here it leaves the field of view in frame n+m.'


And all this talk of stars ... eternal stars. Unmoving...This reminds me of something.

Sometimes in machine vision applications, in cases where the object to be inspected can be manufactured or altered in such a way as to make visual inspection easier -- circuit boards, for example -- the manufacturer is kind enough to print fiducial marks on the object.

Fiducial marks on a circuit board.

Those are marks designed to be easily located by a vision system. In the case of circuit board assembly, they allow a pick-and-place machine to put all the little chips in all the right places. That isn't done by humans, you know. And those machines need to be able, at least a little bit, to see.

Such marks need to be easy to find, and unchanging.

Well, guess what else has such marks.

 

The Fiducial Marks of the Cosmos!
 

 

The Cosmos has its own set -- as long as you don't move very far. And we are not planning to move far. This is not Star Trek, where we zoom around so fast that you can watch the stars drift by out your stateroom window. (Just don't think about that too hard...) We are planning to only go zooming around within our own little 1500-cubic-light-hour solar system. In fact only out to the asteroid belt -- more like half a cubic light hour.

From Manchester, Michigan, in the United States, North America, Earth in the year 2020 -- the great ring of the asteroids looks like the vastness of infinite space. 

To the Cosmos, it looks like nothing at all.

For all of our machines flying around the entire asteroid belt for the next thousand years while we build Solar Civilization, the Cosmos provides us with an ideal set of fiducial marks. They're easy to see, and they never change. They're the same for everyone, everywhere.

It would be easy to memorize ten thousand or so of the brightest ones scattered all over the sky. Our machines will be created already knowing them. Using them, any machine anywhere within Solar Civilization can orient itself to an absolute coordinate system and know exactly where it's pointing.

If it can then also locate the Sun (not hard to do) and a few planets -- and if it has information about how the planets move -- then that machine can also know exactly where it is within the solar system -- a 3D location -- and exactly when it is! The eight planets move like the eight hands of a great clock, never to repeat itself, not in a trillion years. 

If you can see them all, you can use that great clock to determine the correct time down to the hour.

the Big Clock


So finally to use these lovely fiducial marks we will have one more vision task for the stellar background.


3. Given an image which is a subset of a known stellar map, locate the image on the map.


There will be much more later, but with these three visual capabilities we will be able to see our way to get where we're going.








Saturday, September 12, 2020

Statement of Purpose

 

 

I have an old suitcase in my basement that is full of scrapbooks that I made over the course of several years starting when I was eight years old. They are all full of newspaper articles about the US space program, the first article being a Sunday color supplement about the Gemini 11 mission.

 

Going Places

 

The suitcase also contains a newspaper article about me. The local paper sent a reporter to my school when I, at the age of eleven, wrote a letter to the federal government asking whether it might be possible for me to purchase a small piece
of the Moon.

I received a response from the State Department explaining that, while I was certainly free to visit the Moon, an international treaty prohibited anyone from claiming any of it. The photographer's picture shows me reading the response, looking mildly irritated.

In spite of such bureaucratic intransigence I was confident, in the summer of 1969, that it would prove to be no more than a minor speed bump on the road to the future.

 


 

It was only three years later, on 13 December, 1972, that Gene Cernan stepped off the surface of the Moon to climb the ladder into the Apollo 17 Lunar Module, and Project Apollo was terminated. I quit clipping out newspaper articles after that, because there weren't any more stories worth saving. It has now been forty-eight years since the last human being left the Moon.

 

I wanted to stay a while.

As I entered high school I began to understand that my future would not be full of rockets. But in my freshman year I read a book by Gerard K O'Neill called The High Frontier: Human Colonies in Space, and I started dreaming of building islands in the sky using nothing but sunlight and asteroids.

 

Islands in the Sky


Eventually I found my way to grad school where I fell in love with the highest-tech field I had ever heard of: Artificial Intelligence and Machine Vision. Hope in American space efforts was fading, weighed down by the miserable performance of the Space Shuttle. 

At the dawn of the decade we had been told that the Shuttle would fly five hundred missions in the Eighties, would reduce launch costs to a fraction of what they had been, would usher in a new era. But by January 1986, we'd had only 24 flights. Less than a tenth of what had been hoped.

 

I was on a lunch break from my first high-tech job, at a startup called Machine Vision International in Ann Arbor, sitting in my car in the drive-up line at the local McDonald's, when I heard on the radio that Challenger had died. When I pulled forward to accept my little bag of lunch from the McDonald's woman at the window, I was weeping.

When I got back to work some of my colleagues in the Research Department were standing outside and they asked if I had heard the news. Yes, I said, and now it's over. We just lost the US space program. Nancy said, "Oh, no, don't worry. They'll fix it and have it flying again in a couple months." "No," I told her. "More like two years."

I was close, if a little optimistic. It took two years and eight months before the shuttle flew again. By the end of the Eighties we'd had a grand total of thirty-two flights.


The Day the Future Died


Life went on: marriage, jobs, moving to California just in time to for a Michigan boy and girl to see what a real earthquake feels like, fleeing back to Michigan, bringing a new baby girl into the world.

The Nineties passed, and then the Oh-Oh Decade. 9/11 came. 

Then it was winter again, in early 2003, and I was in my car again -- this time getting the oil changed -- when Columbia broke up during reentry, raining its ruin upon east Texas.


Columbia, falling.


More years, more jobs. The Global Financial Crisis A good job at Red Hat! Our daughter going to college, and then finding her way to grad school. My wife rejoining the workforce. The Grandparents dying.

Until one day in early 2018 -- it was winter again -- I saw on the internet the most amazing video. I saw two rockets, made by a private company, after having delivered their payloads and reentering the atmosphere --- decelerating to a landing on their tails.

Just like they did in the science fiction movies when I was eight.

Over the next year, I think I watched that clip a hundred times.

 

They're here.

They're using vision systems to help land those rockets, I thought. Yes, OK, but too many years have gone by. Everything just took too long. Too much water over the dam. Good luck, younger people, and may all your rockets fly true.

Until the foul year of 2020 dawned, with viruses and riots and the biggest economic convulsion since the Fall of Rome. And the month of June came along and I was poking around the internet, daydreaming of rockets, when I came upon an interesting article.

Space is back, baby, she said. It’s back in the news, back in our thoughts, and back in the culture.

I read with interest.

The key is private industry: What used to cost the government $54,500 per kilogram of payload lifted to orbit now costs SpaceX $2,720, saving 95 percent.

That really got my attention. A factor of twenty reduction in cost.  I had just a short time before learned about the Erie Canal that opened almost two hundred years ago. It reduced the cost of westward travel by a factor of twenty-five or thirty -- and that's what opened my home state of Michigan to settlement. Back when it was the West.

If that has already happened because of SpaceX, I thought, then the road has opened. 

 

Fifteen years on the Erie Canal
 

She even mentioned the Outer Space Treaty, my source of long-ago irritation, and said that recent legal thinking is that just because states cannot lay claim to heavenly bodies like the Moon or Mars doesn't mean that private individuals can't have property rights over things like asteroids -- and the materials they might take from them.

See? the eleven-year-old said. I told you.

And then the author said:

Space law used to be entirely academic, but now it’s a rising field. NASA is funding asteroid-mining research. The Colorado School of Mines now has an asteroid-mining program of study.

When I read that last sentence it was like hearing a great bell toll. I'm going there, I thought, age be damned.

If I drop dead halfway through the program, that's fine with me. Well, you know. Fine-ish. What is not OK is not trying. I don't think eleven-year-old Mike would be happy with that, no, not one bit. So we're going.

They even have the same block-M as Michigan. I can re-use all my old school stuff.

I finished my application two days ago.

 

Go West, old man.


This is why we're doing this blog, and why we're processing images of stars. And why later we'll be trying to track things like the Lunar Landers moving against a background of stars, features on an asteroid's surface, structures taking shape in free space.

When we send machines out there to start exploring and mining and building for us, they might end up half a light-hour away from the nearest human being -- much too far to phone home for instructions for your every move.

Our machines will need to be able to see.

It's time to be making vision systems for the asteroids.