diff --git a/vrc_pondernet.ipynb b/vrc_pondernet.ipynb index 64304c6..105ffaa 100644 --- a/vrc_pondernet.ipynb +++ b/vrc_pondernet.ipynb @@ -21,41 +21,74 @@ }, { "cell_type": "markdown", - "source": [], + "source": [ + "## Problem setting\n", + "\n", + "### Model\n", + "Given input and output data, we want to learn a supervised model of the function $X \\to y$ as follows:\n", + "\n", + "$\n", + "f: X,h_n \\mapsto \\tilde{y},h_{n+1}, \\lambda_n\n", + "$\n", + "\n", + "where $X$ and $y$ denote stimulus and response symbols, $\\lambda_n$ denotes halting probability at time $n$, and $h_{n}$ is the latent state of the model. The learninig continious up to the time point $N$.\n", + "\n", + "For the brevity and compatibility, both data are one-hot encoded.\n", + "\n", + "\n", + "### Input\n", + "\n", + "One-hot encoded symbols.\n", + "\n", + "### Output\n", + "\n", + "One-hot encoded symbols.\n", + "\n", + "### Criterion\n", + "\n", + "L = L_cross_entropy + L_halting" + ], "metadata": {} }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 161, "source": [ "# Setup and imports\n", "import torch\n", "from torch import nn\n", + "from torch.utils.tensorboard import SummaryWriter\n", + "\n", + "from sklearn.metrics import accuracy_score\n", "\n", "import numpy as np\n", "from scipy import stats\n", "import pandas as pd\n", "\n", "import matplotlib.pyplot as plt\n", - "import seaborn as sns; sns.set()" + "import seaborn as sns; sns.set()\n", + "\n", + "import tensorflow as tf\n", + "import tensorboard as tb\n", + "tf.io.gfile = tb.compat.tensorflow_stub.io.gfile" ], "outputs": [], "metadata": {} }, { "cell_type": "code", - "execution_count": 170, + "execution_count": 2, "source": [ "# produce a tarin of spikes and store timestamps of each spike in `spike_timestamps`.\n", "\n", "signal_rate = 2\n", "noise_rate = 1\n", "rate = signal_rate + noise_rate\n", - "duration_in_sec = 10.\n", + "max_duration_in_sec = 10.\n", "resolution_in_sec = .1\n", "\n", - "n_total_timesteps = int(duration_in_sec / resolution_in_sec)\n", - "n_spikes = np.random.poisson(rate * duration_in_sec)\n", + "n_total_timesteps = int(max_duration_in_sec / resolution_in_sec)\n", + "n_spikes = np.random.poisson(rate * max_duration_in_sec)\n", "\n", "# method 1: shuffle timesteps\n", "spike_timesteps = np.sort(np.random.choice(n_total_timesteps, size=n_spikes, replace=False))\n", @@ -65,7 +98,7 @@ "# spike_timestamps = np.cumsum(isi)\n", "\n", "# method 3: homogenous spikes -> timestamps\n", - "# spike_timestamps = stats.uniform.rvs(loc=0, scale=duration_in_sec, size=n_spikes)\n" + "# spike_timestamps = stats.uniform.rvs(loc=0, scale=max_duration_in_sec, size=n_spikes)" ], "outputs": [], "metadata": {} @@ -73,32 +106,11 @@ { "cell_type": "markdown", "source": [ - "## RNN" + "## PonderRNN" ], "metadata": {} }, { - "cell_type": "code", - "execution_count": 174, - "source": [ - "class PonderVRC(nn.Module):\n", - " def __init__(self, n_inputs, n_channels):\n", - " super(PonderVRC, self).__init__()\n", - " self.rnn = nn.RNN(n_inputs, n_channels)\n", - " self.fc1 = nn.Linear(n_channels, n_inputs, bias=False)\n", - " self.fc2 = nn.Linear(n_channels,1, bias=False)\n", - "\n", - " def forward(self, x):\n", - " h = self.rnn(x)\n", - " y = self.fc1(h)\n", - " y = self.fc1(h)\n", - "\n", - " return y" - ], - "outputs": [], - "metadata": {} - }, - { "cell_type": "markdown", "source": [ "## Mock data" @@ -107,86 +119,157 @@ }, { "cell_type": "code", - "execution_count": 330, + "execution_count": 3, "source": [ - "n_trials = 30\n", - "n_stimuli = 6\n", + "\n", + "\n", + "def generate_mock_data(n_subjects, n_trials, n_stimuli):\n", + " \"\"\"[summary]\n", + "\n", + " # TODO required data columns: subject_index, trial_index, stimulus_index, accuracy, response_time\n", + "\n", + " Args:\n", + " n_subjects (int): [description]\n", + " n_trials (int): [description]\n", + " n_stimuli (int): [description]\n", + "\n", + " Returns:\n", + " (X, accuracies, response_times): A tuple containing generated mock X, accuracies, and response_times (in sec).\n", + " \"\"\"\n", + " # stimuli\n", + " X = np.random.randint(low=1, high=n_stimuli+1, size=(n_subjects, n_trials))\n", + "\n", + " # response accuracy\n", + " subject_accuracies = np.random.uniform(low=0.2, high=1.0, size=n_subjects)\n", + " subject_accuracies = np.round(subject_accuracies * n_trials) / n_trials\n", + " accuracies = np.empty(shape=(n_subjects, n_trials))\n", + " for subj in range(n_subjects):\n", + " accuracies[subj,:] = np.random.choice(\n", + " [0,1],\n", + " p=[1-subject_accuracies[subj],subject_accuracies[subj]],\n", + " size=n_trials)\n", + "\n", + " # generate output w.r.t the accuracy (and fill incorrect trials with invalid response)\n", + " y = np.where(accuracies == 1., X, X+1 % (n_stimuli+1))\n", + "\n", + " # response time\n", + " response_times = np.random.exponential(.5, size=accuracies.shape)\n", + "\n", + " return X, y, accuracies, response_times" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": 105, + "source": [ + "# mock data parameters\n", "n_subjects = 1\n", + "n_trials = 20\n", + "n_stimuli = 6\n", "\n", - "# required data columns: subject_index, trial_index, stimulus_index, accuracy, response_time\n", - "# TODO: generate random data and reshape into the following\n", + "X, y, accuracies, response_times = generate_mock_data(n_subjects, n_trials, n_stimuli)" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": 172, + "source": [ + "logs = SummaryWriter()\n", "\n", - "# stimuli\n", - "X = np.random.randint(low=1, high=n_stimuli+1, size=(n_subjects, n_trials))\n", + "class PonderRNN(nn.Module):\n", + " def __init__(self, n_inputs, n_channels, n_outputs):\n", + " super(PonderRNN, self).__init__()\n", + " self.fc1 = nn.Linear(n_inputs, n_channels, bias=False)\n", + " self.rnn = nn.RNN(n_channels, n_channels)\n", + " self.fc2 = nn.Linear(n_channels,n_outputs, bias=False)\n", + " self.softmax = nn.Softmax(dim=2)\n", "\n", - "# accuracy (index=0)\n", - "accuracies = np.random.randint(low=0, high=2, size=(n_subjects, n_trials))\n", - "response_times = np.random.exponential(.5, size=(n_subjects, n_trials))\n", + " def forward(self, x):\n", + " sent_msg = self.fc1(x)\n", + " rcvd_msg, embedding = self.rnn(sent_msg)\n", + " logits = self.fc2(rcvd_msg)\n", "\n", - "response_times\n", - "# responses = np.empty((n_subjects, n_trials, 2))\n", - "# responses[:,:,0] = np.where(accuracies==1., X, )\n", - "# response_time (index=1)\n", - "# responses[:,:,1].exponential_(.5)\n", - "\n" + " out = self.softmax(logits).squeeze()\n", + "\n", + " halting_prob = 0. # TODO\n", + "\n", + " return out, embedding, halting_prob\n", + "\n", + "def criterion(self, input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:\n", + " return torch.functional.binary_cross_entropy_with_logits()\n", + "\n", + "n_epoches = 1500\n", + "\n", + "model = PonderRNN(n_stimuli+1, n_stimuli, n_stimuli+1)\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n", + "criterion = torch.nn.CrossEntropyLoss()\n", + "\n", + "X_train = nn.functional.one_hot(torch.tensor(X)).type(torch.float)\n", + "y_train = torch.tensor(y) - 1\n", + "\n", + "for epoch in range(n_epoches):\n", + " model.train()\n", + " optimizer.zero_grad()\n", + " y_pred, h, _ = model(X_train)\n", + "\n", + " # logs.add_embedding(h.reshape(n_trials,n_stimuli), global_step=epoch, tag='embedding')\n", + "\n", + " model_accuracy = accuracy_score(y_train.squeeze(), torch.argmax(y_pred.detach(),dim=1))\n", + " logs.add_scalar('accurracy/train', model_accuracy, epoch) \n", + "\n", + " loss = criterion(y_pred, y_train.squeeze())\n", + " logs.add_scalar('loss/train', loss, epoch)\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + "# tensorboard --logdir==runs/" ], "outputs": [ { - "output_type": "execute_result", - "data": { - "text/plain": [ - "array([[0.89434811, 0.64370202, 0.19886853, 1.39208346, 0.41082363,\n", - " 0.08900332, 1.11360565, 0.46728826, 0.36291653, 0.67963475,\n", - " 0.45148227, 0.38839379, 0.64743332, 0.41294597, 0.45289691,\n", - " 0.13357337, 0.85012272, 0.7988117 , 1.23502906, 0.53615726,\n", - " 0.07061297, 0.80473662, 0.38354505, 0.58555392, 0.38719181,\n", - " 0.42993123, 0.23014178, 0.13333575, 0.26819837, 0.28917237]])" - ] - }, - "metadata": {}, - "execution_count": 330 + "output_type": "stream", + "name": "stdout", + "text": [ + "torch.Size([1, 20, 6])\n" + ] + }, + { + "output_type": "error", + "ename": "NameError", + "evalue": "name 'xx' is not defined", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0mxx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 42\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0mlogs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_embedding\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn_trials\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mn_stimuli\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mglobal_step\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mepoch\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtag\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'embedding'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'xx' is not defined" + ] } ], "metadata": {} }, { "cell_type": "code", - "execution_count": 176, + "execution_count": 137, "source": [ - "\n", - "n_epoches = 10\n", - "\n", - "model = PonderVRC(10,10)\n", - "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n", - "criterion = torch.nn.BCELoss()\n", - "\n", - "for epoch in range(n_epoches):\n", - " model.train()\n", - " optimizer.zero_grad()\n", - " x = ...\n", - " y_true = ...\n", - " y_pred = model(x)\n", - "\n", - " loss = criterion(y_pred, y_pred)\n", - "\n", - " loss.backward()\n", - " optimizer.step()" + "model.eval()\n", + "y_pred, _ = model(X_train)\n", + "y_pred = np.argmax(y_pred.detach().numpy(), axis=1) + 1\n", + "y_pred, y" ], "outputs": [ { - "output_type": "error", - "ename": "AssertionError", - "evalue": "", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m...\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0my_true\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m...\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0my_pred\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0mloss\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcriterion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my_pred\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my_pred\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniconda3/envs/py3/lib/python3.9/site-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 887\u001b[0m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_slow_forward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 888\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 889\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 890\u001b[0m for hook in itertools.chain(\n\u001b[1;32m 891\u001b[0m \u001b[0m_global_forward_hooks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0mh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrnn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 10\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfc1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfc1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniconda3/envs/py3/lib/python3.9/site-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 887\u001b[0m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_slow_forward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 888\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 889\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 890\u001b[0m for hook in itertools.chain(\n\u001b[1;32m 891\u001b[0m \u001b[0m_global_forward_hooks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/miniconda3/envs/py3/lib/python3.9/site-packages/torch/nn/modules/rnn.py\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, input, hx)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[0mmax_batch_size\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbatch_sizes\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 243\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 244\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTensor\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 245\u001b[0m \u001b[0mbatch_sizes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 246\u001b[0m \u001b[0mmax_batch_size\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbatch_first\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mAssertionError\u001b[0m: " - ] + "output_type": "execute_result", + "data": { + "text/plain": [ + "(array([2, 6, 5, 2, 6, 4, 4, 7, 3, 7, 5, 3, 4, 3, 3, 6, 3, 5, 7, 2]),\n", + " array([[2, 6, 5, 1, 6, 4, 4, 6, 3, 7, 5, 3, 4, 3, 3, 6, 3, 5, 7, 2]]))" + ] + }, + "metadata": {}, + "execution_count": 137 } ], "metadata": {}