😎
processingの勉強1
とりあえず何も考えずぽちぽちしていく。
// 4x4 -> 3 -> 2 3D NN Visualizer + 2D「AIくん」判定吹き出し付き
// Processing 4 / Java mode / P3D
// ====== レイアウト / 見た目 ======
final int CANVAS_W = 1280;
final int CANVAS_H = 900;
final int GRID_ROWS = 4, GRID_COLS = 4; // 入力は4x4=16
final float GRID_SP = 70; // 上部グリッド点間隔
final float GRID_Y = -360; // 上部グリッド高さ
final float L0_Y = -180f; // 入力(16)
final float L1_Y = -20f; // 隠れ(3)
final float L2_Y = 140f; // 出力(2)
final float L1_SPAN_X = 260; // 隠れの横幅
final float L2_SPAN_X = 150; // 出力の横幅
final float NODE_R = 4.0f; // ノード球半径
final boolean ADDITIVE_GLOW = true; // 加算合成で発光
final int COL_BG = 0xff0E0E10; // 背景
final int COL_DOT = 0xffE8E8E8; // 白点(入力グリッド)
final int COL_NODE = 0xffC82828; // ノード
final int COL_LINE_POS = 0xffFF3A3A; // 正の重み(赤)
final int COL_LINE_NEG = 0xff2A6AFF; // 負の重み(青)
final int LINE_ALPHA = 85; // 線の透明度
final float LINE_W_MIN = 0.4f; // 線太さ min
final float LINE_W_MAX = 5.0f; // 線太さ max
// 出力シンボル(3D ○/×)のスケール
final float O_SCALE_MIN = 0.65f, O_SCALE_MAX = 1.35f; // o0用
final float X_SCALE_MIN = 0.65f, X_SCALE_MAX = 1.35f; // o1用
final float O_MAJOR_R = 26; // ○の大半径(ベース)
final float O_TUBE_R = 6; // ○のチューブ半径(ベース)
final float X_BAR_LEN = 55; // ×の棒の長さ(ベース)
final float X_BAR_THICK = 10; // ×の棒の太さ(ベース)
// 右側 UI(入力パネル)
final int PANEL_X = 900, PANEL_Y = 120;
final int CELL = 80, GAP = 10;
final int COL_PANEL_BORDER = 0xffC8C8C8;
// ====== NN パラメータ(16->3->2:提供値) ======
float[][][] weights = new float[][][] {
{ // 入力(16) -> 隠れ(3)
{
-0.19556837184815432, -2.0731887662694675, -0.7652514121341945, -1.9884231323546566,
-4.952637298076189, 5.659829256271411, -0.5713695038053532, -1.4846930025289022,
-1.4970230006948473, 2.5726393101553975, -0.2504789124544582, 1.480466604318017,
-0.8298236501477579, -4.5199641859013955, -1.4981634293951982, 2.011290351680955
},
{
-3.4835715114090715, 5.010347806892839, 2.9247242936422113, -4.194203236742492,
-0.17924275715765517, -2.403425422788088, 0.40385725801892475, 1.8787273651616636,
2.047521825332689, -0.16374517197602814, 0.47853555594913116, 5.6545162920862575,
-6.058153846339116, 0.42470424485595815,-0.8371742892189643, -2.879606740652077
},
{
2.884860808289696, 0.23975579237277614,-1.2403687366139762, -2.3025676808322486,
-0.7475210018222626, -6.5294340577398575, -0.559934356147751, 4.0010381968700575,
5.0747200536885, -4.225817417542366, 0.3105588568588239, 3.308254461438346,
4.348740489196476, 1.5652833651727298, -4.873553428254676, -1.3786319596139733
}
},
{ // 隠れ(3) -> 出力(2)
{ -8.832622109783433, 8.303120604609045, -6.0039452831036275 },
{ 8.827857967700506, -8.306736033721686, 6.003293693110446 }
}
};
float[][] biases = new float[][] {
{ 6.286020903686753, 3.2317338139016565, 2.8075640195084577 }, // 隠れ
{ 2.626446601080335, -2.618405339273877 } // 出力
};
// ====== 内部ワーク ======
PVector[] topGrid; // 上部 4x4 白点
PVector[] lay0; // 入力(16)
PVector[] lay1; // 隠れ(3)
PVector[] lay2; // 出力(2) [0]=○, [1]=×
boolean[][] grid = new boolean[GRID_ROWS][GRID_COLS]; // 入力パネル(0/1)
float angleY = 0, angleX = 0;
// 正規化用:それぞれの層で |activation*weight| の最大想定
float maxW_IH = 1f; // 入力->隠れ
float maxW_HO = 1f; // 隠れ->出力
void settings() {
size(CANVAS_W, CANVAS_H, P3D);
smooth(8);
}
void setup() {
surface.setTitle("4x4 -> 3 -> 2 : 3D O/X + 2D AI-kun speech");
buildTopGrid();
buildLayers();
clearGrid();
computeWeightMaxima();
}
void draw() {
background(COL_BG);
lights();
// ==== 左:3D ビジュアライズ ====
float[] o; // 出力活性(後でAIくんの吹き出しに渡す)
{
pushMatrix();
translate(width*0.33f, height*0.56f, 0);
// ゆっくり回転(3D感)
rotateY(angleY);
rotateX(angleX);
angleY += 0.005;
angleX += 0;
// 上部 4x4 白グリッド(ONセルは赤)
drawTopGrid();
// 入力ベクトル x(0/1)
float[] x = currentInputVector();
// 前向き計算(sigmoid)
float[] h = new float[3];
for (int j = 0; j < 3; j++) {
float s = 0;
for (int i = 0; i < 16; i++) s += weights[0][j][i] * x[i];
s += biases[0][j];
h[j] = sigmoid(s);
}
o = new float[2];
for (int k = 0; k < 2; k++) {
float s = 0;
for (int j = 0; j < 3; j++) s += weights[1][k][j] * h[j];
s += biases[1][k];
o[k] = sigmoid(s);
}
// 線の描画:太さ ∝ |activation * weight|
if (ADDITIVE_GLOW) blendMode(ADD);
drawEdges_InputToHidden(x);
drawEdges_HiddenToOutput(h);
blendMode(BLEND);
// ノード(入力・隠れは球)
drawNodes(lay0);
drawNodes(lay1);
// 出力は 3Dの○ と 3Dの× に置換(大きさ = o0, o1)
drawOutputSymbols(o);
popMatrix();
}
// ==== 右:入力パネル & 判定表示(2D HUD) ====
drawGridPanel();
drawPrediction(o);
// ==== 右:AIくん(2D) ====
drawAIKunWithSpeech(o);
}
// ================= 構築 =================
void buildTopGrid() {
topGrid = new PVector[GRID_ROWS * GRID_COLS];
float totalW = (GRID_COLS - 1) * GRID_SP;
float totalH = (GRID_ROWS - 1) * GRID_SP;
float ox = -totalW / 2f;
float oz = -totalH / 2f;
int idx = 0;
for (int r = 0; r < GRID_ROWS; r++) {
for (int c = 0; c < GRID_COLS; c++) {
float x = ox + c * GRID_SP;
float z = oz + r * GRID_SP;
topGrid[idx++] = new PVector(x, GRID_Y, z);
}
}
}
void buildLayers() {
lay0 = new PVector[GRID_ROWS * GRID_COLS];
for (int i = 0; i < lay0.length; i++) {
PVector g = topGrid[i];
lay0[i] = new PVector(g.x, L0_Y, g.z);
}
lay1 = new PVector[3];
float left1 = -L1_SPAN_X/2f, right1 = L1_SPAN_X/2f;
for (int i = 0; i < 3; i++) {
float t = i / 2f;
lay1[i] = new PVector(lerp(left1, right1, t), L1_Y, 0);
}
lay2 = new PVector[2];
float left2 = -L2_SPAN_X/2f, right2 = L2_SPAN_X/2f;
for (int i = 0; i < 2; i++) {
float t = i / 1f;
lay2[i] = new PVector(lerp(left2, right2, t), L2_Y, 0);
}
}
void computeWeightMaxima() {
float mIH = 0;
for (int j = 0; j < 3; j++)
for (int i = 0; i < 16; i++)
mIH = max(mIH, abs(weights[0][j][i]));
maxW_IH = (mIH < 1e-6f) ? 1f : mIH;
float mHO = 0;
for (int k = 0; k < 2; k++)
for (int j = 0; j < 3; j++)
mHO = max(mHO, abs(weights[1][k][j]));
maxW_HO = (mHO < 1e-6f) ? 1f : mHO;
}
// ================= 描画(3D) =================
void drawTopGrid() {
int idx = 0;
for (int r = 0; r < GRID_ROWS; r++) {
for (int c = 0; c < GRID_COLS; c++) {
PVector p = topGrid[idx++];
boolean on = grid[r][c];
stroke(on ? 0xffFF3A3A : COL_DOT);
strokeWeight(on ? 3 : 2);
point(p.x, p.y, p.z);
}
}
}
void drawNodes(PVector[] nodes) {
noStroke();
fill(COL_NODE);
for (PVector p : nodes) {
pushMatrix();
translate(p.x, p.y, p.z);
sphereDetail(6);
sphere(NODE_R);
popMatrix();
}
}
void drawEdges_InputToHidden(float[] x) {
for (int j = 0; j < 3; j++) {
for (int i = 0; i < 16; i++) {
float w = weights[0][j][i];
float strength = abs(x[i] * w); // xは0/1
float sw = map(strength, 0, maxW_IH, LINE_W_MIN, LINE_W_MAX);
int col = (w >= 0) ? COL_LINE_POS : COL_LINE_NEG;
stroke(red(col), green(col), blue(col), LINE_ALPHA);
strokeWeight(sw);
PVector a = lay0[i], b = lay1[j];
line(a.x, a.y, a.z, b.x, b.y, b.z);
}
}
}
void drawEdges_HiddenToOutput(float[] h) {
for (int k = 0; k < 2; k++) {
for (int j = 0; j < 3; j++) {
float w = weights[1][k][j];
float strength = abs(h[j] * w); // h∈(0,1)
float sw = map(strength, 0, maxW_HO, LINE_W_MIN, LINE_W_MAX);
int col = (w >= 0) ? COL_LINE_POS : COL_LINE_NEG;
stroke(red(col), green(col), blue(col), LINE_ALPHA);
strokeWeight(sw);
PVector a = lay1[j], b = lay2[k];
line(a.x, a.y, a.z, b.x, b.y, b.z);
}
}
}
// 出力シンボル(3Dの○ と 3Dの×)
void drawOutputSymbols(float[] o) {
// o[0] → ○(トーラス)
float sO = map(constrain(o[0], 0, 1), 0, 1, O_SCALE_MIN, O_SCALE_MAX);
pushMatrix();
translate(lay2[0].x, lay2[0].y, lay2[0].z);
scale(sO);
noStroke();
fill(240, 40, 40);
drawTorus(O_MAJOR_R, O_TUBE_R, 42, 18);
popMatrix();
// o[1] → ×(交差する2本の棒)
float sX = map(constrain(o[1], 0, 1), 0, 1, X_SCALE_MIN, X_SCALE_MAX);
pushMatrix();
translate(lay2[1].x, lay2[1].y, lay2[1].z);
scale(sX);
noStroke();
fill(240, 40, 40);
pushMatrix(); rotateZ(radians(45)); box(X_BAR_LEN, X_BAR_THICK, X_BAR_THICK); popMatrix();
pushMatrix(); rotateZ(radians(-45)); box(X_BAR_LEN, X_BAR_THICK, X_BAR_THICK); popMatrix();
popMatrix();
}
// トーラス描画(R:大半径, r:チューブ半径, segR/segT:セグメント数)
void drawTorus(float R, float r, int segR, int segT) {
for (int i = 0; i < segR; i++) {
float u0 = TWO_PI * i / segR;
float u1 = TWO_PI * (i+1) / segR;
beginShape(QUAD_STRIP);
for (int j = 0; j <= segT; j++) {
float v = TWO_PI * j / segT;
float x1 = (R + r * cos(v)) * cos(u0);
float y1 = (R + r * cos(v)) * sin(u0);
float z1 = r * sin(v);
float x2 = (R + r * cos(v)) * cos(u1);
float y2 = (R + r * cos(v)) * sin(u1);
float z2 = r * sin(v);
vertex(x1, y1, z1);
vertex(x2, y2, z2);
}
endShape();
}
}
// ================= 入力パネル / HUD =================
void drawGridPanel() {
hint(DISABLE_DEPTH_TEST);
camera();
noLights();
// パネル枠
fill(255, 255, 255, 12);
stroke(COL_PANEL_BORDER);
rect(PANEL_X - 20, PANEL_Y - 50, 4*CELL + 3*GAP + 40, 4*CELL + 3*GAP + 140, 12);
fill(255);
textSize(16);
textAlign(LEFT, TOP);
text("4×4 入力(クリックでON/OFF)", PANEL_X - 8, PANEL_Y - 36);
// グリッド
for (int r = 0; r < GRID_ROWS; r++) {
for (int c = 0; c < GRID_COLS; c++) {
int x = PANEL_X + c*(CELL + GAP);
int y = PANEL_Y + r*(CELL + GAP);
boolean on = grid[r][c];
if (on) fill(35); else fill(240);
stroke(170);
rect(x, y, CELL, CELL, 10);
fill(on ? 255 : 90);
textAlign(CENTER, CENTER);
textSize(12);
int idx = r*GRID_COLS + c;
text("In(" + idx + ")", x + CELL/2, y + CELL/2);
}
}
// Clear ボタン
int bx = PANEL_X - 8, by = PANEL_Y + 4*(CELL + GAP) + 20, bw = 120, bh = 32;
fill(250); stroke(180); rect(bx, by, bw, bh, 6);
fill(0); textAlign(CENTER, CENTER); textSize(14); text("Clear [C]", bx + bw/2, by + bh/2);
hint(ENABLE_DEPTH_TEST);
}
void drawPrediction(float[] o) {
int label = (o[0] >= o[1]) ? 0 : 1; // 0:〇, 1:×
String verdict = (label == 0) ? "〇 (Maru)" : "× (Batsu)";
hint(DISABLE_DEPTH_TEST);
camera();
noLights();
fill(255);
textAlign(LEFT, TOP);
textSize(18);
int y0 = PANEL_Y + 4*(CELL + GAP) + 70;
text("判定: " + verdict, PANEL_X - 8, y0);
textSize(14);
text(String.format("o0(〇)=%.3f o1(×)=%.3f", o[0], o[1]), PANEL_X - 8, y0 + 26);
hint(ENABLE_DEPTH_TEST);
}
// ==== 置き換え版:AIくんを入力グリッドの「下」に配置 ====
void drawAIKunWithSpeech(float[] o) {
// 2D HUD座標系
hint(DISABLE_DEPTH_TEST);
camera();
noLights();
// 入力パネルの寸法
float panelContentW = 4*CELL + 3*GAP; // パネル内の正味幅
float panelBottomY = PANEL_Y + 4*(CELL + GAP); // グリッド最下端Y
// --- AIくんの位置(パネルの中央X、グリッドの下に余白をとって配置) ---
float headR = 36;
float ax = PANEL_X - panelContentW/2f; // 中央X
float ay = panelBottomY + headR + 60; // 下に60px余白
// 1) AIくん(棒人間:顔に「AI」)
noStroke();
fill(255);
ellipse(ax, ay, headR*2, headR*2); // 顔
stroke(60); strokeWeight(2); noFill();
ellipse(ax, ay, headR*2, headR*2); // 顔の縁
fill(30); textAlign(CENTER, CENTER); textSize(16);
text("AI", ax, ay);
// 体
stroke(220); strokeWeight(3);
line(ax, ay + headR, ax, ay + headR + 70); // 胴
line(ax, ay + headR + 20, ax - 28, ay + headR + 55); // 左腕
line(ax, ay + headR + 20, ax + 28, ay + headR + 55); // 右腕
line(ax, ay + headR + 70, ax - 24, ay + headR + 110);// 左脚
line(ax, ay + headR + 70, ax + 24, ay + headR + 110);// 右脚
// 2) 吹き出し(楕円):「これはXX%で(○/×)です。」
float p0 = o[0], p1 = o[1];
boolean isMaru = (p0 >= p1);
float p = max(p0, p1);
int percent = round(p * 100);
String symbol = isMaru ? "o" : "×";
String msg = String.format("This is a %s with %d%% probability", symbol, percent);
// 吹き出しを AIくんの「上」に出す(下に配置したので上方向に)
float bw = 280, bh = 95; // バブルの幅・高さ
float bx = ax; // 中央X
float by = ay - headR - 70; // 頭の少し上
// 楕円バブル
noStroke();
fill(255, 245);
ellipse(bx, by, bw, bh);
stroke(60); strokeWeight(2); noFill();
ellipse(bx, by, bw, bh);
// 尻尾(バブル右下→AIくんの口元へ)
float tailX = ax;
float tailY = ay - headR * 0.2f;
line(bx + bw*0.22f, by + bh*0.28f, tailX, tailY);
// 吹き出しテキスト
fill(0);
textAlign(CENTER, CENTER);
textSize(16);
text(msg, bx, by);
hint(ENABLE_DEPTH_TEST);
}
// ================= 入力操作 =================
void mousePressed() {
// グリッドクリックでON/OFF
for (int r = 0; r < GRID_ROWS; r++) {
for (int c = 0; c < GRID_COLS; c++) {
int x = PANEL_X + c*(CELL + GAP);
int y = PANEL_Y + r*(CELL + GAP);
if (mouseX >= x && mouseX <= x + CELL && mouseY >= y && mouseY <= y + CELL) {
grid[r][c] = !grid[r][c];
return;
}
}
}
// クリアボタン
int bx = PANEL_X - 8, by = PANEL_Y + 4*(CELL + GAP) + 20, bw = 120, bh = 32;
if (mouseX >= bx && mouseX <= bx + bw && mouseY >= by && mouseY <= by + bh) clearGrid();
}
void keyPressed() {
if (key == 'c' || key == 'C') clearGrid();
}
void clearGrid() {
for (int r = 0; r < GRID_ROWS; r++)
for (int c = 0; c < GRID_COLS; c++)
grid[r][c] = false;
}
// ================= ユーティリティ =================
float[] currentInputVector() {
float[] x = new float[16];
for (int r = 0; r < GRID_ROWS; r++)
for (int c = 0; c < GRID_COLS; c++)
x[r*GRID_COLS + c] = grid[r][c] ? 1f : 0f;
return x;
}
float sigmoid(float v) { return 1.0f / (1.0f + exp(-v)); }
実行すると、、

