Remove context33.training.dat loading (and read_armadillo import). Training data is now a hardcoded 20-character sentence encoded with the same 40-char vocabulary as moby_rnn.ipynb (space .!? A-Z 0-9). SENTENCE = "MOBY DICK IS A WHALE" Results: 95% reconstruction, 95% next-step prediction (one miss each on the first character where context is zero). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
604 lines
81 KiB
Plaintext
604 lines
81 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "c33-0001",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:22:40.037058385Z",
|
|
"start_time": "2026-05-31T13:22:39.555320188Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:29:00.778448Z",
|
|
"iopub.status.busy": "2026-05-31T13:29:00.778275Z",
|
|
"iopub.status.idle": "2026-05-31T13:29:01.662542Z",
|
|
"shell.execute_reply": "2026-05-31T13:29:01.661652Z"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# context33.prj → pyRBM\n",
|
|
"#\n",
|
|
"# Architecture: shared-weights StackRnn (1 entity, reused every time step)\n",
|
|
"# visible = [context(128) | x_t(40)] = 168 hidden = 128\n",
|
|
"#\n",
|
|
"# All hyperparameters taken verbatim from context33.prj.\n",
|
|
"# Training data: 20-character sentence, encoded with the moby vocabulary.\n",
|
|
"\n",
|
|
"import numpy as np_cpu\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"from rbm.stack_rnn import StackRnn\n",
|
|
"from rbm.matrix import np, convert\n",
|
|
"from rbm.entity import EntityParams, TrainingParams\n",
|
|
"from rbm.status import CheckpointStatus"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "c33-0002",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:22:40.085346225Z",
|
|
"start_time": "2026-05-31T13:22:40.037788851Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:29:01.664498Z",
|
|
"iopub.status.busy": "2026-05-31T13:29:01.664260Z",
|
|
"iopub.status.idle": "2026-05-31T13:29:01.669057Z",
|
|
"shell.execute_reply": "2026-05-31T13:29:01.668207Z"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# ── Config from context33.prj ──────────────────────────────────────────────\n",
|
|
"SENSORY_SIZE = 40 # numVisibleX * numVisibleY = 1 * 40\n",
|
|
"CONTEXT_SIZE = 128 # numContext = numHidden\n",
|
|
"LEARNING_RATE = 0.05 # learningRate\n",
|
|
"MOMENTUM = 0.5 # momentum\n",
|
|
"NUM_EPOCHS = 1000 # numEpochs\n",
|
|
"MINI_BATCH = 100 # miniBatchSize\n",
|
|
"NUM_GIBBS = 3 # numGibbs\n",
|
|
"RAO_BLACKWELL = True # doRaoBlackwell\n",
|
|
"L2_LAMBDA = 0.0 # weightDecay\n",
|
|
"PRJ_NAME = \"context33\"\n",
|
|
"WORK_DIR = \"results\"\n",
|
|
"\n",
|
|
"# Vocabulary (40 chars, matching numVisibleY=40 in context33.prj)\n",
|
|
"# Same encoding as moby_rnn.ipynb\n",
|
|
"ALLOWED = set(' .!?ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')\n",
|
|
"chars = sorted(ALLOWED)\n",
|
|
"idx_to_char = {i: c for i, c in enumerate(chars)}\n",
|
|
"char_to_idx = {c: i for i, c in enumerate(chars)}"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "c33-0003",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:22:40.144967589Z",
|
|
"start_time": "2026-05-31T13:22:40.086400874Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:29:01.670536Z",
|
|
"iopub.status.busy": "2026-05-31T13:29:01.670381Z",
|
|
"iopub.status.idle": "2026-05-31T13:29:01.674395Z",
|
|
"shell.execute_reply": "2026-05-31T13:29:01.673713Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Sentence : 'MOBY DICK IS A WHALE' (20 chars)\n",
|
|
"Vocab : ' !.0123456789?ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# ── Training sentence ──────────────────────────────────────────────────────\n",
|
|
"SENTENCE = \"MOBY DICK IS A WHALE\" # exactly 20 chars, all in vocab\n",
|
|
"N_SAMPLES = len(SENTENCE)\n",
|
|
"\n",
|
|
"sensory_np = np_cpu.zeros((N_SAMPLES, SENSORY_SIZE), dtype=np_cpu.float64)\n",
|
|
"for i, c in enumerate(SENTENCE):\n",
|
|
" sensory_np[i, char_to_idx[c]] = 1.0\n",
|
|
"\n",
|
|
"decoded = SENTENCE\n",
|
|
"print(f\"Sentence : '{decoded}' ({N_SAMPLES} chars)\")\n",
|
|
"print(f\"Vocab : {repr(''.join(chars))}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "c33-0004",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:22:40.520281036Z",
|
|
"start_time": "2026-05-31T13:22:40.145738296Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:29:01.675959Z",
|
|
"iopub.status.busy": "2026-05-31T13:29:01.675735Z",
|
|
"iopub.status.idle": "2026-05-31T13:29:01.924860Z",
|
|
"shell.execute_reply": "2026-05-31T13:29:01.923856Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAABOUAAAEiCAYAAAC2imYsAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAXGhJREFUeJzt3XdcleX/x/H3OSCgMl3gQMCRoxylaWgOFEMzR1m5cqDl18JJfUtb2NS0/FFqmuWqXJVlfkvtayiapuZOc5TbUnALooLC/fvDOF9PHA8cBI7A6+njfuS5ruu+7s99VvDxGibDMAwBAAAAAAAAKDBmZwcAAAAAAAAAFDck5QAAAAAAAIACRlIOAAAAAAAAKGAk5QAAAAAAAIACRlIOAAAAAAAAKGAk5QAAAAAAAIACRlIOAAAAAAAAKGAk5QAAAAAAAIACRlIOAAAAAAAAKGAk5QAARVpwcLAeeughZ4dR6IwZM0Ymk8mqLDg4WP3793dOQAAAAEARQ1IOAJAnfvvtNz3xxBOqXLmy3N3dValSJfXu3Vu//fabs0PLU8ePH9eYMWO0fft2Z4dS7MXHx8tkMunw4cM6fPiwTCaT4uPjLfWZiUWz2axjx45lOT8pKUklS5aUyWTSkCFDstSfOXNG//73v1WrVi15eHioTJkyioiI0HfffZelbeb1bzy8vb3VsGFDTZ48Wenp6Tp//rwqVqyo5s2byzCMLH1s2LBBZrNZ//73v7O958zD3d1d/v7+at26td5++22dOnUqyzmzZ8+WyWTS5s2bs9Rt375dTzzxhAIDA+Xu7q4yZcooPDxcs2bNUnp6uqXdzZ6jt99+WyaTSQMGDFBGRsZN47aVHL948aJiYmJ01113qXTp0ipbtqwaNmyo4cOH6/jx4zft65+WLl0qk8mkSpUq2Y3hRs8884zMZrPOnj1rVX727FmZzWa5u7vrypUrVnUHDx6UyWTSiy++KOl/r/m7775r8xqZ77/Tp0/brH/88cdlMpn0wgsv2KzPfK2/+uoru/fyz/fdjcfgwYMt7fr376/WrVtbYgsODrbbLwAAyH+uzg4AAFD4ff311+rZs6fKlCmjgQMHKiQkRIcPH9aMGTP01VdfacGCBXr44YedHWaeOH78uF577TUFBwerYcOGzg6nQO3bt09mc+H79zx3d3fNnz9fzz//vFX5119/fdNz9u3bp7Zt2+rUqVOKjIxU48aNdf78ec2dO1edOnXSc889pwkTJmQ5r2fPnnrwwQclSRcuXNDSpUs1dOhQHTlyRBMmTFBsbKx69Oihjz/+WIMGDbKcd+3aNQ0ePFhBQUF67bXXsr2nYcOG6d5771V6erpOnTqln3/+WTExMZo4caK++OILtWnTJts+PvnkEw0ePFj+/v7q06ePatasqeTkZMXFxWngwIE6ceKEJQFly7hx4/TSSy+pX79++uSTTxx6b1y9elUtW7bU3r171a9fPw0dOlQXL17Ub7/9pnnz5unhhx9WpUqVctTX3LlzFRwcrMOHD2vlypUKDw/P9pz7779fU6dO1bp169SpUydL+c8//yyz2ayrV69q8+bNuv/++y1169ats5x7q5KSkvSf//xHwcHBmj9/vsaNG5dlZKoj2rVrp759+2Ypv+OOO24lTAAAkM9IygEAbsmBAwfUp08fVatWTWvWrFH58uUtdcOHD1eLFi3Up08f/frrr6pWrZoTI8Wtcnd3d3YIufLggw/aTMrNmzdPHTt21KJFi6zKr169qkcffVTnzp3TmjVr1LRpU0vdyJEj1bt3b7377rtq3LixunfvbnXuPffcoyeeeMLy+JlnnlHTpk01b948TZgwQd27d9ecOXM0atQodenSRf7+/pKk999/Xzt27NDSpUtVqlSpbO+pRYsWevTRR63KduzYoQceeEDdunXT7t27VbFixZuev2HDBg0ePFihoaFaunSpvLy8LHUjRozQ5s2btWvXrpueP2HCBI0ePVp9+/bVzJkzHU7WLl68WNu2bdPcuXPVq1cvq7orV64oLS0tR/2kpKTo22+/1dixYzVr1izNnTs3x0k5SVq7dq1VUm7dunWqX7++Ll++rLVr11ol4NauXSuz2axmzZrlKDZ7Fi1apPT0dM2cOVNt2rTRmjVr1KpVq1z3d8cdd1i97wAAQOFQ+P65GwBwW5kwYYIuXbqk6dOnWyXkJKlcuXL66KOPlJKSovHjx1vKM6d17d+/X/3795evr698fHwUGRmpS5cuZbnG559/rkaNGqlkyZIqU6aMevToYXM6oj1r165VkyZN5OHhoWrVqunTTz/N0ubgwYN67LHHVKZMGZUqVUr33Xefvv/+e0t9fHy87r33XklSZGSkZYrY7Nmz7V77r7/+0oABA+Tv7y93d3fdeeedmjlzplWbzKlqX3zxhd566y1VqVJFHh4eatu2rfbv35+lz40bN+rBBx+Un5+fSpcurfr16+v999+3arNy5Uq1aNFCpUuXlq+vr7p06aI9e/bYfG7uvfdeeXh4qHr16vroo49s3sc/15TLnBa5bt06RUdHq3z58ipdurQefvjhLNMoMzIyNGbMGFWqVEmlSpVSWFiYdu/ebXOdugMHDujAgQP2nlKH9OrVS9u3b9fevXstZQkJCVq5cmWWhJB0PWGya9cujRo1yiohJ0kuLi766KOP5OvrqzFjxmR7bZPJJH9/f7m6/u/fQT/88EOlpqYqOjpaknTs2DGNGTNG3bt3V4cOHXJ5l1KDBg0UGxur8+fPa/LkyXbbvvbaazKZTJo7d65VQi5T48aNb7p+4MSJE/X888/riSee0KxZs3I1ejLz9W3evHmWOg8PD3l7e+eon2+++UaXL1/WY489ph49eujrr7/OMu3UlqpVqyowMNAy+i3TunXr1Lx5czVr1sxm3Z133ilfX98cxWbP3Llz1a5dO4WFhalOnTqaO3fuLfcJAAAKH5JyAIBbkjkFq0WLFjbrW7ZsqeDgYKvkVqbHH39cycnJGjt2rB5//HHNnj07y9S9t956S3379lXNmjU1ceJEjRgxQnFxcWrZsqXOnz+foxj379+vRx99VO3atdN7770nPz8/9e/f32q9u8TERDVr1kw//PCDnnnmGb311lu6cuWKOnfurG+++UaSVKdOHb3++uuSpEGDBumzzz7TZ599ppYtW9702omJibrvvvv0448/asiQIXr//fdVo0YNDRw4ULGxsVnajxs3Tt98842ee+45jR49Whs2bFDv3r2t2qxYsUItW7bU7t27NXz4cL333nsKCwuzWuvsxx9/VEREhE6ePKkxY8YoOjpaP//8s5o3b67Dhw9b2u3cuVMPPPCApV1kZKRiYmIs95wTQ4cO1Y4dOxQTE6Onn35a//nPf7KsPzZ69Gi99tpraty4sSZMmKCaNWsqIiJCKSkpWfpr27at2rZtm+PrZ6dly5aqUqWK5s2bZylbuHChPD091bFjxyzt//Of/0iSzemAkuTj46MuXbpo7969WRKmly5d0unTp3X69GkdPHhQU6ZM0fLly9WvXz9Lm+DgYL322muaN2+eVqxYoWHDhsnV1dXm+8FRjz76qEqWLKn//ve/N21z6dIly2eoatWqDvX//vvv69lnn1WvXr00e/bsXE9nDgoKkiR9+umnNtfXy6m5c+cqLCxMAQEB6tGjh5KTky2vX3buv/9+bd68WampqZKktLQ0bdq0Sc2aNVOzZs30888/W2I7d+6cdu/ebXPq6o2v+Y2HrX9gkK5PgV+1apV69uwp6fqU56+++irHowNtuXLlis0YbqVPAABQAAwAAHLp/PnzhiSjS5cudtt17tzZkGQkJSUZhmEYMTExhiRjwIABVu0efvhho2zZspbHhw8fNlxcXIy33nrLqt3OnTsNV1fXLOW2BAUFGZKMNWvWWMpOnjxpuLu7G88++6ylbMSIEYYk46effrKUJScnGyEhIUZwcLCRnp5uGIZhbNq0yZBkzJo1K9trG4ZhDBw40KhYsaJx+vRpq/IePXoYPj4+xqVLlwzDMIxVq1YZkow6deoYqamplnbvv/++IcnYuXOnYRiGce3aNSMkJMQICgoyzp07Z9VnRkaG5e8NGzY0KlSoYJw5c8ZStmPHDsNsNht9+/a1lHXt2tXw8PAwjhw5YinbvXu34eLiYvzzx4SgoCCjX79+lsezZs0yJBnh4eFW1x45cqTh4uJinD9/3jAMw0hISDBcXV2Nrl27WvU3ZswYQ5JVn5nXCQoKMm5V5vvs1KlTxnPPPWfUqFHDUnfvvfcakZGRhmEYhiQjKirKUtewYUPDx8fHbt8TJ040JBlLliwxDMMwDh06ZEiyeTz99NNWz49hGMbVq1eNhg0bGmXKlDEkGR999FGO7inzffLll1/etE2DBg0MPz8/y+PM12nTpk2GYVx/H0gyhg8fnqNrGsb15yjzs9SzZ0/j2rVrOT7XMK6/ph07drQ8vnTpklGrVi1Lv/379zdmzJhhJCYm5rjPxMREw9XV1fj4448tZc2aNcv2+yjTlClTrD7z69evNyQZR44cMXbv3m1IMn777TfDMAzju+++MyQZc+fOtZxv7zW/8Th16pTVdd99912jZMmSlu/D33//3ZBkfPPNN1btcvJaG4Zh99rz58/P0XMBAACcg5FyAIBcS05OliSb099ulFmflJRkVX7jzoDS9XWyzpw5Y2n39ddfKyMjQ48//rjV6I+AgADVrFlTq1atylGcdevWtRrJV758edWqVUsHDx60lC1dulRNmjSxGgnj6empQYMG6fDhw9q9e3eOrnUjwzC0aNEiderUSYZhWN1DRESELly4oK1bt1qdExkZKTc3N6vnRJIl1m3btunQoUMaMWJElml0mQvFnzhxQtu3b1f//v1VpkwZS339+vXVrl07LV26VJKUnp6uH374QV27drUaMVWnTh1FRETk+D4HDRpktUh9ixYtlJ6eriNHjkiS4uLidO3aNT3zzDNW5w0dOtRmf5m7qealXr16af/+/dq0aZPlv7amrkrX39e5fU8PGjRIK1as0IoVK7Ro0SJFRUXpo48+skxVzeTq6qrp06fr7Nmzuu+++/TUU0/dwt1Z8/T0tHw2bcmMObt7/KfExERJUkhIiFxcXHIfoKSSJUtq48aNlp1mZ8+erYEDB6pixYoaOnSoZfSaPQsWLJDZbFa3bt0sZT179tSyZct07ty5bM+/cV056fr01MqVK6tq1aqqXbu2ypQpY5nCam+Thxtf8xuPPn362Lzu3Llz1bFjR8vzX7NmTTVq1OiWprB26dLFZgxhYWG57hMAAOQ/NnoAAORa5i+V9hIAN9b/Mwnwz6lzfn5+kq5PFfP29tYff/whwzBUs2ZNm/2WKFFCknTx4kVdvHjRUu7i4mK1vp2tKXp+fn5Wv7gfOXIky/ph0vUEVWb9XXfddfObtOHUqVM6f/68pk+frunTp9tsc/LkSavH9p4T6X9rcdmLJTMZVqtWrSx1derU0Q8//KCUlBQlJyfr8uXLNp/fWrVqWZJ32cku5sx4atSoYdWuTJkylrb57e6771bt2rU1b948+fr6KiAg4KY7lHp5een06dN2+7vZe7pmzZpWGw088sgjMplMio2N1YABA1SvXj1LXeb6hI0aNbqlnTf/6eLFi3YTbpnrtWX3uf2nfv366fjx43r77bdVrlw5jRw58pbi9PHx0fjx4zV+/HgdOXJEcXFxevfddzV58mT5+PjozTfftHv+559/riZNmujMmTM6c+aMpOuvc1pamr788kur3W1tueuuu+Tr62uVeMtc485kMik0NFTr1q3TU089pXXr1ikwMNDmd8k/X/NMmcm+G+3Zs0fbtm1T3759raY+t27dWlOmTFFSUlKO19O7UZUqVXK0wQUAALi9kJQDAOSaj4+PKlasqF9//dVuu19//VWVK1fO8svmzUbbGH+v45SRkSGTyaRly5bZbOvp6SlJevfdd63WogsKCrIaaZXddfJLRkaGJOmJJ56wWlPsRvXr17d67KxYb0VhiblXr16aOnWqvLy81L1795uuh1anTh1t375dR48evemaa5nv+bp162Z73bZt22ry5Mlas2aNVVIuP1y9elW///673aRtjRo15Orqqp07dzrUt6urq7744gu1b99ezz77rHx9fRUZGXmrIUu6/pkdMGCAHn74YVWrVk1z5861m5T7448/tGnTJkmymVSeO3dutkk5s9ms0NBQy9px69at04svvmipb9asmWbOnGlZa65r1665u7kbfP7555Ku7+JrK6m5aNGiPHtOAQDA7Y+kHADgljz00EP6+OOPtXbtWptTu3766ScdPnxY//rXvxzuu3r16jIMQyEhIbrjjjtu2q5v375W1y5ZsqTD1woKCtK+ffuylGfu2Jm5ML0jI5rKly8vLy8vpaen59kolurVq0uSdu3addM+M2O92f2UK1dOpUuXloeHh0qWLKk//vgjSztb5+ZWZjz79+9XSEiIpfzMmTM5mmaYV3r16qVXX31VJ06c0GeffXbTdg899JDmz5+vTz/9VC+//HKW+qSkJH377beqXbt2ltF/tly7dk2SrEZz5pevvvpKly9ftjv9uFSpUmrTpo1WrlypY8eOKTAwMMf9e3h4aMmSJQoLC9NTTz0lX19fPfzww3kRuqTroyyrV6+uXbt22W03d+5clShRQp999lmWpPDatWv1wQcf2E2qZrr//vu1bNkyLVmyRCdPnrTaDbZZs2Z66aWXtHTpUl2+fNnm95sjDMPQvHnzFBYWlmUqtyS98cYbmjt3Lkk5AACKEdaUAwDckn//+98qWbKk/vWvf1mmkGU6e/asBg8erFKlSlnWjnLEI488IhcXF7322mtZRl0ZhmG5XrVq1RQeHm45bvzFOqcefPBB/fLLL1q/fr2lLCUlRdOnT1dwcLBlRFTp0qUlKUc7v7q4uKhbt25atGiRzSTDqVOnHI7znnvuUUhIiGJjY7PEkPkcVaxYUQ0bNtScOXOs2uzatUv//e9/9eCDD1rii4iI0OLFi3X06FFLuz179uiHH35wOLabadu2rVxdXTV16lSr8smTJ9tsf+DAAcs03bxUvXp1xcbGauzYsWrSpMlN2z366KOqW7euxo0bp82bN1vVZWRk6Omnn9a5c+cUExOTo+tm7gbaoEGD3AefAzt27NCIESPk5+enqKgou21j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3S6CgoIkSZcuXdLRo0eVlpZmVV+/fn2H+8xRUu7//u//5OXlJUmKjY11+CIAAAAAAAAonkwm+xs9FIKcnE6dOqXIyEgtW7bMZn16errDfeYoKdevXz+bfwcAAAAAAADsMZtNMttZN85e3e1ixIgROn/+vDZu3KjWrVvrm2++UWJiot5880299957ueqTNeUAAAAAAACQb4rC9NWVK1fq22+/VePGjWU2mxUUFKR27drJ29tbY8eOVceOHR3uM+9Wp8uFsWPH6t5775WXl5cqVKigrl27at++fVZtrly5oqioKJUtW1aenp7q1q2bEhMTnRQxAAAAAAAAHJE5fdXecbtLSUlRhQoVJEl+fn46deqUJKlevXraunVrrvp0alJu9erVioqK0oYNG7RixQpdvXpVDzzwgFJSUixtRo4cqf/85z/68ssvtXr1ah0/flyPPPKIE6MGAAAAAABATplMpmyP212tWrUsA8kaNGigjz76SH/99ZemTZumihUr5qpPp05fXb58udXj2bNnq0KFCtqyZYtatmypCxcuaMaMGZo3b57atGkjSZo1a5bq1KmjDRs26L777nNG2AAAAAAAAMghF5NJLnYSb/bqbhfDhw/XiRMnJEkxMTFq37695s6dKzc3N82ePTtXfd5SUu7YsWOSpMDAwFvpxuLChQuSpDJlykiStmzZoqtXryo8PNzSpnbt2qpatarWr19vMymXmpqq1NRUy+OkpKQ8iQ0AAAAAAACOM5kke3s5FIKcnJ544gnL3xs1aqQjR45o7969qlq1qsqVK5erPh2evnrt2jW98sor8vHxUXBwsIKDg+Xj46OXX35ZV69ezVUQkpSRkaERI0aoefPmuuuuuyRJCQkJcnNzk6+vr1Vbf39/JSQk2Oxn7Nix8vHxsRx5lTAEAAAAAACA48ym7I/b3dq1a60elypVSvfcc0+uE3JSLpJyQ4cO1fTp0zV+/Hht27ZN27Zt0/jx4zVjxgwNGzYs14FERUVp165dWrBgQa77kKTRo0frwoULliNzNB8AAAAAAAAKXlFYU65NmzYKCQnRiy++qN27d+dJnw5PX503b54WLFigDh06WMrq16+vwMBA9ezZU1OnTnU4iCFDhui7777TmjVrVKVKFUt5QECA0tLSdP78eavRcomJiQoICLDZl7u7u9zd3R2OAQAAAAAAAHnPxXz9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Qc8884wlIZcpICBAvXv31sKFC2UYhpMizBsXL17U559/rho1aqhs2bLODifX+vXrp7Zt22rAgAGaPHmydu3aZTVyDrenNm3aqEGDBvr666+dHQp0/Xtv+fLlioqKskrIZfL19S34oPLQCy+8oDfeeEPfffcdCTnkO09PT3l6emrx4sVKTU11djiw44svvlDt2rVVq1YtPfHEE5o5c2ah//muqAgLC9OqVassj1etWqXWrVurVatWlvLLly9r48aNJOVuA3yWANwKknJ54IknntDatWt15MgRHTlyROvWrdMTTzzh7LBy5Y8//pBhGKpTp47N+jp16ujcuXM6depUAUd267777jvLLwteXl5asmSJFi5cKLO5cH8Mpk+frl27dmnEiBGaPn16oRz1VxzVrl1bhw8fdnYYkLR//34ZhqHatWs7O5Q8t2zZMo0fP17ffvut2rZt6+xwUAy4urpq9uzZmjNnjnx9fdW8eXO9+OKLhXYN16JsxowZlp9X27dvrwsXLmj16tVOjgrS9aTcunXrdO3aNSUnJ2vbtm1q1aqVWrZsqfj4eEnX1zBLTU0tdEm5G38ezzw6dOjg7LBuCZ+lwsPW++/tt992dlgo5gp3NuI2Ub58eXXs2FGzZ8/WrFmz1LFjR5UrV87ZYd2SovivO2FhYdq+fbu2b9+uX375RREREerQoYOOHDni7NBuSYUKFfSvf/1LderUKXILshZlhmHIZDI5OwyoaH7fZapfv76Cg4MVExOjixcvOjscFBPdunXT8ePHtWTJErVv317x8fG65557NHv2bGeHhr/t27dPv/zyi3r27CnpejK1e/fumjFjhpMjgyS1bt1aKSkp2rRpk3766SfdcccdKl++vFq1amVZVy4+Pl7VqlUrdGtY3/jzeObxySefODusXOOzVLjYev/Z2rQRKEisKZdHBgwYoCFDhkiSpkyZ4uRocq9GjRoymUzas2ePzWlOe/bskZ+fX6EcjVW6dGnVqFHD8viTTz6Rj4+PPv74Y7355ptOjOzWubq6ytWVj3NhsmfPnkK77mRRU7NmTZlMJu3du9fZoeS5ypUr66uvvlJYWJjat2+vZcuWycvLy9lhoRjw8PBQu3bt1K5dO73yyit68sknFRMTU2h3pS9qZsyYoWvXrqlSpUqWMsMw5O7ursmTJ8vHx8eJ0aFGjRqqUqWKVq1a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",
|
|
"text/plain": [
|
|
"<Figure size 1400x300 with 2 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"# ── Visualise one-hot encoding ─────────────────────────────────────────────\n",
|
|
"plt.figure(figsize=(14, 3))\n",
|
|
"plt.imshow(sensory_np.T, aspect='auto', cmap='Blues', vmin=0, vmax=1)\n",
|
|
"plt.colorbar(label='activation')\n",
|
|
"plt.xlabel('Position')\n",
|
|
"plt.ylabel('Vocab index')\n",
|
|
"plt.title(f'One-hot encoding: \"{decoded}\"')\n",
|
|
"plt.xticks(range(N_SAMPLES), list(decoded))\n",
|
|
"plt.tight_layout()\n",
|
|
"plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "c33-0005",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:22:40.574951208Z",
|
|
"start_time": "2026-05-31T13:22:40.522104813Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:29:01.926569Z",
|
|
"iopub.status.busy": "2026-05-31T13:29:01.926367Z",
|
|
"iopub.status.idle": "2026-05-31T13:29:01.929974Z",
|
|
"shell.execute_reply": "2026-05-31T13:29:01.929256Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"sequences shape : (1, 20, 40) → 1 sequence of 20 chars\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# ── Prepare sequences for StackRnn ─────────────────────────────────────────\n",
|
|
"sequences = sensory_np[np_cpu.newaxis, :, :] # (1, 20, 40)\n",
|
|
"print(f\"sequences shape : {sequences.shape} → 1 sequence of {N_SAMPLES} chars\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "c33-0006",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:22:40.693389541Z",
|
|
"start_time": "2026-05-31T13:22:40.581860790Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:29:01.931570Z",
|
|
"iopub.status.busy": "2026-05-31T13:29:01.931406Z",
|
|
"iopub.status.idle": "2026-05-31T13:29:02.037412Z",
|
|
"shell.execute_reply": "2026-05-31T13:29:02.036520Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Mode : shared\n",
|
|
"Visible : 128 (context) + 40 (sensory) = 168\n",
|
|
"Hidden : 128\n",
|
|
"Parameters : 21,504\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# ── Build model ────────────────────────────────────────────────────────────\n",
|
|
"rnn = StackRnn(PRJ_NAME, WORK_DIR)\n",
|
|
"rnn.append(StackRnn.make_layer(\n",
|
|
" \"layer0\",\n",
|
|
" sensory_size=SENSORY_SIZE,\n",
|
|
" h_size=CONTEXT_SIZE,\n",
|
|
" entity_params=EntityParams(\n",
|
|
" do_gaussian_visible=False,\n",
|
|
" do_gaussian_hidden=False,\n",
|
|
" num_gibbs_samples=NUM_GIBBS,\n",
|
|
" ),\n",
|
|
" training_params=TrainingParams(\n",
|
|
" learning_rate=LEARNING_RATE,\n",
|
|
" momentum=MOMENTUM,\n",
|
|
" num_epochs=NUM_EPOCHS,\n",
|
|
" mini_batch_size=MINI_BATCH,\n",
|
|
" num_gibbs_samples=NUM_GIBBS,\n",
|
|
" do_rao_blackwell=RAO_BLACKWELL,\n",
|
|
" l2_lambda=L2_LAMBDA,\n",
|
|
" ),\n",
|
|
"))\n",
|
|
"\n",
|
|
"rnn.state_init(0.01)\n",
|
|
"rnn.state_load()\n",
|
|
"\n",
|
|
"e = rnn.from_index(0).entity\n",
|
|
"print(f\"Mode : {'shared' if rnn.is_shared else 'unrolled'}\")\n",
|
|
"print(f\"Visible : {rnn.h_size()} (context) + {rnn.sensory_size()} (sensory) = {e.shape[0]}\")\n",
|
|
"print(f\"Hidden : {rnn.h_size()}\")\n",
|
|
"print(f\"Parameters : {e.shape[0] * e.shape[1]:,}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "c33-0007",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:23:41.130302008Z",
|
|
"start_time": "2026-05-31T13:22:40.695146047Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:29:02.039109Z",
|
|
"iopub.status.busy": "2026-05-31T13:29:02.038931Z",
|
|
"iopub.status.idle": "2026-05-31T13:30:46.898008Z",
|
|
"shell.execute_reply": "2026-05-31T13:30:46.897173Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 0%\n",
|
|
"Entity-168x128: err_rms : 0.006513810748197312\n",
|
|
"Entity-168x128: l2_norm : 0.16668707179363768\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 10%\n",
|
|
"Entity-168x128: err_rms : 0.005327613080843449\n",
|
|
"Entity-168x128: l2_norm : 2.1248952398421848\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 20%\n",
|
|
"Entity-168x128: err_rms : 0.0022508816936137495\n",
|
|
"Entity-168x128: l2_norm : 7.285520227496324\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 30%\n",
|
|
"Entity-168x128: err_rms : 0.00023891875964096135\n",
|
|
"Entity-168x128: l2_norm : 11.942612143538451\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 40%\n",
|
|
"Entity-168x128: err_rms : 0.0003654588775567404\n",
|
|
"Entity-168x128: l2_norm : 14.038897529481288\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 50%\n",
|
|
"Entity-168x128: err_rms : 0.0005439847855184065\n",
|
|
"Entity-168x128: l2_norm : 15.413432769275325\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 60%\n",
|
|
"Entity-168x128: err_rms : 4.005501369432108e-05\n",
|
|
"Entity-168x128: l2_norm : 16.458922493692164\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 70%\n",
|
|
"Entity-168x128: err_rms : 1.826141900561072e-05\n",
|
|
"Entity-168x128: l2_norm : 17.16704910391379\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 80%\n",
|
|
"Entity-168x128: err_rms : 1.072283482720063e-05\n",
|
|
"Entity-168x128: l2_norm : 17.9025294873916\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 90%\n",
|
|
"Entity-168x128: err_rms : 1.808959411651762e-05\n",
|
|
"Entity-168x128: l2_norm : 18.510211685821016\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"-------------------------------------------\n",
|
|
"Entity-168x128: progress : 100%\n",
|
|
"Entity-168x128: err_rms : 1.8806019913429117e-05\n",
|
|
"Entity-168x128: l2_norm : 19.03956209476975\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# ── Train: predict next character from current context ─────────────────────\n",
|
|
"# Pairs used: (h_t, x_{t+1})\n",
|
|
"# Step 1 — advance context: h_t = forward([h_{t-1} | x_t]) (no weight update)\n",
|
|
"# Step 2 — CD update on visible = [h_t | x_{t+1}] (predict next)\n",
|
|
"from rbm.train import cd_binary_binary, _to_gpu\n",
|
|
"from rbm.matrix import rms_error_accu\n",
|
|
"\n",
|
|
"entity = rnn.from_index(0).entity\n",
|
|
"h_sz = rnn.h_size()\n",
|
|
"num_seq, T, s_sz = sequences.shape\n",
|
|
"\n",
|
|
"rnn.state_init(0.01) # fresh weights for the new training objective\n",
|
|
"entity.grad_zero()\n",
|
|
"\n",
|
|
"d_progress = 100.0 / NUM_EPOCHS\n",
|
|
"progress = 0.0\n",
|
|
"status = CheckpointStatus(rnn.state_save, update_interval=10)\n",
|
|
"status.on_change(entity)\n",
|
|
"\n",
|
|
"for epoch in range(NUM_EPOCHS):\n",
|
|
" h = np.zeros((num_seq, h_sz))\n",
|
|
" err_total = 0.0\n",
|
|
"\n",
|
|
" for t in range(T - 1):\n",
|
|
" x_t = _to_gpu(sequences[:, t, :]) # current char x_t\n",
|
|
" x_tp1 = _to_gpu(sequences[:, t+1, :]) # next char x_{t+1}\n",
|
|
"\n",
|
|
" # Step 1: advance context to h_t (no training)\n",
|
|
" h = entity.forward(np.concatenate([h, x_t], axis=1))\n",
|
|
"\n",
|
|
" # Step 2: train on [h_t | x_{t+1}]\n",
|
|
" vis = np.concatenate([h, x_tp1], axis=1)\n",
|
|
" dwhv, dbv, dbh = cd_binary_binary(entity, vis)\n",
|
|
" grad = entity.grad_compute(dbv, dbh, dwhv)\n",
|
|
" entity.state_adjust(grad, 1.0 / num_seq)\n",
|
|
" err_total += rms_error_accu(vis - entity.reconstruct(entity.forward(vis)))\n",
|
|
"\n",
|
|
" progress += d_progress\n",
|
|
" if status.want_report(round(progress)):\n",
|
|
" if not status.on_change(entity, {\n",
|
|
" \"progress\": {\"value\": round(progress), \"unit\": \"%\"},\n",
|
|
" \"err_rms\": {\"value\": err_total / (T - 1), \"unit\": \"\"},\n",
|
|
" }):\n",
|
|
" break\n",
|
|
"\n",
|
|
"rnn.state_save()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "c33-0008",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:23:41.188793248Z",
|
|
"start_time": "2026-05-31T13:23:41.131570611Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:30:46.899659Z",
|
|
"iopub.status.busy": "2026-05-31T13:30:46.899504Z",
|
|
"iopub.status.idle": "2026-05-31T13:30:46.946219Z",
|
|
"shell.execute_reply": "2026-05-31T13:30:46.945561Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Input : 'MOBY DICK IS A WHALE'\n",
|
|
"Reconstruction: 'KOBY DICK IS A WHALE'\n",
|
|
"Char accuracy : 19/20 = 95%\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# ── Reconstruction: teacher-forced ─────────────────────────────────────────\n",
|
|
"# Step through each sample, reconstruct, compare to input.\n",
|
|
"rnn.reset(batch_size=1)\n",
|
|
"recons = []\n",
|
|
"for i in range(N_SAMPLES):\n",
|
|
" x_t = np.array(sensory_np[i][np_cpu.newaxis, :])\n",
|
|
" h = rnn.step(x_t)\n",
|
|
" rec = convert(rnn.reconstruct(h))[0] # (40,)\n",
|
|
" recons.append(rec)\n",
|
|
"\n",
|
|
"recons_np = np_cpu.array(recons) # (12, 40)\n",
|
|
"decoded_recon = ''.join(idx_to_char[int(np_cpu.argmax(recons_np[i]))] for i in range(N_SAMPLES))\n",
|
|
"\n",
|
|
"print(f\"Input : '{decoded}'\")\n",
|
|
"print(f\"Reconstruction: '{decoded_recon}'\")\n",
|
|
"\n",
|
|
"correct = sum(decoded[i] == decoded_recon[i] for i in range(N_SAMPLES))\n",
|
|
"print(f\"Char accuracy : {correct}/{N_SAMPLES} = {100*correct/N_SAMPLES:.0f}%\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "c33-0009",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:23:41.447170202Z",
|
|
"start_time": "2026-05-31T13:23:41.189542593Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:30:46.948165Z",
|
|
"iopub.status.busy": "2026-05-31T13:30:46.947978Z",
|
|
"iopub.status.idle": "2026-05-31T13:30:47.251185Z",
|
|
"shell.execute_reply": "2026-05-31T13:30:47.250343Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "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zdu6dasuX76shg0bqmHDhnZh84cffpDk+Cdd1mN+45TdH0fLli1TWlqaevToodDQUDVv3tzpkJydCxcuOKzhxmuNAQDgiLXRWaJECdu8n3/+Wffdd59++eUXvfDCC5o4caKKFCmijh07asmSJbb10tLS1KRJE33wwQe6//77NXnyZA0ePFj79u3T8ePHJf31hWXz5s312WefqXfv3powYYLMZrP69evn8FdGc+fO1YQJEzRo0CC9/vrrOnLkiDp37mz32dqlSxctWbJE/fv319SpU/XUU0/pwoULOnr0qCRp0qRJKlu2rKpUqWLLmy+99JLdOE8++aT+85//aMyYMXrhhRdy/Lq9+uqrevTRR1WwYEGNGzdOr776qiIiImz5xpkaMouPj1e3bt1UoEABjR8/Xo8//rgWL16sxo0b6/z583brOpvjR40apapVq+bZNYtvlQe/+uorFSpUKNsztsuXL6/GjRtr7dq1unjxot2yzHnm119/1SuvvKK9e/fa/Yrqvvvu0xNPPKEJEyZoz549GjRokKKionJ8TwRHnMnRBw4c0L59+9SxY8cc//pq+PDhev/99zVy5Ei9+eabua6zXLlyunbtmj777LNc70P6q2nbuXNn+fn5qWfPnrbLDtxKoUKFVKdOHbscfezYMR07dsxhjt6zZ48sFovDHJ1dhnV0nw5J2rx5sw4ePKiePXvKz89PnTt3vu0c/eeffzqs4erVq7e1X8BlDAB3lFmzZhmSjK1bt9rm9e3b15BkjBs3zm7du+++26hTp47t8eHDhw1JRkBAgHH8+HHb/M2bNxuSjOHDh9vmNWvWzGjWrFmW8fv27WuUK1fO9vjUqVOGJGPs2LFZ1rWO17dv35w/0Rs0a9bMqF69umEYhnHvvfcaAwcONAzDMM6dO2f4+fkZs2fPNtatW2dIMhYuXGgYhmGcP3/ekGQ89NBDN933gw8+aEgyLBaLYRj/e41vnPz9/Y34+Pgs2x85csQoUqSIERQUZBQsWNDYs2ePU89p7NixhiTj1KlTDpefO3fOkGR06tTJNq9v375GkSJFbI8nT55sSDKWLFni1JjW16hcuXKGJGPKlClObWdlPaYTJkywzdu7d68REBBgSDL+8Y9/GMOGDTO+/PJLIz093en9Llq0yJBkHDhwwDAMw7BYLEahQoWM9957z6ntH374YSMgIMC4fPmyYRiGMX78eKN8+fKGYRjG1KlTjZCQENu6zz33nCHJ+P33323zsjvmmSfr+y+z9u3bG40aNbI9nj59uuHr62ucPHnSbr1bHWvD+N+xyW46ceKEU68FAMA7WD+7vvvuO+PUqVPGsWPHjEWLFhmlSpUy/P39jWPHjtnWbdmypVGzZk3j0qVLtnnXr183GjZsaFSqVMk2b8yYMYYkY/HixVnGu379umEYhjFp0iRDkjFnzhzbssuXLxsNGjQwihYtastT1swQHBxsnD171rbu0qVLDUnGV199ZRjG//JO5mzhSPXq1R1mU+vr0LhxY+Pq1at2y27MrVbWz2WrAwcOGD4+PkanTp2Ma9euOXzeN6vB+hm+bt062+sREhJi1KhRw7h48aJtva+//tqQZIwZM8auRmdyfOZ1Dx8+nKWGnHA2DxYvXtyoXbv2Tff11FNPGZKM3bt32+37xsnHx8d44403smyfmppqhIeHG0FBQYYkY8WKFU49B0d/E93IbDYbd999t+3xjXnM+l50Nm9a39PW123EiBFObZeZJCMuLs72ODk52ShVqpQhyahSpYoxePBgY+7cucb58+ed3ue2bdsMScbq1asNw/jrPVu2bFlj2LBhTm0/YsQIQ5Lt78N58+YZhQoVMjIyMoxvv/3WKFCggO3f9YcffmhIMpKSkmzb3yrDSrL7+8VqyJAhRkREhO3f2KpVqwxJxs6dO+3Wc+ZYW49NdtOmTZucei2A/MaZtoAXGTx4sN3jJk2a6L///W+W9Tp27KgyZcrYHterV0/169fXt99+m6f1REVFyTCMPL/Lbq9evbR48WJdvnxZixYtUoECBRzeSMx619hbfXNuXW6xWOzmT5kyRatXr9bq1as1Z84cxcTE6LHHHrO7i6z01zfkY8eO1dmzZ/XMM8+oRo0at/P0bKw3HXB091sra805PTsgJSVFvr6+Kl++fO4L/H/Vq1fXTz/9pEceeURHjhzR5MmT1bFjR5UuXVqffPKJU/tISEjQvffea7thQrFixdSuXbscXSLh4sWL2r59uyTZXResUaNGOnnypA4cOGBbVr58eYWHh2fZT+Zjnnly9BO9M2fOaOXKlXZ3Pu7SpYtMJpM+//xzp+p2ZMyYMQ5rCAoKyvU+AQB3rlatWqlUqVKKiIhQ165dVaRIES1btsx2iYCzZ89q7dq16tatm92ZcGfOnFFsbKwOHDhgO3Pziy++UO3atR3mKutPob/99luFhobaff4VLFhQTz31lNLS0rR+/Xq77bp372531q/110/WjBoQECA/Pz8lJibq3LlzuX4dHn/88Rz96iizL7/8UtevX9eYMWOyXEc1Nz8B37Ztm06ePKknn3zS7uft7dq1U5UqVRz+wsuZHB8fHy/DMG7rmp+Z3SoPOnNT2OxydOY8s2DBAvXs2VMvvfRSlrOxAwMDNWnSJJ09e1bdu3dXbGzsbTwje0WLFnVZjpakypUr5764/1e6dGnt2rVLgwcP1rlz5/TRRx+pV69eCgkJ0WuvvebUL60SEhJUunRpxcTESPrrPdu9e3fNnz8/yyU2HLGeNbthwwZJf2XlOnXqyM/PTw0aNLBdEsG6zHp5lRtll2Ez32jO6urVq1qwYIG6d+9u+zfWokULhYSE3NbZtv/85z8d1lCtWrVc7xNwJZq2gJcoVKhQlmu2lihRwmH4rVSpUpZ5lStXtv2cztP16NFDqampWr58uRISEtS+fXuHYcs672ZhLfPyG/dRr149tWrVSq1atVLv3r31zTffqFq1ahoyZIguX75st6717riOAkxupaWlOawrs8DAQLvn4Kx33nlHkZGR6tq1a5ZrWOVG5cqV9dlnn+n06dPavXu33nzzTfn6+uqf//ynvvvuu5tue/78eX377bdq1qyZDh48aJsaNWqkbdu26ddff73l+Jmva2sYhn744Qc1atRIklSjRg0FBgYqKSlJly5d0vbt27O9nm3mY555yvzHptWCBQt05coV3X333baaz549q/r1699W2KxZs6bDGv7Od6QGALiO9QvHRYsW6YEHHtDp06fl7+9vW37w4EEZhqHRo0erVKlSdpP1Z+jWG4ceOnToll8+//bbb6pUqVKW5qb1pkS//fab3fzIyEi7x9bPVGtG9ff319tvv63ly5erdOnSatq0qd555x2nLpGU2e18EX3o0CH5+PjkWWPH+hrcddddWZZVqVIly2uUkxyfl26VB4sVK5brHJ05z3Tr1k1z5sxR+/bt9cILL+jUqVN267oiR0t/ZWlX5OiRI0eqbt26GjRokBYtWnRbNUpSWFiYpk2bphMnTmj//v16//33VapUKY0ZM0YzZsy46bbXrl3T/PnzFRMTo8OHD9syaf369ZWSkqI1a9bccvxGjRrJZDLZ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zVq8eLHS0tIkSbt27dLYsWPzvEAAAAAAAAAA8CY5btq+8MILev3117V69Wr5+fnZ5rdo0UI//vhjnhYHAAAAAAAAAN4mx03bPXv2qFOnTlnmh4SE6PTp03lSFAAAAAAAAAB4qxw3bYsXL64TJ05kmb9z506VKVMmR/v6/vvv1aFDB4WHh8tkMunLL7+0W96vXz+ZTCa7qU2bNjktGQAAAMgxsioAAADcxTenG/To0UMjR47UwoULZTKZdP36dSUlJem5555Tnz59crSv9PR01a5dWwMGDFDnzp0drtOmTRvNmjXL9tjf3z+nJXs97gYIAO7D/wO9G8f/742smj/IqgDgPvw/0Ltx/D1bjpu2b775puLi4hQREaFr166pWrVqunbtmnr16qWXX345R/tq27at2rZte9N1/P39FRoamtMyAQAAgNtCVgUAAIC75Lhp6+fnp08++USjR4/W3r17lZaWprvvvluVKlVyRX1KTExUSEiISpQooRYtWuj1119XcHBwtutnZGQoIyPD9thisbikLgAAAICsCgAAAFfIcdPWKjIyUpGRkXlZSxZt2rRR586dVb58eR06dEgvvvii2rZtq02bNqlAgQIOtxk/frxeffVVl9YFAAAAkFUBAADgKk41bZ955hmnd/juu+/mupgb9ejRw/bfNWvWVK1atRQdHa3ExES1bNnS4TajRo2yq9disSgiIiLPagIAAAAksioAAABcx6mm7c6dO+0e79ixQ1evXtVdd90lSfr1119VoEAB1alTJ+8rzKRChQoqWbKkDh48mG0Q9vf35wYQAAAAyHdkVQAAAOQVp5q269ats/33u+++q2LFimn27NkqUaKEJOncuXPq37+/mjRp4poq/9/x48d15swZhYWFuXScOw13A4Q7cUdoAIC3IKvmDp/VcCeyKgDAU+X4mrYTJ07UqlWrbA1bSSpRooRef/113X///Xr22Wed3ldaWpoOHjxoe3z48GH99NNPCgoKUlBQkF599VV16dJFoaGhOnTokJ5//nlVrFhRsbGxOS0bAAAAyBGyKgAAANwlx01bi8WiU6dOZZl/6tQpXbhwIUf72rZtm2JiYmyPrdf36tu3r6ZNm6bdu3dr9uzZOn/+vMLDw3X//ffrtdde4ydlAAAAcDmyKgAAANwlx03bTp06qX///po4caLq1asnSdq8ebNGjBih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",
|
|
"text/plain": [
|
|
"<Figure size 1400x300 with 2 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"# ── Visualise reconstruction ───────────────────────────────────────────────\n",
|
|
"fig, axes = plt.subplots(1, 2, figsize=(14, 3))\n",
|
|
"\n",
|
|
"axes[0].imshow(sensory_np.T, aspect='auto', cmap='Blues', vmin=0, vmax=1)\n",
|
|
"axes[0].set_title(f'Input: \"{decoded}\"')\n",
|
|
"axes[0].set_xticks(range(N_SAMPLES))\n",
|
|
"axes[0].set_xticklabels(list(decoded))\n",
|
|
"axes[0].set_ylabel('Vocab index')\n",
|
|
"\n",
|
|
"axes[1].imshow(recons_np.T, aspect='auto', cmap='Blues', vmin=0, vmax=1)\n",
|
|
"axes[1].set_title(f'Reconstruction: \"{decoded_recon}\"')\n",
|
|
"axes[1].set_xticks(range(N_SAMPLES))\n",
|
|
"axes[1].set_xticklabels(list(decoded_recon))\n",
|
|
"\n",
|
|
"plt.tight_layout()\n",
|
|
"plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"id": "c33-0010",
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-05-31T13:23:41.550688083Z",
|
|
"start_time": "2026-05-31T13:23:41.448385388Z"
|
|
},
|
|
"execution": {
|
|
"iopub.execute_input": "2026-05-31T13:30:47.253086Z",
|
|
"iopub.status.busy": "2026-05-31T13:30:47.252868Z",
|
|
"iopub.status.idle": "2026-05-31T13:30:47.404677Z",
|
|
"shell.execute_reply": "2026-05-31T13:30:47.403914Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Input (t+1) : 'OBY DICK IS A WHALE'\n",
|
|
"Predicted from h_t : 'OIY DICK IS A WHALE'\n",
|
|
"Next-step accuracy : 18/19 = 95%\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# ── Next-step prediction ───────────────────────────────────────────────────\n",
|
|
"# Given h_t (context after seeing x_t), predict x_{t+1} via clamped Gibbs.\n",
|
|
"def predict_next(rnn, context, n_gibbs=NUM_GIBBS, temperature=1.0):\n",
|
|
" entity = rnn.next_entity()\n",
|
|
" h_sz, s_sz = rnn.h_size(), rnn.sensory_size()\n",
|
|
" x_init = (np.random.rand(1, s_sz) > 0.5).astype(float)\n",
|
|
" visible = np.concatenate([context, x_init], axis=1)\n",
|
|
" for _ in range(n_gibbs):\n",
|
|
" h = entity.forward(visible)\n",
|
|
" visible = entity.reconstruct(h)\n",
|
|
" visible[:, :h_sz] = context\n",
|
|
" probs = convert(visible[:, h_sz:])[0]\n",
|
|
" probs = np_cpu.power(np_cpu.clip(probs, 1e-10, 1.0), 1.0 / temperature)\n",
|
|
" probs /= probs.sum()\n",
|
|
" return probs\n",
|
|
"\n",
|
|
"rnn.reset(batch_size=1)\n",
|
|
"h = np.zeros((1, CONTEXT_SIZE))\n",
|
|
"predicted = ''\n",
|
|
"\n",
|
|
"for i in range(N_SAMPLES - 1):\n",
|
|
" x_t = np.array(sensory_np[i][np_cpu.newaxis, :])\n",
|
|
" h = rnn.step(x_t) # advance to h_t\n",
|
|
" probs = predict_next(rnn, h.copy()) # predict x_{t+1} from h_t\n",
|
|
" predicted += idx_to_char[int(np_cpu.argmax(probs))]\n",
|
|
"\n",
|
|
"print(f\"Input (t+1) : '{decoded[1:]}'\")\n",
|
|
"print(f\"Predicted from h_t : '{predicted}'\")\n",
|
|
"correct = sum(decoded[i+1] == predicted[i] for i in range(N_SAMPLES - 1))\n",
|
|
"print(f\"Next-step accuracy : {correct}/{N_SAMPLES-1} = {100*correct/(N_SAMPLES-1):.0f}%\")"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.12.3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|