# HG changeset patch # User Robert McIntyre # Date 1395886662 14400 # Node ID f339e3d5cc8cdf3a7ed8e4e27e59bc69c7dcb5df # Parent 0a4362d1f1386b748ecd9716b12fb92f665f189f finish draft of chapter 3. diff -r 0a4362d1f138 -r f339e3d5cc8c org/self_organizing_touch.clj --- a/org/self_organizing_touch.clj Wed Mar 26 20:38:17 2014 -0400 +++ b/org/self_organizing_touch.clj Wed Mar 26 22:17:42 2014 -0400 @@ -28,14 +28,14 @@ (defn touch-kinesthetics [] [[170 :lift-1 40] - [190 :lift-1 20] + [190 :lift-1 19] [206 :lift-1 0] [400 :lift-2 40] [410 :lift-2 0] [570 :lift-2 40] - [590 :lift-2 20] + [590 :lift-2 21] [606 :lift-2 0] [800 :lift-1 30] @@ -57,10 +57,18 @@ (defn single-worm-segment [] (load-blender-model "Models/worm/worm-single-segment.blend")) +(defn worm-segment [] + (let [model (single-worm-segment)] + {:body (doto model (body!)) + :touch (touch! model) + :proprioception (proprioception! model) + :muscles (movement! model)})) + + (defn worm-segment-defaults [] (let [direct-control (worm-direct-control worm-muscle-labels 40)] (merge (worm-world-defaults) - {:worm-model single-worm-segment + {:worm worm-segment :view single-worm-segment-view :experience-watch nil :motor-control @@ -97,23 +105,27 @@ (rect-region [8 0] [14 29]) (rect-region [15 15] [22 22]))) -(defn view-touch-region [coords] - (let [touched-region - (reduce - (fn [m k] - (assoc m k [0.0 0.1])) - (zipmap all-touch-coordinates (repeat [0.1 0.1])) coords) - data - [[(vec (keys touched-region)) (vec (vals touched-region))]] - touch-display (view-touch)] - (dorun (repeatedly 5 #(touch-display data))))) +(defn view-touch-region + ([coords out] + (let [touched-region + (reduce + (fn [m k] + (assoc m k [0.0 0.1])) + (zipmap all-touch-coordinates (repeat [0.1 0.1])) coords) + data + [[(vec (keys touched-region)) (vec (vals touched-region))]] + touch-display (view-touch)] + (touch-display data out))) + ([coords] (view-touch-region nil))) + (defn learn-touch-regions [] (let [experiences (atom []) world (apply-map worm-world (assoc (worm-segment-defaults) - :experiences experiences))] + :experiences experiences + :record (File. "/home/r/proj/cortex/thesis/video/touch-learn-2/")))] (run-world world) (->> @experiences @@ -132,6 +144,24 @@ (map set) remove-similar))) + +(def all-touch-coordinates + (concat + (rect-region [0 15] [7 22]) + (rect-region [8 0] [14 29]) + (rect-region [15 15] [22 22]))) + +(defn view-touch-region [coords] + (let [touched-region + (reduce + (fn [m k] + (assoc m k [0.0 0.1])) + (zipmap all-touch-coordinates (repeat [0.1 0.1])) coords) + data + [[(vec (keys touched-region)) (vec (vals touched-region))]] + touch-display (view-touch)] + (dorun (repeatedly 5 #(touch-display data))))) + (defn learn-and-view-touch-regions [] (map view-touch-region (learn-touch-regions))) diff -r 0a4362d1f138 -r f339e3d5cc8c thesis/cortex.org --- a/thesis/cortex.org Wed Mar 26 20:38:17 2014 -0400 +++ b/thesis/cortex.org Wed Mar 26 22:17:42 2014 -0400 @@ -211,7 +211,8 @@ #+caption: full circle. Imagine how you would replicate this functionality #+caption: using low-level pixel features such as HOG filters! #+name: grand-circle-intro - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (defn grand-circle? "Does the worm form a majestic circle (one end touching the other)?" @@ -400,7 +401,7 @@ :muscles (movement! model)})) #+end_src #+end_listing - + ** Embodiment factors action recognition into managable parts Using empathy, I divide the problem of action recognition into a @@ -436,7 +437,8 @@ #+caption: independent and ignores vermopomorphic differences such as #+caption: worm textures and colors. #+name: curled - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (defn curled? "Is the worm curled up?" @@ -451,7 +453,9 @@ #+caption: Program for summarizing the touch information in a patch #+caption: of skin. #+name: touch-summary - #+begin_listing clojure + #+attr_latex: [htpb] + +#+begin_listing clojure #+begin_src clojure (defn contact "Determine how much contact a particular worm segment has with @@ -476,7 +480,8 @@ #+caption: floor. Note that this function contains no references to #+caption: proprioction at all. #+name: resting - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (def worm-segment-bottom (rect-region [8 15] [14 22])) @@ -495,7 +500,8 @@ #+caption: I am able to both use a previous action predicate (=curled?=) #+caption: as well as the direct tactile experience of the head and tail. #+name: grand-circle - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (def worm-segment-bottom-tip (rect-region [15 15] [22 22])) @@ -525,7 +531,8 @@ #+caption: wiggle but can't. Frustrated wiggling is very visually different #+caption: from actual wiggling, but this definition gives it to us for free. #+name: wiggling - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (defn fft [nums] (map @@ -565,7 +572,8 @@ #+caption: Use the action predicates defined earlier to report on #+caption: what the worm is doing while in simulation. #+name: report-worm-activity - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (defn debug-experience [experiences text] @@ -683,7 +691,8 @@ #+caption: Program to convert an experience vector into a #+caption: proprioceptively binned lookup function. #+name: bin - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (defn bin [digits] (fn [angles] @@ -741,7 +750,8 @@ #+caption: and finding the longest (ie. most coherent) interpretation #+caption: of the data. #+name: longest-thread - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (defn longest-thread "Find the longest thread from phi-index-sets. The index sets should @@ -783,7 +793,8 @@ #+caption: Fill in blanks in sensory experience by replicating the most #+caption: recent experience. #+name: infer-nils - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (defn infer-nils "Replace nils with the next available non-nil element in the @@ -804,19 +815,21 @@ To use =EMPATH= with the worm, I first need to gather a set of experiences from the worm that includes the actions I want to - recognize. The =generate-phi-space= program (listint + recognize. The =generate-phi-space= program (listing \ref{generate-phi-space} runs the worm through a series of exercices and gatheres those experiences into a vector. The =do-all-the-things= program is a routine expressed in a simple - muscle contraction script language for automated worm control. + muscle contraction script language for automated worm control. It + causes the worm to rest, curl, and wiggle over about 700 frames + (approx. 11 seconds). #+caption: Program to gather the worm's experiences into a vector for #+caption: further processing. The =motor-control-program= line uses #+caption: a motor control script that causes the worm to execute a series #+caption: of ``exercices'' that include all the action predicates. #+name: generate-phi-space - #+attr_latex: [!H] - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (def do-all-the-things (concat @@ -843,7 +856,8 @@ #+caption: Use longest thread and a phi-space generated from a short #+caption: exercise routine to interpret actions during free play. #+name: empathy-debug - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (defn init [] (def phi-space (generate-phi-space)) @@ -891,7 +905,8 @@ #+caption: Determine how closely empathy approximates actual #+caption: sensory data. #+name: test-empathy-accuracy - #+begin_listing clojure + #+attr_latex: [htpb] +#+begin_listing clojure #+begin_src clojure (def worm-action-label (juxt grand-circle? curled? wiggling?)) @@ -931,6 +946,7 @@ #+caption: Program to generate \Phi-space using manual training. #+name: manual-phi-space + #+attr_latex: [htpb] #+begin_listing clojure #+begin_src clojure (defn init-interactive [] @@ -949,11 +965,174 @@ After about 1 minute of manual training, I was able to achieve 95% accuracy on manual testing of the worm using =init-interactive= and - =test-empathy-accuracy=. The ability of the system to infer sensory - states is truly impressive. + =test-empathy-accuracy=. The majority of errors are near the + boundaries of transitioning from one type of action to another. + During these transitions the exact label for the action is more open + to interpretation, and dissaggrement between empathy and experience + is more excusable. ** Digression: bootstrapping touch using free exploration + In the previous section I showed how to compute actions in terms of + body-centered predicates which relied averate touch activation of + pre-defined regions of the worm's skin. What if, instead of recieving + touch pre-grouped into the six faces of each worm segment, the true + topology of the worm's skin was unknown? This is more similiar to how + a nerve fiber bundle might be arranged. While two fibers that are + close in a nerve bundle /might/ correspond to two touch sensors that + are close together on the skin, the process of taking a complicated + surface and forcing it into essentially a circle requires some cuts + and rerragenments. + + In this section I show how to automatically learn the skin-topology of + a worm segment by free exploration. As the worm rolls around on the + floor, large sections of its surface get activated. If the worm has + stopped moving, then whatever region of skin that is touching the + floor is probably an important region, and should be recorded. + + #+caption: Program to detect whether the worm is in a resting state + #+caption: with one face touching the floor. + #+name: pure-touch + #+begin_listing clojure + #+begin_src clojure +(def full-contact [(float 0.0) (float 0.1)]) + +(defn pure-touch? + "This is worm specific code to determine if a large region of touch + sensors is either all on or all off." + [[coords touch :as touch-data]] + (= (set (map first touch)) (set full-contact))) + #+end_src + #+end_listing + + After collecting these important regions, there will many nearly + similiar touch regions. While for some purposes the subtle + differences between these regions will be important, for my + purposes I colapse them into mostly non-overlapping sets using + =remove-similiar= in listing \ref{remove-similiar} + + #+caption: Program to take a lits of set of points and ``collapse them'' + #+caption: so that the remaining sets in the list are siginificantly + #+caption: different from each other. Prefer smaller sets to larger ones. + #+name: remove-similiar + #+begin_listing clojure + #+begin_src clojure +(defn remove-similar + [coll] + (loop [result () coll (sort-by (comp - count) coll)] + (if (empty? coll) result + (let [[x & xs] coll + c (count x)] + (if (some + (fn [other-set] + (let [oc (count other-set)] + (< (- (count (union other-set x)) c) (* oc 0.1)))) + xs) + (recur result xs) + (recur (cons x result) xs)))))) + #+end_src + #+end_listing + + Actually running this simulation is easy given =CORTEX='s facilities. + + #+caption: Collect experiences while the worm moves around. Filter the touch + #+caption: sensations by stable ones, collapse similiar ones together, + #+caption: and report the regions learned. + #+name: learn-touch + #+begin_listing clojure + #+begin_src clojure +(defn learn-touch-regions [] + (let [experiences (atom []) + world (apply-map + worm-world + (assoc (worm-segment-defaults) + :experiences experiences))] + (run-world world) + (->> + @experiences + (drop 175) + ;; access the single segment's touch data + (map (comp first :touch)) + ;; only deal with "pure" touch data to determine surfaces + (filter pure-touch?) + ;; associate coordinates with touch values + (map (partial apply zipmap)) + ;; select those regions where contact is being made + (map (partial group-by second)) + (map #(get % full-contact)) + (map (partial map first)) + ;; remove redundant/subset regions + (map set) + remove-similar))) + +(defn learn-and-view-touch-regions [] + (map view-touch-region + (learn-touch-regions))) + #+end_src + #+end_listing + + The only thing remining to define is the particular motion the worm + must take. I accomplish this with a simple motor control program. + + #+caption: Motor control program for making the worm roll on the ground. + #+caption: This could also be replaced with random motion. + #+name: worm-roll + #+begin_listing clojure + #+begin_src clojure +(defn touch-kinesthetics [] + [[170 :lift-1 40] + [190 :lift-1 19] + [206 :lift-1 0] + + [400 :lift-2 40] + [410 :lift-2 0] + + [570 :lift-2 40] + [590 :lift-2 21] + [606 :lift-2 0] + + [800 :lift-1 30] + [809 :lift-1 0] + + [900 :roll-2 40] + [905 :roll-2 20] + [910 :roll-2 0] + + [1000 :roll-2 40] + [1005 :roll-2 20] + [1010 :roll-2 0] + + [1100 :roll-2 40] + [1105 :roll-2 20] + [1110 :roll-2 0] + ]) + #+end_src + #+end_listing + + + #+caption: The small worm rolls around on the floor, driven + #+caption: by the motor control program in listing \ref{worm-roll}. + #+name: worm-roll + #+ATTR_LaTeX: :width 12cm + [[./images/worm-roll.png]] + + + #+caption: After completing its adventures, the worm now knows + #+caption: how its touch sensors are arranged along its skin. These + #+caption: are the regions that were deemed important by + #+caption: =learn-touch-regions=. Note that the worm has discovered + #+caption: that it has six sides. + #+name: worm-touch-map + #+ATTR_LaTeX: :width 12cm + [[./images/touch-learn.png]] + + While simple, =learn-touch-regions= exploits regularities in both + the worm's physiology and the worm's environment to correctly + deduce that the worm has six sides. Note that =learn-touch-regions= + would work just as well even if the worm's touch sense data were + completely scrambled. The cross shape is just for convienence. This + example justifies the use of pre-defined touch regions in =EMPATH=. + * Contributions diff -r 0a4362d1f138 -r f339e3d5cc8c thesis/images/touch-learn.png Binary file thesis/images/touch-learn.png has changed diff -r 0a4362d1f138 -r f339e3d5cc8c thesis/images/worm-roll.png Binary file thesis/images/worm-roll.png has changed diff -r 0a4362d1f138 -r f339e3d5cc8c thesis/rlm-cortex-meng.tex --- a/thesis/rlm-cortex-meng.tex Wed Mar 26 20:38:17 2014 -0400 +++ b/thesis/rlm-cortex-meng.tex Wed Mar 26 22:17:42 2014 -0400 @@ -45,6 +45,11 @@ \usepackage{libertine} \usepackage{inconsolata} \usepackage{rotating} +\usepackage{caption} + +%\usepackage{afterpage} + +%\afterpage{\clearpage} % \usepackage[backend=bibtex,style=alphabetic]{biblatex} \addbibresource{cortex.bib} @@ -58,6 +63,8 @@ citecolor={dark-blue}, urlcolor={medium-blue} } +\newenvironment{code}{\captionsetup{type=listing}}{} + \renewcommand{\thesection}{\arabic{section}} \renewcommand{\thefigure}{\arabic{figure}} @@ -82,6 +89,27 @@ %\usepackage{lgrind} \pagestyle{plain} + +%% % Alter some LaTeX defaults for better treatment of figures: +%% % See p.105 of "TeX Unbound" for suggested values. +%% % See pp. 199-200 of Lamport's "LaTeX" book for details. +%% % General parameters, for ALL pages: +%% \renewcommand{\topfraction}{0.9} % max fraction of floats at top +%% \renewcommand{\bottomfraction}{0.8} % max fraction of floats at bottom +%% % Parameters for TEXT pages (not float pages): +%% \setcounter{topnumber}{2} +%% \setcounter{bottomnumber}{2} +%% \setcounter{totalnumber}{4} % 2 may work better +%% \setcounter{dbltopnumber}{2} % for 2-column pages +%% \renewcommand{\dbltopfraction}{0.9} % fit big float above 2-col. text +%% \renewcommand{\textfraction}{0.07} % allow minimal text w. figs +%% % Parameters for FLOAT pages (not text pages): +%% \renewcommand{\floatpagefraction}{0.7} % require fuller float pages +%% % N.B.: floatpagefraction MUST be less than topfraction !! +%% \renewcommand{\dblfloatpagefraction}{0.7} % require fuller float pages +%% % remember to use [htp] or [htpb] for placement + + \begin{document} \include{cover}