ヒストグラムあり版
// 4x4 -> 3 -> 2 3D NN Visualizer
// - 最上段:独立した4×4タッチ風グリッド(ONで赤点)
// 中段:16→3→2ネットワーク(回転、線太さ=活性×重み)
// 右:4×4入力ボタン(クリックON/OFF)
// 中央右:〇/×の横棒ヒストグラム(確率表示)
// Processing 4 / Java mode / P3D
// ====== レイアウト / 見た目 ======
final int CANVAS_W = 1280;
final int CANVAS_H = 900;
final int GRID_ROWS = 4, GRID_COLS = 4; // 入力は4x4=16
final float GRID_SP = 70; // 最上段グリッド点間隔
final float GRID_Y = -360; // 最上段グリッド高さ
final float L0_Y = -180f; // 入力(16)
final float L1_Y = -20f; // 隠れ(3)
final float L2_Y = 140f; // 出力(2)
final float L1_SPAN_X = 260; // 隠れの横幅
final float L2_SPAN_X = 150; // 出力の横幅
final float NODE_R = 4.0f; // ノード球半径
final boolean ADDITIVE_GLOW = true; // 加算合成で発光
final int COL_BG = 0xff0E0E10; // 背景
final int COL_DOT = 0xffE8E8E8; // 白点(最上段)
final int COL_NODE = 0xffC82828; // ノード
final int COL_LINE_POS = 0xffFF3A3A; // 正の重み(赤)
final int COL_LINE_NEG = 0xff2A6AFF; // 負の重み(青)
final int LINE_ALPHA = 85; // 線の透明度
final float LINE_W_MIN = 0.4f; // 線太さ min
final float LINE_W_MAX = 5.0f; // 線太さ max
// 出力シンボル(3D ○/× の代わりに今回は横棒ヒストグラムを追加)
final int BAR_AREA_X = 640; // ヒストグラム描画領域の開始X(3D原点からの相対ではなく2D HUDで描く)
final int BAR_AREA_Y = 160;
final int BAR_W_MAX = 280; // 横棒の最大幅
final int BAR_H = 22;
final int BAR_GAP = 16;
final int COL_BAR_BG = 0xff2A2A2E;
final int COL_BAR_O = 0xff38D973; // 〇 のバー色(緑寄り)
final int COL_BAR_X = 0xffFF6B6B; // × のバー色(赤寄り)
final int COL_TEXT = 0xffEDEDED;
// 右側 UI(入力パネル)
final int PANEL_X = 900, PANEL_Y = 120;
final int CELL = 80, GAP = 10;
final int COL_PANEL_BORDER = 0xffC8C8C8;
// ====== NN パラメータ(16->3->2:提供値) ======
float[][][] weights = new float[][][] {
{ // 入力(16) -> 隠れ(3)
{
-0.19556837184815432, -2.0731887662694675, -0.7652514121341945, -1.9884231323546566,
-4.952637298076189, 5.659829256271411, -0.5713695038053532, -1.4846930025289022,
-1.4970230006948473, 2.5726393101553975, -0.2504789124544582, 1.480466604318017,
-0.8298236501477579, -4.5199641859013955, -1.4981634293951982, 2.011290351680955
},
{
-3.4835715114090715, 5.010347806892839, 2.9247242936422113, -4.194203236742492,
-0.17924275715765517, -2.403425422788088, 0.40385725801892475, 1.8787273651616636,
2.047521825332689, -0.16374517197602814, 0.47853555594913116, 5.6545162920862575,
-6.058153846339116, 0.42470424485595815,-0.8371742892189643, -2.879606740652077
},
{
2.884860808289696, 0.23975579237277614,-1.2403687366139762, -2.3025676808322486,
-0.7475210018222626, -6.5294340577398575, -0.559934356147751, 4.0010381968700575,
5.0747200536885, -4.225817417542366, 0.3105588568588239, 3.308254461438346,
4.348740489196476, 1.5652833651727298, -4.873553428254676, -1.3786319596139733
}
},
{ // 隠れ(3) -> 出力(2)
{ -8.832622109783433, 8.303120604609045, -6.0039452831036275 },
{ 8.827857967700506, -8.306736033721686, 6.003293693110446 }
}
};
float[][] biases = new float[][] {
{ 6.286020903686753, 3.2317338139016565, 2.8075640195084577 }, // 隠れ
{ 2.626446601080335, -2.618405339273877 } // 出力
};
// ====== 内部ワーク ======
PVector[] topGrid; // 最上段 4x4 白点(独立の“タッチ面”)
PVector[] lay0; // 入力(16)
PVector[] lay1; // 隠れ(3)
PVector[] lay2; // 出力(2)
boolean[][] grid = new boolean[GRID_ROWS][GRID_COLS]; // 入力パネル(0/1)
float angleY = 0, angleX = 0;
// 正規化用:|activation*weight| の最大想定
float maxW_IH = 1f; // 入力->隠れ
float maxW_HO = 1f; // 隠れ->出力
void settings() {
size(CANVAS_W, CANVAS_H, P3D);
smooth(8);
}
void setup() {
surface.setTitle("4x4 -> 3 -> 2 : top touch-like grid + bars (○/×)");
buildTopGrid();
buildLayers();
clearGrid();
computeWeightMaxima();
}
void draw() {
background(COL_BG);
lights();
// ==== 左:3Dビジュアライズ ====
float[] o; // 出力
{
pushMatrix();
translate(width*0.30f, height*0.56f, 0);
// ゆっくり回転(3D感)
rotateY(angleY);
rotateX(angleX);
angleY += 0.005;
angleX += 0;
// 最上段 4x4 タッチ風グリッド(ONで赤)
drawTopGrid(); // ←ネットワーク非接続の“見た目面”
// 入力ベクトル x(0/1)— 右パネルのON/OFFが反映
float[] x = currentInputVector();
// 前向き計算(sigmoid)
float[] h = new float[3];
for (int j = 0; j < 3; j++) {
float s = 0;
for (int i = 0; i < 16; i++) s += weights[0][j][i] * x[i];
s += biases[0][j];
h[j] = sigmoid(s);
}
o = new float[2];
for (int k = 0; k < 2; k++) {
float s = 0;
for (int j = 0; j < 3; j++) s += weights[1][k][j] * h[j];
s += biases[1][k];
o[k] = sigmoid(s);
}
// 線の描画:太さ ∝ |activation * weight|
if (ADDITIVE_GLOW) blendMode(ADD);
drawEdges_InputToHidden(x);
drawEdges_HiddenToOutput(h);
blendMode(BLEND);
// ノード
drawNodes(lay0);
drawNodes(lay1);
drawNodes(lay2);
popMatrix();
}
// ==== 中央右:2D横棒ヒストグラム(○/×) ====
drawBars(o);
// ==== 右:入力パネル(クリックON/OFF) ====
drawGridPanel();
}
// ================= 構築 =================
void buildTopGrid() {
topGrid = new PVector[GRID_ROWS * GRID_COLS];
float totalW = (GRID_COLS - 1) * GRID_SP;
float totalH = (GRID_ROWS - 1) * GRID_SP;
float ox = -totalW / 2f;
float oz = -totalH / 2f;
int idx = 0;
for (int r = 0; r < GRID_ROWS; r++) {
for (int c = 0; c < GRID_COLS; c++) {
float x = ox + c * GRID_SP;
float z = oz + r * GRID_SP;
topGrid[idx++] = new PVector(x, GRID_Y, z);
}
}
}
void buildLayers() {
// 入力(16):最上段グリッドと同じ x,z に“少し下”へ配置
lay0 = new PVector[GRID_ROWS * GRID_COLS];
for (int i = 0; i < lay0.length; i++) {
PVector g = topGrid[i];
lay0[i] = new PVector(g.x, L0_Y, g.z);
}
// 隠れ(3)
lay1 = new PVector[3];
float left1 = -L1_SPAN_X/2f, right1 = L1_SPAN_X/2f;
for (int i = 0; i < 3; i++) {
float t = i / 2f;
lay1[i] = new PVector(lerp(left1, right1, t), L1_Y, 0);
}
// 出力(2)
lay2 = new PVector[2];
float left2 = -L2_SPAN_X/2f, right2 = L2_SPAN_X/2f;
for (int i = 0; i < 2; i++) {
float t = i / 1f;
lay2[i] = new PVector(lerp(left2, right2, t), L2_Y, 0);
}
}
void computeWeightMaxima() {
float mIH = 0;
for (int j = 0; j < 3; j++)
for (int i = 0; i < 16; i++)
mIH = max(mIH, abs(weights[0][j][i]));
maxW_IH = (mIH < 1e-6f) ? 1f : mIH;
float mHO = 0;
for (int k = 0; k < 2; k++)
for (int j = 0; j < 3; j++)
mHO = max(mHO, abs(weights[1][k][j]));
maxW_HO = (mHO < 1e-6f) ? 1f : mHO;
}
// ================= 描画(3D) =================
void drawTopGrid() {
// 右パネルの状態(grid[][])をミラーして、ONセルだけ赤点に
int idx = 0;
for (int r = 0; r < GRID_ROWS; r++) {
for (int c = 0; c < GRID_COLS; c++) {
PVector p = topGrid[idx++];
boolean on = grid[r][c];
stroke(on ? 0xffFF3A3A : COL_DOT);
strokeWeight(on ? 3 : 2);
point(p.x, p.y, p.z);
}
}
}
void drawNodes(PVector[] nodes) {
noStroke();
fill(COL_NODE);
for (PVector p : nodes) {
pushMatrix();
translate(p.x, p.y, p.z);
sphereDetail(6);
sphere(NODE_R);
popMatrix();
}
}
void drawEdges_InputToHidden(float[] x) {
for (int j = 0; j < 3; j++) {
for (int i = 0; i < 16; i++) {
float w = weights[0][j][i];
float strength = abs(x[i] * w); // xは0/1
float sw = map(strength, 0, maxW_IH, LINE_W_MIN, LINE_W_MAX);
int col = (w >= 0) ? COL_LINE_POS : COL_LINE_NEG;
stroke(red(col), green(col), blue(col), LINE_ALPHA);
strokeWeight(sw);
PVector a = lay0[i], b = lay1[j];
line(a.x, a.y, a.z, b.x, b.y, b.z);
}
}
}
void drawEdges_HiddenToOutput(float[] h) {
for (int k = 0; k < 2; k++) {
for (int j = 0; j < 3; j++) {
float w = weights[1][k][j];
float strength = abs(h[j] * w); // h∈(0,1)
float sw = map(strength, 0, maxW_HO, LINE_W_MIN, LINE_W_MAX);
int col = (w >= 0) ? COL_LINE_POS : COL_LINE_NEG;
stroke(red(col), green(col), blue(col), LINE_ALPHA);
strokeWeight(sw);
PVector a = lay1[j], b = lay2[k];
line(a.x, a.y, a.z, b.x, b.y, b.z);
}
}
}
// ================= 2D 横棒ヒストグラム(○/×) =================
void drawBars(float[] o) {
// 2D HUD(画面座標)で描画
hint(DISABLE_DEPTH_TEST);
camera();
noLights();
// 背景パネル
fill(255, 255, 255, 12);
stroke(140);
rect(BAR_AREA_X, BAR_AREA_Y - 50, BAR_W_MAX + 160, BAR_H*2 + BAR_GAP + 120, 12);
// タイトル
fill(COL_TEXT);
textAlign(LEFT, TOP);
textSize(16);
text("〇 / × の確率(横棒)", BAR_AREA_X + 10, BAR_AREA_Y - 36);
// 値
float pO = constrain(o[0], 0, 1);
float pX = constrain(o[1], 0, 1);
// 1本目(○)
int x0 = BAR_AREA_X + 20;
int y0 = BAR_AREA_Y;
fill(COL_BAR_BG); noStroke();
rect(x0, y0, BAR_W_MAX, BAR_H, 6);
fill(COL_BAR_O);
rect(x0, y0, BAR_W_MAX * pO, BAR_H, 6);
// 2本目(×)
int y1 = y0 + BAR_H + BAR_GAP;
fill(COL_BAR_BG);
rect(x0, y1, BAR_W_MAX, BAR_H, 6);
fill(COL_BAR_X);
rect(x0, y1, BAR_W_MAX * pX, BAR_H, 6);
// ラベル&数値
fill(COL_TEXT);
textAlign(LEFT, CENTER);
textSize(14);
text("〇", x0 - 20, y0 + BAR_H/2f);
text("×", x0 - 20, y1 + BAR_H/2f);
textAlign(LEFT, CENTER);
text(nf(pO*100, 0, 1) + "%", x0 + BAR_W_MAX + 10, y0 + BAR_H/2f);
text(nf(pX*100, 0, 1) + "%", x0 + BAR_W_MAX + 10, y1 + BAR_H/2f);
hint(ENABLE_DEPTH_TEST);
}
// ================= 右側:入力パネル(ローカル操作) =================
void drawGridPanel() {
hint(DISABLE_DEPTH_TEST);
camera();
noLights();
// パネル枠
fill(255, 255, 255, 12);
stroke(COL_PANEL_BORDER);
rect(PANEL_X - 20, PANEL_Y - 50, 4*CELL + 3*GAP + 40, 4*CELL + 3*GAP + 140, 12);
fill(255);
textSize(16);
textAlign(LEFT, TOP);
text("4×4 入力(クリックでON/OFF)", PANEL_X - 8, PANEL_Y - 36);
// グリッド
for (int r = 0; r < GRID_ROWS; r++) {
for (int c = 0; c < GRID_COLS; c++) {
int x = PANEL_X + c*(CELL + GAP);
int y = PANEL_Y + r*(CELL + GAP);
boolean on = grid[r][c];
if (on) fill(35); else fill(240);
stroke(170);
rect(x, y, CELL, CELL, 10);
fill(on ? 255 : 90);
textAlign(CENTER, CENTER);
textSize(12);
int idx = r*GRID_COLS + c;
text("In(" + idx + ")", x + CELL/2, y + CELL/2);
}
}
// Clear ボタン
int bx = PANEL_X - 8, by = PANEL_Y + 4*(CELL + GAP) + 20, bw = 120, bh = 32;
fill(250); stroke(180); rect(bx, by, bw, bh, 6);
fill(0); textAlign(CENTER, CENTER); textSize(14); text("Clear [C]", bx + bw/2, by + bh/2);
hint(ENABLE_DEPTH_TEST);
}
// ================= 入力操作 =================
void mousePressed() {
// グリッドクリックでON/OFF
for (int r = 0; r < GRID_ROWS; r++) {
for (int c = 0; c < GRID_COLS; c++) {
int x = PANEL_X + c*(CELL + GAP);
int y = PANEL_Y + r*(CELL + GAP);
if (mouseX >= x && mouseX <= x + CELL && mouseY >= y && mouseY <= y + CELL) {
grid[r][c] = !grid[r][c];
return;
}
}
}
// クリアボタン
int bx = PANEL_X - 8, by = PANEL_Y + 4*(CELL + GAP) + 20, bw = 120, bh = 32;
if (mouseX >= bx && mouseX <= bx + bw && mouseY >= by && mouseY <= by + bh) clearGrid();
}
void keyPressed() {
if (key == 'c' || key == 'C') clearGrid();
}
void clearGrid() {
for (int r = 0; r < GRID_ROWS; r++)
for (int c = 0; c < GRID_COLS; c++)
grid[r][c] = false;
}
// ================= ユーティリティ =================
float[] currentInputVector() {
float[] x = new float[16];
for (int r = 0; r < GRID_ROWS; r++)
for (int c = 0; c < GRID_COLS; c++)
x[r*GRID_COLS + c] = grid[r][c] ? 1f : 0f;
return x;
}
float sigmoid(float v) { return 1.0f / (1.0f + exp(-v)); }
ノード数16→3→2、4×4の入力パネルで入力をし、まるばつ判定をするニューラルネットワークの可視化に成功した。だが実際はもっとぬるぬる動くようなプログラムを書きたい。だが、実力が足りない、、
こんな感じで作成してみたがまだまだわからないことばかりだ。
現在大学4年生。社会人まで残り半年だが、有意義な研究をしたい。
この夏はprocessingでできることを学びつつ、図形の作成をしていきたい。
Discussion