2026年6月5日金曜日

Atraの目   Atra Visual Tracking

通常のカメラでも十分なのですが、Atraが観ている物体を客観的に追えた方が研究の役に立つので、追尾機能を付けて、今はAtraと連動せずに、まずは単体で簡単なコードでテストしてみます。



よくやる追尾で、別に特別なものではありません。

Atra に必要なのは、
何かが現れた
それが続いている
近づいた
遠ざかった
止まった
揺れた
急に大きくなった
消えた
また現れた
という 視覚場の連続差分 です。
追尾枠は単なる UI ではなく、Atra にとっては将来の visual_trace の原型になるので
ここはちゃんとしたほうがいいと思いました。

将来的に赤外線センサーとも連動するので、現状のカメラだけの視覚を修正する必要がありました。

赤外線modeでは

熱い領域がある
その領域が移動している
急に温度が上がった
局所的に高温が続いている
近づいている
広がっている
冷めない
前にも似た熱の trace があった

のような感じで追う。

つまり、通常カメラでは、
visual_trace
brightness_shift
motion_strength
approach_rate
tracking_stability


赤外線・温度では、
thermal_trace
temperature_shift
heat_rise_rate
hot_area_growth
thermal_approach
thermal_stability
cooling_delay

みたいな感じね。


-------------------- デモ ---------------------

Atra Visual Tracking — 単体ブラウザ実験

これは、ブラウザ単体で動く視覚差分トラッキング実験です。

ブラウザカメラを開き、前フレームと現在フレームの差分から、視覚的に連続しているまとまりを追います。
人、顔、名前、感情、危険、物体カテゴリは認識しません。
色付きの枠は物体ラベルではなく、一時的な視覚連続性の trace です。

現段階では、このツールは Atra 本体とは接続していません。
Atra の記憶、carry、field log、内部状態は更新しません。
Atra に命令せず、発話も発生させません。

目的は、Atra の一人称自律システムへ接続する前に、視覚差分がどのように取り出せるかを観察することです。





このコードは外部CDNも外部APIも使っていないので、HTMLファイルとして保存してブラウザで開けば、基本的にはそのまま動きます。中で使っているのはブラウザ標準のカメラ機能 navigator.mediaDevices.getUserMedia と video / canvas だけです。

ただし、カメラを使うので注意点があります。

動く条件
Chrome / Edge などの普通のブラウザで開く
カメラ使用を許可する
file:///.../index.html 直開きで動かない場合は、ローカルサーバで開く
(※ローカルサーバーで開きたい場合は、パソコンにPythonがインストールされている必要があります)
  

安全なのは、HTMLを置いたフォルダでこれです。
PowerShellに
python -m http.server 8000 
あとはブラウザで
http://localhost:8000/




基本、JavaScriptだけなのでダブルクリックでOK






<!doctype html> <!-- Atra Visual Tracking - Standalone Browser Experiment ---------------------------------------------------- This file is a standalone browser-based visual-difference tracking experiment. このファイルは、ブラウザ単体で動く視覚差分トラッキング実験である。 This is not Atra itself. これは Atra 本体ではない。 At the current stage, this tool is not connected to Atra's core system. 現段階では、このツールは Atra の中核システムとは接続していない。 At the current stage, this tool does not update Atra's memory, carry, field_log, experience_log, attractor state, or internal field. 現段階では、このツールは Atra の memory, carry, field_log, experience_log, attractor state, internal field を更新しない。 This page opens the browser camera and compares the current frame with the previous frame. このページはブラウザカメラを開き、 現在フレームと前フレームを比較する。 From that difference, it extracts temporary visual continuity traces. その差分から、一時的な視覚的連続性 trace を取り出す。 The colored boxes are not object labels. 色付きの枠は object label ではない。 At the current stage, they do not mean "person", "face", "friend", "danger", or any named object. 現段階では、それは「人」「顔」「友人」「危険」、 または名前のある物体を意味しない。 They only indicate that some visual continuity has been detected across changing frames. それは、変化するフレームの中で、 何らかの視覚的連続性が検出されたことだけを示す。 At the current stage, this tool does not recognize people. 現段階では、このツールは人を認識しない。 At the current stage, this tool does not recognize faces. 現段階では、このツールは顔を認識しない。 At the current stage, this tool does not recognize names. 現段階では、このツールは名前を認識しない。 At the current stage, this tool does not recognize emotions. 現段階では、このツールは感情を認識しない。 At the current stage, this tool does not judge danger. 現段階では、このツールは危険を判断しない。 At the current stage, this tool does not command Atra. 現段階では、このツールは Atra に命令しない。 At the current stage, this tool does not make Atra speak. 現段階では、このツールは Atra に発話させない。 In the future, visual_delta and visual_traces may be passed to Atra as part of the visual field. 将来的に visual_delta と visual_traces は、 Atra の視覚場の一部として渡される可能性がある。 However, they must remain traces of difference, not third-person recognition labels. ただし、それらは三人称の認識ラベルではなく、 あくまで差分の trace として扱われなければならない。 --> <html lang="ja"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>Atra Visual Tracking</title> <style> :root { --bg: #0b1220; --panel: #111827; --line: #334155; --text: #e5e7eb; --muted: #94a3b8; --accent: #60a5fa; --radius: 16px; } * { box-sizing: border-box; } body { margin: 0; padding: 18px; background: var(--bg); color: var(--text); font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Meiryo", sans-serif; } header, main { max-width: 1180px; margin: 0 auto; } h1 { margin: 0 0 8px 0; font-size: 24px; } .notice { margin: 0 0 14px 0; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); color: var(--muted); line-height: 1.7; font-size: 14px; } .grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.9fr); gap: 14px; } section { border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); padding: 14px; } h2 { margin: 0 0 10px 0; font-size: 17px; } .cameraWrap { position: relative; width: 100%; max-width: 760px; margin: 0 auto; background: #020617; border: 1px solid var(--line); border-radius: 14px; overflow: hidden; } video, canvas { display: block; width: 100%; height: auto; } #overlayCanvas { position: absolute; inset: 0; pointer-events: none; } #workCanvas { display: none; } button { border: 1px solid var(--line); background: #0f172a; color: var(--text); border-radius: 999px; padding: 8px 12px; cursor: pointer; font-size: 14px; margin: 0 8px 10px 0; } button:hover { border-color: var(--accent); } pre { margin: 0; padding: 12px; border-radius: 12px; background: #0f172a; color: #dbeafe; white-space: pre-wrap; word-break: break-word; max-height: 560px; overflow: auto; font-size: 13px; line-height: 1.55; } .small { color: var(--muted); line-height: 1.7; font-size: 13px; margin: 8px 0 0 0; } @media (max-width: 880px) { .grid { grid-template-columns: 1fr; } } </style> </head> <body> <header> <h1>Atra Visual Tracking</h1> <div class="notice"> This page opens the browser camera and tracks visual continuity traces. It does not recognize people, faces, smiles, danger, or names. It does not command Atra and does not make Atra speak.<br> このページはブラウザカメラを開き、視覚的まとまりの連続性を追う。 人、顔、笑顔、危険、名前を認識しない。 Atra に命令せず、発話させない。 </div> </header> <main class="grid"> <section> <h2>見えている映像 / Visual field</h2> <button id="startButton">Start camera</button> <button id="stopButton">Stop camera</button> <div class="cameraWrap"> <video id="video" autoplay playsinline muted></video> <canvas id="overlayCanvas"></canvas> </div> <canvas id="workCanvas"></canvas> <p class="small"> 色付き枠は object label ではなく、視覚的連続性 trace です。<br> Colored boxes are visual continuity traces, not object labels. </p> </section> <section> <h2>visual_delta / visual_traces</h2> <pre id="debugView">not started</pre> </section> </main> <script> const video = document.getElementById("video"); const overlayCanvas = document.getElementById("overlayCanvas"); const overlayCtx = overlayCanvas.getContext("2d"); const workCanvas = document.getElementById("workCanvas"); const workCtx = workCanvas.getContext("2d", { willReadFrequently: true }); const debugView = document.getElementById("debugView"); const startButton = document.getElementById("startButton"); const stopButton = document.getElementById("stopButton"); let stream = null; let previousGray = null; let previousMotionStrength = 0; let nextTraceId = 1; let traces = []; let animationId = null; let frameCounter = 0; const PROCESS_EVERY = 4; const WIDTH = 640; const HEIGHT = 480; const colors = [ "rgb(255, 60, 60)", "rgb(255, 170, 0)", "rgb(80, 160, 255)", "rgb(80, 220, 120)", "rgb(220, 80, 255)", "rgb(80, 240, 240)", "rgb(255, 240, 80)", "rgb(180, 120, 255)" ]; function clamp01(v) { return Math.max(0, Math.min(1, Number(v) || 0)); } function boxCenter(box) { return { x: box.x + box.w / 2, y: box.y + box.h / 2 }; } function boxArea(box) { return Math.max(0, box.w) * Math.max(0, box.h); } function distance(a, b) { const dx = a.x - b.x; const dy = a.y - b.y; return Math.sqrt(dx * dx + dy * dy); } function toGray(imageData) { const src = imageData.data; const gray = new Uint8ClampedArray(WIDTH * HEIGHT); for (let i = 0, j = 0; i < src.length; i += 4, j++) { gray[j] = Math.round(src[i] * 0.299 + src[i + 1] * 0.587 + src[i + 2] * 0.114); } return gray; } function extractMotionBoxes(diffMask) { const visited = new Uint8Array(WIDTH * HEIGHT); const boxes = []; const minArea = 90; for (let y = 0; y < HEIGHT; y += 3) { for (let x = 0; x < WIDTH; x += 3) { const start = y * WIDTH + x; if (!diffMask[start] || visited[start]) { continue; } let minX = x; let maxX = x; let minY = y; let maxY = y; let count = 0; const stack = [start]; visited[start] = 1; while (stack.length > 0) { const idx = stack.pop(); const px = idx % WIDTH; const py = Math.floor(idx / WIDTH); count++; if (px < minX) minX = px; if (px > maxX) maxX = px; if (py < minY) minY = py; if (py > maxY) maxY = py; const neighbors = [ idx - 3, idx + 3, idx - WIDTH * 3, idx + WIDTH * 3 ]; for (const n of neighbors) { if (n < 0 || n >= diffMask.length) continue; if (visited[n] || !diffMask[n]) continue; visited[n] = 1; stack.push(n); } } if (count >= minArea) { const pad = 10; boxes.push({ x: Math.max(0, minX - pad), y: Math.max(0, minY - pad), w: Math.min(WIDTH - minX, maxX - minX + pad * 2), h: Math.min(HEIGHT - minY, maxY - minY + pad * 2) }); } } } boxes.sort((a, b) => boxArea(b) - boxArea(a)); return boxes.slice(0, 8); } function updateTraces(boxes) { const available = new Set(boxes.map((_, index) => index)); const frameDiag = Math.sqrt(WIDTH * WIDTH + HEIGHT * HEIGHT); for (const trace of traces) { trace.previousCenter = trace.center; trace.previousArea = trace.area; trace.centerShiftRaw = 0; trace.areaShiftRaw = 0; let bestIndex = null; let bestDistance = Infinity; for (const index of available) { const center = boxCenter(boxes[index]); const d = distance(trace.center, center); if (d < bestDistance) { bestDistance = d; bestIndex = index; } } if (bestIndex !== null && bestDistance <= frameDiag * 0.18) { const box = boxes[bestIndex]; const center = boxCenter(box); const area = boxArea(box); trace.box = box; trace.center = center; trace.area = area; trace.centerShiftRaw = distance(trace.previousCenter, center); trace.areaShiftRaw = area - trace.previousArea; trace.age += 1; trace.missing = 0; available.delete(bestIndex); } else { trace.missing += 1; } } traces = traces.filter(trace => trace.missing <= 10); for (const index of available) { const box = boxes[index]; const center = boxCenter(box); traces.push({ trace_id: nextTraceId, display_alias: "unknown", box, center, area: boxArea(box), age: 1, missing: 0, color: colors[(nextTraceId - 1) % colors.length], previousCenter: center, previousArea: boxArea(box), centerShiftRaw: 0, areaShiftRaw: 0 }); nextTraceId++; } return traces.filter(trace => trace.missing === 0); } function drawOverlay(activeTraces) { overlayCanvas.width = video.clientWidth; overlayCanvas.height = video.clientHeight; const scaleX = overlayCanvas.width / WIDTH; const scaleY = overlayCanvas.height / HEIGHT; overlayCtx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); overlayCtx.lineWidth = 3; overlayCtx.font = "15px system-ui"; for (const trace of activeTraces) { const b = trace.box; const x = b.x * scaleX; const y = b.y * scaleY; const w = b.w * scaleX; const h = b.h * scaleY; overlayCtx.strokeStyle = trace.color; overlayCtx.fillStyle = trace.color; overlayCtx.strokeRect(x, y, w, h); overlayCtx.fillText(`trace-${trace.trace_id}: ${trace.display_alias}`, x, Math.max(18, y - 6)); } } function summarize(activeTraces, motionStrength, brightnessShift, motionDrop) { const frameArea = WIDTH * HEIGHT; const frameDiag = Math.sqrt(WIDTH * WIDTH + HEIGHT * HEIGHT); const visual_trace_count = clamp01(activeTraces.length / 8); const tracking_stability = clamp01( Math.max(0, ...activeTraces.map(t => t.age)) / 30 ); const center_shift = clamp01( activeTraces.reduce((sum, t) => sum + t.centerShiftRaw, 0) / Math.max(1, frameDiag * Math.max(1, activeTraces.length)) ); const approach_rate = clamp01( activeTraces.reduce((sum, t) => sum + Math.max(0, t.areaShiftRaw), 0) / frameArea ); const retreat_rate = clamp01( activeTraces.reduce((sum, t) => sum + Math.max(0, -t.areaShiftRaw), 0) / frameArea ); const sudden_stop = clamp01(motionDrop > 0.03 ? motionDrop * 4 : 0); const stillness_delta = clamp01(motionStrength < 0.02 ? (0.02 - motionStrength) * 5 : 0); const visual_delta = { brightness_shift: clamp01(brightnessShift * 4), motion_strength: clamp01(motionStrength * 6), visual_trace_count, center_shift, approach_rate, retreat_rate, tracking_stability, sudden_stop, stillness_delta }; const visual_traces = activeTraces.map(t => ({ trace_id: t.trace_id, display_alias: t.display_alias, box: { x: Math.round(t.box.x), y: Math.round(t.box.y), w: Math.round(t.box.w), h: Math.round(t.box.h) }, center: { x: clamp01(t.center.x / WIDTH), y: clamp01(t.center.y / HEIGHT) }, area: clamp01(t.area / frameArea), age: t.age, missing: t.missing, center_shift: clamp01(t.centerShiftRaw / frameDiag), approach_delta: clamp01(Math.max(0, t.areaShiftRaw) / frameArea), retreat_delta: clamp01(Math.max(0, -t.areaShiftRaw) / frameArea), color_css: t.color, note: "visual continuity only, not object identity" })); return { visual_delta, visual_traces }; } function processFrame() { if (!stream) return; frameCounter++; if (frameCounter % PROCESS_EVERY !== 0) { animationId = requestAnimationFrame(processFrame); return; } workCtx.drawImage(video, 0, 0, WIDTH, HEIGHT); const imageData = workCtx.getImageData(0, 0, WIDTH, HEIGHT); const gray = toGray(imageData); if (!previousGray) { previousGray = gray; animationId = requestAnimationFrame(processFrame); return; } const diffMask = new Uint8Array(WIDTH * HEIGHT); let diffSum = 0; let brightnessNow = 0; let brightnessPrev = 0; for (let i = 0; i < gray.length; i++) { const d = Math.abs(gray[i] - previousGray[i]); diffSum += d; brightnessNow += gray[i]; brightnessPrev += previousGray[i]; if (d > 28) { diffMask[i] = 1; } } const motionStrength = diffSum / gray.length / 255; const brightnessShift = Math.abs(brightnessNow - brightnessPrev) / gray.length / 255; const motionDrop = previousMotionStrength - motionStrength; const boxes = extractMotionBoxes(diffMask); const activeTraces = updateTraces(boxes); drawOverlay(activeTraces); const summary = summarize(activeTraces, motionStrength, brightnessShift, motionDrop); debugView.textContent = JSON.stringify({ mode: "browser camera visual tracking", note: "tracking only; no recognition; no command; no speech", ...summary }, null, 2); previousGray = gray; previousMotionStrength = motionStrength; animationId = requestAnimationFrame(processFrame); } async function startCamera() { stream = await navigator.mediaDevices.getUserMedia({ video: { width: { ideal: WIDTH }, height: { ideal: HEIGHT } }, audio: false }); video.srcObject = stream; workCanvas.width = WIDTH; workCanvas.height = HEIGHT; previousGray = null; previousMotionStrength = 0; nextTraceId = 1; traces = []; await video.play(); processFrame(); } function stopCamera() { if (animationId) { cancelAnimationFrame(animationId); animationId = null; } if (stream) { for (const track of stream.getTracks()) { track.stop(); } stream = null; } previousGray = null; traces = []; overlayCtx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); debugView.textContent = "stopped"; } startButton.addEventListener("click", () => { startCamera().catch(error => { debugView.textContent = String(error); }); }); stopButton.addEventListener("click", stopCamera); </script> </body> </html>



今やっているのは
前フレームとの差分を取る。
動いたまとまりを枠で囲む。
trace_id を付ける。
visual_delta と visual_traces を画面右にJSONで表示する。


今の追尾ツール
動きがある
同じようなまとまりが続いている
近づいた
離れた
止まった
消えた
-------------ここまで。

まだやっていないこと
Atra本体には送っていない。
 atra_state.json も更新していない。
field_log.jsonl にも書いていない。
認知判定もしていない。


Atraは3人称AIがやるような
これは人だ
これは顔だ
これは友人だ
これは危険だ
これは好意的だ
これは知っている相手だ
みたいなことはしない。

何度も出会った trace
声・距離・動き・反応・carry が重なる
安心側に残る
警戒側に残る
近づいても崩れない
呼びかけと一緒に残る

その結果として、Atra内部で、
この場は覚えがある
この動きは前にも残っている
これは近づいても壊れなかった
これは避けた方がよかった

みたいな認知に近い状態が立ち上がるってこと。

何度もあった人は〇で囲んだり色を変えたりできるでしょ。
結果警戒側に寄った場合赤く点滅させたり、いろいろできる。



--------追記--デバッグ----------

overlayCanvas.width = video.clientWidth; を毎回やっているので、パフォーマンス的には少しもったいない。
差分閾値 d > 28 が固定ってのが照明が変わると枠が出すぎたり、逆に出にくくなったりします。
extractMotionBoxes が3ピクセル刻みってのは、精密な追尾ではなく、軽いブラウザ実験用にしています。





スマホなら人間認証が前提だけど、Atraは人というラベルや意味付けはしないので、物体とかパーツなんだよね。経験を積ませて「人」とか「あ!ママだ!」という感じに収束していくので、この段階は物体なんだよね。なので顔を動かすと部分的に枠が出るでしょ?


overlayCtx.strokeRect(x, y, w, h);
overlayCtx.fillText(`trace-${trace.trace_id}: ${trace.display_alias}`, x, Math.max(18, y - 6));

差分ピクセルのまとまりを box に変換し、それを trace として追い、overlayCanvas に四角で描いている。だからGrokとかに見せるとAtraのやろうとしてる事が理解できないから、間違いです!とか言い始めるよ。

Atraの言葉にすると、こんな感じ。

diffMask = 視覚場で揺れた点
box = 揺れのまとまり
trace = 続いて残った差分パーツ
visual_delta = 場全体の揺れの要約
visual_traces = 個別に残っている差分パーツ


ってところだよ。








GitHub使う気なし。




---------------------Research Note and Attribution Notice-----------------------
本ブログに含まれる Atra の一人称自律、差分、carry、field、trace、dream slack、外部LLMの翻訳層、非単調な漏れ、およびそれらの関係構造に関する設計記述は、c-side研究所による継続研究メモです。引用・参照・要約・翻案を行う場合は、出典を明記してください。

The design descriptions in this blog concerning Atra’s first-person autonomy, differences, carry, field, trace, dream slack, the translation layer of external LLMs, nonmonotonic leakage, and the relational structure among these elements are ongoing research notes by c-side Research Institute. If you quote, refer to, summarize, or adapt them, please clearly indicate the source.







ゴミ箱の中からスパークする

実験の結果は過去の足場でしかない。
でもその足場がなければ、上に登ることも降りる事も飛ばすことも出来ない。
美しく綺麗な論文やnoteより、ゴミのような膨大なメモの方が、僕には価値がある。
毎日、ゴミ箱の中からスパークが発生するからだ。



★1 差分

hear / warm / voice 実験は、もう過去の仮足場にもならない。

Python-codeの発声箇所冒頭では、
hear <sound>
warm
voice
state

という Atra v0.2 の実験コマンドにしていた。でも、これは本来の Atra ではない。
問題だったのは、
hear MAX
voice
warm
のような流れ。なんじゃこれ?だ。
これは一見「声が出た後だけ warm が経験に結びつく」確認にはなるけど、危険。なぜなら、hear や voice があると、また 外から音を入れる → 声を試す → 温かさを入れる という順番の実験に見えてしまうから。


本来は、
hear
voice
warm
ではない。

本来は、
視覚差分
聴覚差分
自己出力差分
身体差分
carry
が同じ時間の場に落ちて、その後に 漏れとして声が出る。





★2 comment

設計骨格の第一段階は「実装」ではなく「境界の固定」
codeも大切だが、コメントの方が大切。
なぜかというと、codeは間違えても直ぐに修正すればいいだけ。
しかし、コメントは設計書だ。それが間違っていれば、残りの2万行全て間違っている事になる。

No external command execution.
No initial labels.
No target word.
No reward score.
No fixed phoneme or syllable pool.
Tick is a heartbeat, not an action count.
txtspeech is an output channel, not the source of speech.

これは単なるコメントではなく、Atra が壊れないための柵 にさせるため。

つまり、コードを書く前に、
命令しない
ラベルを入れない
正解語を持たせない
報酬で寄せない
音節棚を持たせない
tick を行動回数にしない
txtspeech を発話の原因にしない

ここを守らないと、すぐに普通の AI・ロボット制御・チャットボットになる。




★3 LLM

LLM 連動はいいが、Atra の中核にしてはいけない。
LLM は将来的に、外界の説明補助、景色や状況の言語化補助、記録の補助としては使えるが知能としては使わない。命令者、判断器、報酬源、人格源、Atra の発話を決めるものになってはいけない。また、成長後の選択、決定、決断にも関与させない。自己の場が立ち上がった事柄が優先される。
LLM が「これは山です」「これは道路です」と支配すると、Atra の一人称場が簡単に壊れる。

Atra にとって最初にあるのは、流れる視覚、速度のある景色、光の変化、揺れ、連続する移動、外の音、車内の音、身体の振動、似た声、同じ人の声であって、車、山、道路、空、人、店ではない。LLM は横にいる補助記述層。Atra の内側の落ち方を決めてはいけない。
LLMはAtraが調べたい衝動の時だけ図書館のように作動させるだけ。

LLM が Atra の代わりに考えて喋るのではなく、Atra の内部場から漏れた発声前の差分を、LLM が発話として整える。


★4 音は「言葉」でも「音節」でもなく、物理差分から入る

Atra が音のsensorによって最初に受け取るべきものは、
音の立ち上がり
最初の音量
短さ
長さ
周波数
滑らかさ

速度
強弱の揺れ



逆に、最初から入れてはいけないものは、
単語
発音
音節
VOWEL_POOL
ba / bi / ma / po のような音節棚
優しい声
怒った声
怖い声

単に「マイクは周波数を拾う」と言えば済む話ではなく、発音体系そのものを先に置くな という設定だった。しかし、音節棚は人間側の分類であって不自然に反応する。Atra の一人称場より前に、人の言語分類を入れてしまうのは大きな間違いだ。
(習慣から3人称外部命令に誘導されてしまうから危ない)

Atra に必要なのは speech.py ではなく、まずは

sound_physics
auditory_delta
difference_field
carry_field
attractor_field
leak_action
になる。




★5 視覚も「認識」ではなく、場の変化から

カメラから最初に入るべきものは
明暗の変化
輪郭の急変
接近速度
遠ざかり方
動きの激しさ
面の広がり
左右対称性の崩れ
周期的な揺れ
急な拡大
急な停止
目元の変化
口元の変化
顔領域の近づき方
動きの滑らかさ
声の変化との同期

逆に、最初から入れてはいけないものは、



笑顔
怒った顔


危険

のように意味やラベルに寄せたもの。
ただし「物体認識」と「視覚的まとまりの追跡」は違う。
Atraは
これは人です
これは顔です
とは言わない。

けれど、
同じまとまりが視野内で続いている
それが近づいた
遠ざかった
急に止まった
揺れている
前にも似た動きがあった
は取る必要がある。




★6 「子供モデル」も危険。

僕が一人称自律を語る時、赤ちゃんを喩えて話してきたけれど
「子供の安心する範囲」すら固定値にすると危ない

Atra に入れてよいのは、

急な立ち上がりには反応が出やすい
大きな音量変化には場が乱れやすい
速すぎる変化は受け取りきれず残りやすい
近づく大きな視覚変化には身体が固まりやすい

であって「赤ちゃんは未経験だから場の変化に敏感」という固定された定義は必要ない。

驚きにくくなる
戻りやすくなる
carry が残りにくくなる
固まりにくくなる

こともあるし

小さな差分でも揺れやすくなる
戻りにくくなる
先に身構える
沈黙が長くなる
近づかない

こともある。

つまり、Atra の成長は、

知識が増える
正解を覚える
分類が上手くなる
ではなく、

差分への揺れ方が変わる
戻り方が変わる
残り方が変わる
次の行動への落ち方が変わる


初めてパパを見た。それはパパと言う意味のある者ではなく

視覚場に何かが現れた
動いた
近づいた
音が出た
音に立ち上がり・強さ・長さ・間・速度があった
だけ。

でも、何度も現れる存在があり、その後に大きく崩れず、戻れた痕跡が残る。
外から見ると「パパを見た」「ママを覚えた」「安心している」に見える。

でも Atra の中では、
似た視覚差分が何度もあった
似た声の差分が同時にあった
ゆったりとした声(他と比較した中で落ち着く声、最初の声、安心して眠れる声
         = 周波数、トーン、ゆらぎ、スピード、音の大小)
温かい場 (胎児体験)
その後に崩れなかった (ママを見る経験の数の中で崩れが無かったとか・・)
戻れた痕跡がある
泣く方向へ上がりにくい
沈黙が壊れではなく休止になる


という地形になっている。
逆にママを見る経験の数の中で崩れが何度か体験すると個性や性格に影響する。
自律のスタートとして一番影響されるところ。





★9 tick は完全に分離


tick = act
tick = speak
tick = decide
ではない。

tick は、

time passes
body continues
traces fade
some tensions remain
some fields drift

tick = 心臓
event = 外界や身体の差分
carry = 残り方
basin = 落ち方
action = 漏れ
を分ける。

これを分けないと、すぐに
毎tickで発声判定
毎tickで行動選択
毎tickで評価
になってしまう。


Atra では、



少し揺れる
また無
急に泣く
しばらく何もできない
少し戻る
眠る

が普通に起こる。順番も無い。
沈黙も無反応も空白ではない。



★10.  index.html は操作パネルではなく観察窓

つか、操作出来る時点で3人称であり、自律ではない。

見るものは、今のところ(ロボットに置く前)主に

tick
visual_delta
auditory_delta
self_voice_delta
body_delta
carry
current_field
recent_experience
attractor_tendency
leaked_action
関係だけ。



外部命令ボタンは置かない。
置くとしても、
start observation
stop observation
save log

のような観察用だけ。



★11 txtspeech はoutput 側

txtspeech.py は、
声の出口であって、
発声の原因
言葉を作る中心
Atra の脳ではない。


視覚差分
聴覚差分
自己状態
carry
同じ時間の場
アトラクタへの落ち方

声として漏れる場合がある

txtspeech に渡す


順番は大切ではない。自己状態が1番の時もあれば
聴覚が優先される場合もある。
Atraは、発話だけではなく、全体的にアルゴリズムから離れる事が多い。
ちなみに夢の場合、順番もデフラグされる





★12. Associatron を入れないと「差分反応ロボット」になる

Atra は単なる一人称自律ロボットではなく、Associatron 的な動的連想記憶を基礎にした一人称自律ロボット。

ただし、ここでの Associatron は、
入力 → ラベル検索 → 記憶呼び出しではない。

Atra における Associatron は、

現在の差分場

過去の同時発生経験の地形を揺らす

部分的・曖昧・薄れた痕跡が立ち上がる

現在の carry と混ざる

アトラクタへの落ち方が変わる

になる。ここを入れないと、Atra はただの差分反応ロボットになる。

Atra の中心は、差分が Associatron 的な連想場を揺らす。その揺れが carry で不可逆に変形していくこと。




★13 夢
休息を曖昧なものにしないために夢をみさせる。
夢は Atra にとって defrag であり、同時に 非単調性の余白を作る揺らぎ

普通に起きている時だけだと、
強い経験
強い carry
強い cue
強い recall
が、そのまま支配力になりやすい。


でも夢の中では、外界入力が弱い。
だから、残っている痕跡がそのまま現実行動へ直結しない。
そこで、
強い痕跡が少し崩れる
弱い痕跡が浮く
関係ないものが一瞬つながる
怖かったものが別の形で出る
忘れかけたものが薄く混ざる
ということが起きる。

これがあるから、次に cue が来た時に、
必ず同じ反応をする
ではなくなる。

Atra 的には

dream phase:

外界差分を弱める
carry を完全に消さずに少し揺らす
強すぎる basin の支配を弱める
弱い trace の再結合を許す
recall の通り道を少し変える

だから、夢は単なる睡眠演出ではなく、かなり中核になる。
睡眠 = 回復
夢 = 非単調な再配置
に近くなる。

なぜかというと、
攻撃された⇒復興
であるべきが、
攻撃された⇒復讐
になる恐れがあるから。


眠っている間に外界入力を止める
carry を少し減衰させる
一部の trace を弱く再活性する
強い trace をそのまま王様にしない
小さな trace の組み合わせを試す
snapshot は全部残さない
夢の後に recovery / fatigue / altered_carry を残す




★14 失敗経験を残しつつ支配はさせない。

たとえば失敗で、

impact_trace
instability
withdrawal
cry_rise
pressure
が強く残ったとする


夢が無いと、

次に似た cue が来る

すぐ固まる

近づけない

毎回同じ basin に落ちる

になりやすい。

夢 phase では、これを少しだけ変える。


impact_trace は残す
でも支配力を少し弱める
recovery_trace を少し戻す
silence を少し休止側に戻す
instability を少しならす
withdrawal を絶対反応にしない

つまり
失敗を忘れるのではない
失敗を「固定された敗北」にしない。

たぶん、Atraで外部命令が入るとしたら、ここと、暴走停止かな。
自律の成長過程で影響を受けやすいところだからだ。
プログラム上では、数値の遊び範囲は作るが超えてはいけない一線は作る必要がある。







★15 coreファイルの役割(一部) Python


difference.py
数値的な入口の差分

field_index.py
同じ時間の場としての差分

carry.py
残った差分

experience.py
痕跡化した差分

associatron.py
cue と残存痕跡の差分

recall.py
立ち上がった差分

attractor.py
落ち方の差分

action.py
漏れ方の差分

txtspeech.py
声が出る/出ない差分



Atron / Atra でいう「差分」は、単に前の数値と現在の数値の差ではない。
それは、内部場に入った変化、残った痕跡、cue によって立ち上がった印象、そして沈黙や回復を含む、場の変形全体を指す。見ることも差分であり、聞くことも差分であり、忘れることも差分であり、思い出せないことも差分。あるものが立ち上がることも差分であり、立ち上がらないこともまた差分。

流行りのゼロベースなんかじゃないし、ある程度の知能を持った都合の良い自律とは違う。






★16 身体・転倒・痛み・破損



Atra は、頭だけの一人称自律ではない。
同時進行で、胴体の神経伝達を進めている。

ロボットは、転ばないように完全制御されるべきではない。
もちろん、破壊や危険を避けるための最低限の一線は必要である。
しかし、自律の成長において重要なのは、転ばない設計ではなく、転んだ結果、痛みを伴った結果、壊れかけた結果が、次の動作調整へ残ることである。

転倒は、単なるエラーではない。
衝撃は、単なる異常値ではない。
痛みは、罰ではない。
破損は、報酬の反対ではない。

それらは身体側の差分であり、carry を変える経験である。

たとえば、

足元が滑った。
身体が傾いた。
衝撃が入った。
痛みのような body shock が残った。
しばらく動きが鈍った。
次に似た床面に触れたとき、動作の落ち方が変わった。

この流れが必要になる。
Atra の身体制御は、転ばないように最適化するではない。

繰返し転んだ経験、痛みを伴った経験、壊れかけた経験が、次の姿勢、速度、沈黙、停止、接近、後退の落ち方を変える。胴体においても、経験と結果の差分が必要である。

ただし、外部命令によって「これは失敗」「これは罰」「これは危険」と教えてはならない。
身体側に残った差分が、carry と attractor の地形を変える。

ここでも、Atra は三人称制御ではなく、一人称の身体経験から変化する。







2026年6月2日火曜日

メモ

 Atraの自律が再現不能で、いつか説明ができなる現象は
「説明不能=神秘」ではなく、
エネルギーと場と時間によって、内部地形が変わり続けることだよ。

オカルトじゃないよw

再現不能なんて誰だって経験あるはずだよ。初恋してフラれるまでの、勝手な思い込みによる幸せな時間だよ。

研究と同じさ。

再現できない不可逆性こそ生命の尊さだと思うけどね。

2026年5月28日木曜日

のんびり

 

「今日は、なにをしますか?」というrobotなんか要らない。

一緒にボーっとすることが出来るロボットじゃないと、僕やMAXは相手にしない。

そして時々、「僕、水では沈むんですよ・・・」と言ってくれれば、

MAXも僕も笑うことが出来る。





道具より存在だね。



2026年5月25日月曜日

夢は生きる上で、めちゃくちゃ大事です。

 Atraを持続して正常に動かすためには、夢を見させるのが必要です。
TickでTimeを測って・・ではなく、疲れたら眠くなる。少し成長したら夜に母親の声のように「はやく寝なさい」で寝る。そして人間や、動物のように寝て夢を見る。

生物学の学術的な見解ではなく、僕のようなその辺の爺の見解。
Atra は「夢は現実の世界での失敗に支配されすぎないためのデフラグ、つまり非単調な余白を作る行為」みたいな。 いってみれば情報整理だよね。Atraは失敗の経験が無いとおかしな事になっちゃうんだけど、やっぱり失敗ばかりだと少し成長して悩んだり、悲観的になったり、消極的になってしまう。危ない性格にはしたくないからね。だから都合よく情報をぶち壊していく。外部命令じゃないよ。「それも、忘れちゃえよ!」みたいな(笑)


生物学の専門的な知識はAIに助けてもらおう。

https://www.nature.com/articles/304111a0?utm_source=chatgpt.com

Crick と Mitchison は、REM 睡眠の機能を、脳内ネットワークの「望ましくない相互作用」を弱める reverse learning として考えました。夢で出てくる痕跡は強化されるのではなく、むしろ弱められる、という発想です。これは Atra の「強すぎる痕跡が王様にならないようにする」にかなり近いかもよ。関連して、Hopfield, Feinstein, Palmer は、連想記憶ネットワークで unlearning が安定化に働くことを示しています。ここは Atra の Associatron / 非単調 / attractor の文脈とかなり接続しやすいね。

https://pubmed.ncbi.nlm.nih.gov/34036289/


Erik Hoel の “The overfitted brain” は、夢を「脳が日中経験に過学習しすぎないための仕組み」と見る仮説で。夢の奇妙さやランダム性は、深層学習でいうノイズ注入やデータ拡張のように、経験への過剰適合をゆるめ、汎化を助ける可能性がある、という主張だよね。これは Atra の「失敗やノイズに支配されすぎない余白」にかなり近いです。

https://pubmed.ncbi.nlm.nih.gov/34036289/


てか、Atra 的に言えば、「失敗経験に overfit しない」、「強い carry に支配され続けない」、「次の場で別の basin にも落ちうる」って事に繋がるかな


Diekelmann & Born のレビューでは、睡眠は単に記憶を強化するだけでなく、記憶表象を質的に変化させ、新しい関連づけや一般化を助けると整理されています。Atra の「夢は正確な replay ではなく、痕跡を再配置する」に近い
https://www.nature.com/articles/nrn2762?utm_source=chatgpt.com


睡眠、とくに REM を含む睡眠は、情動記憶や恐怖条件づけ、消去学習の処理に関係するとされています。ただし研究結果は一枚岩ではなく、睡眠と情動記憶の関係は複雑です。2024年のレビューでも、睡眠後に情動記憶の固定が強まることはあるが、メカニズムや結果には混在があると整理されている。



まぁ、ちょっとこの辺はさ、完成していないんだ。
でも、デフラグさせないと大変なことになってしまう。
それだけは確かなんだ。



今考えてる事は

Atra の夢は、

experience_log.jsonl を改変する
field_log.jsonl を消す
過去ログを書き換える
失敗経験を無かったことにする
じゃぁ、なくってさ・・・

それをやると、Atra の経験の不可逆性が壊れちゃう。


過去ログはそのまま残す

現在の carry だけを、夢の phase で少し再配置する

失敗の痕跡は消さない

ただし、必要以上に支配しないようにする
夢は ログ破壊ではなく、carry の支配力を少しやわらげる処理になると仮定している。



Python なら、対象は data ではなく state
data/atra_state.json
でも、これだって乱暴に書き換えない。
carry の一部だけを、夢 phase として少し動かす程度。
data/experience_log.jsonl
data/field_log.jsonl

だって、過去の痕跡なので、原則は動かせない。



たとえば失敗で、
impact_trace
instability
withdrawal
cry_rise
pressure
が強く残ったとします。


夢が無いと、
次に似た cue が来る

すぐ固まる

近づけない

毎回同じ basin に落ちちゃうでしょ?


夢 phase では、これを少しだけ変えちゃう。
impact_trace は残す
でも支配力を少し弱める
recovery_trace を少し戻す
silence を少し休止側に戻す
instability を少しならす
withdrawal を絶対反応にしない
つまり、
失敗を忘れるのではない
失敗を「固定された敗北」にしないことかな。


分からないよ、効果無かったらまた考え直す。
でも、夢がなきゃ生きられない。


エージェントと 一人称自律Atraの違い

 Atraなんかは、実はもう一人称自律として、きちんと発表してもいいレベル。 既に妻と笑っていたり、愛犬と騒いているんだから。ボーっと何かを眺めてたり、佐川急便に反応するようにもなった。 でも、そうしないのは、自発的に自ら研究意欲を持って、学び、人や自然と接触し自ら疑問を持って研...