├── line.gif ├── test.png ├── data1.png ├── data2.png ├── dataa2.png ├── dataaa2.png ├── line1.gif ├── line2.gif ├── line3.gif ├── line5.gif ├── table.png ├── line_lr_0_08.gif ├── readme.md ├── Hebb_learning.ipynb ├── BP算法.ipynb ├── CNN手写字符识别.ipynb ├── Discrete_Hopfield_Network.ipynb └── LSTM.ipynb /line.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/line.gif -------------------------------------------------------------------------------- /test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/test.png -------------------------------------------------------------------------------- /data1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/data1.png -------------------------------------------------------------------------------- /data2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/data2.png -------------------------------------------------------------------------------- /dataa2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/dataa2.png -------------------------------------------------------------------------------- /dataaa2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/dataaa2.png -------------------------------------------------------------------------------- /line1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/line1.gif -------------------------------------------------------------------------------- /line2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/line2.gif -------------------------------------------------------------------------------- /line3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/line3.gif -------------------------------------------------------------------------------- /line5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/line5.gif -------------------------------------------------------------------------------- /table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/table.png -------------------------------------------------------------------------------- /line_lr_0_08.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeBurningFish/Brain-inspired-computing/HEAD/line_lr_0_08.gif -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 类脑计算实验 2 | * 作者:周阳 3 | * 学号:201600301148 4 | * QQ : 862077860 5 | 6 | ## 实验 7 | * 实验一: discreate hopfield network 8 | * 实验二: 感知机 9 | * 实验三: Hebb Learning 10 | * 实验四: LSTM 11 | * 实验五: HMax模型 12 | * 实验六: 拓扑ICA模型 13 | * 实验七: CNN手写字符识别 14 | * 实验八: BP算法 15 | * 实验九: GAN与Mnist 16 | 17 | --- 18 | * 实验二可视化补充 19 | 20 | 21 | 22 | 23 | 24 | --- 25 | -------------------------------------------------------------------------------- /Hebb_learning.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 25, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "class Hebb(object):\n", 19 | " def __init__(self):\n", 20 | " self.weights = np.zeros((30,30))\n", 21 | " self.n = 30\n", 22 | " \n", 23 | " def f(self,x):\n", 24 | " x[x>0] = 1\n", 25 | " x[x<=0] = -1\n", 26 | " return x\n", 27 | " \n", 28 | " def wild_hebb(self, vec):\n", 29 | " raw = self.weights * vec.repeat(self.n).reshape(self.n, self.n)\n", 30 | " new = np.zeros_like(raw.reshape(30, 30))\n", 31 | " u, v = new.shape\n", 32 | " for i in range(u):\n", 33 | " for j in range(v):\n", 34 | " new[i, j] = np.sum(raw[0:j+1, i])\n", 35 | " delta_w = vec.repeat(self.n).reshape(self.n, self.n) * new\n", 36 | " return delta_w\n", 37 | "\n", 38 | " def train_new(self, input_vector, iter_, rate):\n", 39 | " for i in range(iter_):\n", 40 | " for vec in input_vector:\n", 41 | " vec = np.matrix(vec)\n", 42 | "\t\t#这里可以使用广义hebb算法中的权重更新算法\n", 43 | " wild_hebb = self.wild_hebb(vec)\n", 44 | " delta = np.ones_like(wild_hebb)\n", 45 | " index = np.where(wild_hebb < 0)\n", 46 | " delta[index] = -1\n", 47 | " self.weights = self.weights + rate * vec.getT().dot(vec)\n", 48 | " \n", 49 | " def train(self, input_vector, iter_, rate):\n", 50 | " for i in range(iter_):\n", 51 | " for vec in input_vector:\n", 52 | " vec = np.matrix(vec)\n", 53 | "\t\t#这里可以使用广义hebb算法中的权重更新算法\n", 54 | " self.weights = self.weights + rate * vec.getT().dot(vec)\n", 55 | " return self.weights\n", 56 | " \n", 57 | " def predict(self, input_vector):\n", 58 | " return self.weights.dot(np.matrix(input_vector).getT())" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 70, 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "def add_noise(x,threshold):\n", 68 | " if len(x.shape) >=2:\n", 69 | " for i in range(x.shape[1]):\n", 70 | " random_c = np.random.randint(0,1000)\n", 71 | " if random_c < threshold*1000:\n", 72 | " x[0,i] = -x[0,i]\n", 73 | " else:\n", 74 | " print(x.shape)\n", 75 | " for i in range(len(x)):\n", 76 | " random_c = np.random.randint(0,1000)\n", 77 | " if random_c < threshold*1000:\n", 78 | " x[i] = -x[i]\n", 79 | " \n", 80 | " return x" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 71, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "zero = [\n", 90 | " -1, 1, 1, 1, -1,\n", 91 | " 1, -1, -1, -1, 1,\n", 92 | " 1, -1, -1, -1, 1,\n", 93 | " 1, -1, -1, -1, 1,\n", 94 | " 1, -1, -1, -1, 1,\n", 95 | " -1, 1, 1, 1, -1\n", 96 | " ]\n", 97 | "\n", 98 | "one = [\n", 99 | " -1, 1, 1, -1, -1,\n", 100 | " -1, -1, 1, -1, -1,\n", 101 | " -1, -1, 1, -1, -1,\n", 102 | " -1, -1, 1, -1, -1,\n", 103 | " -1, -1, 1, -1, -1,\n", 104 | " -1, -1, 1, -1, -1\n", 105 | " ]\n", 106 | "\n", 107 | "two = [\n", 108 | " 1, -1, 1, -1, -1,\n", 109 | " -1, -1, -1, 1, -1,\n", 110 | " -1, -1, -1, 1, -1,\n", 111 | " -1, 1, 1, -1, -1,\n", 112 | " 1, -1, -1, -1, -1,\n", 113 | " 1, 1, 1, 1, 1,\n", 114 | " ]\n", 115 | "half_zero = [\n", 116 | "1, 1, 1, 1, 1,\n", 117 | "1, -1, -1, -1, 1,\n", 118 | "1, -1, 1, -1, 1,\n", 119 | "1, -1, -1, -1, 1,\n", 120 | "-1, -1, -1, -1, -1,\n", 121 | "-1, -1, -1, -1, -1,\n", 122 | "]\n" 123 | ] 124 | }, 125 | { 126 | "cell_type": "markdown", 127 | "metadata": {}, 128 | "source": [ 129 | "### 原始" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": 72, 135 | "metadata": {}, 136 | "outputs": [ 137 | { 138 | "name": "stdout", 139 | "output_type": "stream", 140 | "text": [ 141 | "[[-3.36000000e+03 3.36000000e+03 9.60000000e+02 2.40000000e+03\n", 142 | " -9.60000000e+02]\n", 143 | " [ 2.40000000e+03 -9.60000000e+02 -3.06954462e-11 -3.36000000e+03\n", 144 | " 2.40000000e+03]\n", 145 | " [ 2.40000000e+03 -9.60000000e+02 -3.06954462e-11 -3.36000000e+03\n", 146 | " 2.40000000e+03]\n", 147 | " [ 2.40000000e+03 -3.36000000e+03 -2.40000000e+03 -9.60000000e+02\n", 148 | " 2.40000000e+03]\n", 149 | " [ 3.06954462e-11 -9.60000000e+02 -3.06954462e-11 -9.60000000e+02\n", 150 | " 2.40000000e+03]\n", 151 | " [-3.36000000e+03 3.06954462e-11 9.60000000e+02 3.06954462e-11\n", 152 | " -3.36000000e+03]]\n" 153 | ] 154 | } 155 | ], 156 | "source": [ 157 | "hebb = Hebb()\n", 158 | "w=hebb.train([zero, one, two], 600, 0.2)\n", 159 | "pre = hebb.predict(half_zero)\n", 160 | "print(pre.reshape((6,5)))\n", 161 | "def draw_bin_image(image_matrix):\n", 162 | " for row in image_matrix.tolist():\n", 163 | " print('| ' + ' '.join(' *'[int(val)] for val in row))\n" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 73, 169 | "metadata": {}, 170 | "outputs": [], 171 | "source": [ 172 | "def acti_fun(x):\n", 173 | " for i in range(x.size):\n", 174 | " if x[i] > 0:\n", 175 | " x[i] =1\n", 176 | " else:\n", 177 | " x[i] =0\n", 178 | " return x\n" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": 74, 184 | "metadata": {}, 185 | "outputs": [ 186 | { 187 | "name": "stdout", 188 | "output_type": "stream", 189 | "text": [ 190 | "| * * * * *\n", 191 | "| * *\n", 192 | "| * * *\n", 193 | "| * *\n", 194 | "| \n", 195 | "| \n" 196 | ] 197 | } 198 | ], 199 | "source": [ 200 | "draw_bin_image(acti_fun(np.array(half_zero)).reshape((6,5)))" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 75, 206 | "metadata": {}, 207 | "outputs": [ 208 | { 209 | "name": "stdout", 210 | "output_type": "stream", 211 | "text": [ 212 | "| * * * \n", 213 | "| * *\n", 214 | "| * *\n", 215 | "| * *\n", 216 | "| * *\n", 217 | "| * * * \n" 218 | ] 219 | } 220 | ], 221 | "source": [ 222 | "draw_bin_image(acti_fun(pre).reshape((6,5)))" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 77, 228 | "metadata": {}, 229 | "outputs": [ 230 | { 231 | "name": "stdout", 232 | "output_type": "stream", 233 | "text": [ 234 | "| * * \n", 235 | "| * *\n", 236 | "| *\n", 237 | "| * * *\n", 238 | "| * * *\n", 239 | "| * * * \n" 240 | ] 241 | } 242 | ], 243 | "source": [ 244 | "zero_noise = add_noise(np.matrix(zero),0.2)\n", 245 | "draw_bin_image(acti_fun(np.array(zero_noise).reshape(30,)).reshape((6,5)))" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 78, 251 | "metadata": {}, 252 | "outputs": [ 253 | { 254 | "name": "stdout", 255 | "output_type": "stream", 256 | "text": [ 257 | "| * * * \n", 258 | "| * *\n", 259 | "| * *\n", 260 | "| * *\n", 261 | "| * *\n", 262 | "| * * * \n" 263 | ] 264 | } 265 | ], 266 | "source": [ 267 | "pre = hebb.predict(zero_noise)\n", 268 | "draw_bin_image(acti_fun(pre).reshape((6,5)))" 269 | ] 270 | }, 271 | { 272 | "cell_type": "markdown", 273 | "metadata": {}, 274 | "source": [ 275 | "### 广义" 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": 81, 281 | "metadata": {}, 282 | "outputs": [ 283 | { 284 | "name": "stdout", 285 | "output_type": "stream", 286 | "text": [ 287 | "[[-3.36000000e+03 3.36000000e+03 9.60000000e+02 2.40000000e+03\n", 288 | " -9.60000000e+02]\n", 289 | " [ 2.40000000e+03 -9.60000000e+02 -3.06954462e-11 -3.36000000e+03\n", 290 | " 2.40000000e+03]\n", 291 | " [ 2.40000000e+03 -9.60000000e+02 -3.06954462e-11 -3.36000000e+03\n", 292 | " 2.40000000e+03]\n", 293 | " [ 2.40000000e+03 -3.36000000e+03 -2.40000000e+03 -9.60000000e+02\n", 294 | " 2.40000000e+03]\n", 295 | " [ 3.06954462e-11 -9.60000000e+02 -3.06954462e-11 -9.60000000e+02\n", 296 | " 2.40000000e+03]\n", 297 | " [-3.36000000e+03 3.06954462e-11 9.60000000e+02 3.06954462e-11\n", 298 | " -3.36000000e+03]]\n" 299 | ] 300 | } 301 | ], 302 | "source": [ 303 | "hebb = Hebb()\n", 304 | "## here changed\n", 305 | "w=hebb.train_new([zero, one, two], 600, 0.2)\n", 306 | "pre = hebb.predict(half_zero)\n", 307 | "print(pre.reshape((6,5)))\n", 308 | "def draw_bin_image(image_matrix):\n", 309 | " for row in image_matrix.tolist():\n", 310 | " print('| ' + ' '.join(' *'[int(val)] for val in row))" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 82, 316 | "metadata": {}, 317 | "outputs": [ 318 | { 319 | "name": "stdout", 320 | "output_type": "stream", 321 | "text": [ 322 | "| * * * * *\n", 323 | "| * *\n", 324 | "| * * *\n", 325 | "| * *\n", 326 | "| \n", 327 | "| \n" 328 | ] 329 | } 330 | ], 331 | "source": [ 332 | "draw_bin_image(acti_fun(np.array(half_zero)).reshape((6,5)))" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": 83, 338 | "metadata": {}, 339 | "outputs": [ 340 | { 341 | "name": "stdout", 342 | "output_type": "stream", 343 | "text": [ 344 | "| * * * \n", 345 | "| * *\n", 346 | "| * *\n", 347 | "| * *\n", 348 | "| * *\n", 349 | "| * * * \n" 350 | ] 351 | } 352 | ], 353 | "source": [ 354 | "pre = hebb.predict(half_zero)\n", 355 | "draw_bin_image(acti_fun(pre).reshape((6,5)))" 356 | ] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "execution_count": 84, 361 | "metadata": {}, 362 | "outputs": [ 363 | { 364 | "name": "stdout", 365 | "output_type": "stream", 366 | "text": [ 367 | "| * * * \n", 368 | "| * *\n", 369 | "| * * \n", 370 | "| * *\n", 371 | "| * *\n", 372 | "| * * * * \n" 373 | ] 374 | } 375 | ], 376 | "source": [ 377 | "zero_noise = add_noise(np.matrix(zero),0.2)\n", 378 | "draw_bin_image(acti_fun(np.array(zero_noise).reshape(30,)).reshape((6,5)))" 379 | ] 380 | }, 381 | { 382 | "cell_type": "code", 383 | "execution_count": 85, 384 | "metadata": {}, 385 | "outputs": [ 386 | { 387 | "name": "stdout", 388 | "output_type": "stream", 389 | "text": [ 390 | "| * * * \n", 391 | "| * *\n", 392 | "| * *\n", 393 | "| * *\n", 394 | "| * *\n", 395 | "| * * * \n" 396 | ] 397 | } 398 | ], 399 | "source": [ 400 | "pre = hebb.predict(zero_noise)\n", 401 | "draw_bin_image(acti_fun(pre).reshape((6,5)))" 402 | ] 403 | } 404 | ], 405 | "metadata": { 406 | "kernelspec": { 407 | "display_name": "Python 3", 408 | "language": "python", 409 | "name": "python3" 410 | }, 411 | "language_info": { 412 | "codemirror_mode": { 413 | "name": "ipython", 414 | "version": 3 415 | }, 416 | "file_extension": ".py", 417 | "mimetype": "text/x-python", 418 | "name": "python", 419 | "nbconvert_exporter": "python", 420 | "pygments_lexer": "ipython3", 421 | "version": "3.6.5" 422 | } 423 | }, 424 | "nbformat": 4, 425 | "nbformat_minor": 2 426 | } 427 | -------------------------------------------------------------------------------- /BP算法.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## BP算法" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "### sigmoid 函数 " 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 15, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "import numpy as np\n", 24 | "import matplotlib.pyplot as plt" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "#### 前项计算\n", 32 | "$$ z_1 = W_1 * x$$ \n", 33 | "$$ z_2 = \\delta(z_1)$$\n", 34 | "$$ z_3 = W_2 * z_2$$\n", 35 | "$$ z_4 = \\delta(z_3)$$ \n", 36 | "$$ loss = (z_4 - real)^2 $$\n", 37 | "#### 已知\n", 38 | "$$ f(x) = \\delta(x) $$\n", 39 | "$$ f'(x) = \\delta(x)(1-\\delta(x)) $$\n", 40 | "#### 反向传播\n", 41 | "\n", 42 | "$$ \\delta_1 = \\frac{dloss}{dz_4} = 2z_4 - 2real $$\n", 43 | "$$ \\delta_2 = \\frac{dz_4}{dz_3} = \\delta(z_3)(1-\\delta(z_3)) $$\n", 44 | "$$ \\delta_3 = \\frac{dz_3}{dW_2} = z_2 $$\n", 45 | "$$ \\delta_4 = \\frac{dz_3}{dz_2} = W_2 $$\n", 46 | "$$ \\delta_5 = \\frac{dz_2}{dz_1} = \\delta(z_1)(1-\\delta(z_1)) $$\n", 47 | "$$ \\delta_6 = \\frac{dz_1}{dW_1} = z_1 $$\n", 48 | "\n", 49 | "#### 根据链式法则\n", 50 | "\n", 51 | "$$ W_2 = W_2 - \\eta \\delta_1 \\delta_2 \\delta_4 $$\n", 52 | "\n", 53 | "$$ W_2 = W_2 - \\eta \\delta_1 \\delta_2 \\delta_3 \\delta_5 \\delta_6$$" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 35, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "losses = []\n", 63 | "def sigmoid(x):#激活函数\n", 64 | " return 1/(1+np.exp(-x))\n", 65 | "input = np.array([[0.35], [0.9]]) #输入数据\n", 66 | "w1 = np.array([[0.1, 0.8], [0.4, 0.6]])#第一层权重参数\n", 67 | "w2 = np.array([0.3, 0.9])#第二层权重参数\n", 68 | " \n", 69 | "real = np.array([[0.5]])#真实值\n", 70 | "for s in range(0,1000,1):\n", 71 | " pq = sigmoid(np.dot(w1,input))#第一层输出\n", 72 | " output = sigmoid(np.dot(w2,pq))#第二层输出,也即是最终输出\n", 73 | " e = output-real #误差\n", 74 | " loss = np.square(e)/2\n", 75 | " losses.append(loss[0])\n", 76 | " if loss<1e-12:\n", 77 | " break\n", 78 | " else:\n", 79 | " #否则,按照梯度下降计算权重参数\n", 80 | " #其中,应用链式法则计算权重参数的更新量\n", 81 | " w2 = w2 - e*output*(1-output)*pq.T\n", 82 | " w1 = w1 - e*output*(1-output)*w2*pq.T*(1-pq.T)*input" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 36, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "name": "stdout", 92 | "output_type": "stream", 93 | "text": [ 94 | "[[0.10075115 0.75743519]\n", 95 | " [0.40193153 0.49054763]]\n", 96 | "[[-0.30384153 0.31823294]]\n", 97 | "[[0.50000137]]\n" 98 | ] 99 | } 100 | ], 101 | "source": [ 102 | "print(w1)\n", 103 | "print(w2) \n", 104 | "print(output)" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "### 结果" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 37, 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "data": { 121 | "text/plain": [ 122 | "[]" 123 | ] 124 | }, 125 | "execution_count": 37, 126 | "metadata": {}, 127 | "output_type": "execute_result" 128 | }, 129 | { 130 | "data": { 131 | "image/png": "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\n", 132 | "text/plain": [ 133 | "
" 134 | ] 135 | }, 136 | "metadata": {}, 137 | "output_type": "display_data" 138 | } 139 | ], 140 | "source": [ 141 | "x = np.arange(0,len(losses),1)\n", 142 | "plt.plot(x,losses,\"-\")" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "### relu 函数" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "#### 前项计算\n", 157 | "$$ z_1 = W_1 * x$$ \n", 158 | "$$ z_2 = relu(z_1)$$\n", 159 | "$$ z_3 = W_2 * z_2$$\n", 160 | "$$ z_4 = relu(z_3)$$ \n", 161 | "$$ loss = (z_4 - real)^2 $$\n", 162 | "#### 已知\n", 163 | "$$ f(x) = relu(x) $$\n", 164 | "###### 定义\n", 165 | "$$g(x) = \n", 166 | "\\left\\{\\begin{array}{cc} \n", 167 | "\t\t1, & x>0\\\\ \n", 168 | "\t\t0, & x\\leq 0 \n", 169 | "\\end{array}\\right.\n", 170 | "$$\n", 171 | "###### 则\n", 172 | "$$ f'(x) = g(x) $$\n", 173 | "#### 反向传播\n", 174 | "\n", 175 | "$$ \\delta_1 = \\frac{dloss}{dz_4} = 2z_4 - 2real $$\n", 176 | "$$ \\delta_2 = \\frac{dz_4}{dz_3} = g(z_3) $$\n", 177 | "$$ \\delta_3 = \\frac{dz_3}{dW_2} = z_2 $$\n", 178 | "$$ \\delta_4 = \\frac{dz_3}{dz_2} = W_2 $$\n", 179 | "$$ \\delta_5 = \\frac{dz_2}{dz_1} = g(z_1) $$\n", 180 | "$$ \\delta_6 = \\frac{dz_1}{dW_1} = z_1 $$\n", 181 | "\n", 182 | "#### 根据链式法则\n", 183 | "\n", 184 | "$$ W_2 = W_2 - \\eta \\delta_1 \\delta_2 \\delta_4 $$\n", 185 | "\n", 186 | "$$ W_2 = W_2 - \\eta \\delta_1 \\delta_2 \\delta_3 \\delta_5 \\delta_6$$" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": 38, 192 | "metadata": {}, 193 | "outputs": [], 194 | "source": [ 195 | "losses = []\n", 196 | "def relu(x):#激活函数\n", 197 | " x_index = x <= 0\n", 198 | " x[x_index] = 0\n", 199 | " return x\n", 200 | "\n", 201 | "def bp_relu(x):#激活函数求导结果\n", 202 | " x_index = x <= 0\n", 203 | " x[x_index] = 0\n", 204 | " x_index = x > 0\n", 205 | " x[x_index] = 1\n", 206 | " return x\n", 207 | "\n", 208 | "input = np.array([[0.35], [0.9]]) #输入数据\n", 209 | "w1 = np.array([[0.1, 0.8], [0.4, 0.6]])#第一层权重参数\n", 210 | "w2 = np.array([0.3, 0.9])#第二层权重参数\n", 211 | " \n", 212 | "real = np.array([[0.5]])#真实值\n", 213 | "for s in range(0,1000,1):\n", 214 | " pq = relu(np.dot(w1,input))#第一层输出\n", 215 | " output = relu(np.dot(w2,pq))#第二层输出,也即是最终输出\n", 216 | " e = output-real #误差\n", 217 | " loss = np.square(e)/2\n", 218 | " losses.append(loss[0])\n", 219 | " if loss<1e-12:\n", 220 | " break\n", 221 | " else:\n", 222 | " #否则,按照梯度下降计算权重参数\n", 223 | " #其中,应用链式法则计算权重参数的更新量\n", 224 | " w2 = w2 - e*bp_relu(output)*pq.T\n", 225 | " w1 = w1 - e*bp_relu(output)*w2*bp_relu(pq.T)*input" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 39, 231 | "metadata": {}, 232 | "outputs": [ 233 | { 234 | "name": "stdout", 235 | "output_type": "stream", 236 | "text": [ 237 | "[[0.10070437 0.75123983]\n", 238 | " [0.40181123 0.47461672]]\n", 239 | "[[0.12382036 0.72547718]]\n", 240 | "[[0.49999909]]\n" 241 | ] 242 | } 243 | ], 244 | "source": [ 245 | "print(w1)\n", 246 | "print(w2) \n", 247 | "print(output)" 248 | ] 249 | }, 250 | { 251 | "cell_type": "markdown", 252 | "metadata": {}, 253 | "source": [ 254 | "### 结果" 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "execution_count": 40, 260 | "metadata": {}, 261 | "outputs": [ 262 | { 263 | "data": { 264 | "text/plain": [ 265 | "[]" 266 | ] 267 | }, 268 | "execution_count": 40, 269 | "metadata": {}, 270 | "output_type": "execute_result" 271 | }, 272 | { 273 | "data": { 274 | "image/png": "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\n", 275 | "text/plain": [ 276 | "
" 277 | ] 278 | }, 279 | "metadata": {}, 280 | "output_type": "display_data" 281 | } 282 | ], 283 | "source": [ 284 | "x = np.arange(0,len(losses),1)\n", 285 | "plt.plot(x,losses,\"-\")" 286 | ] 287 | } 288 | ], 289 | "metadata": { 290 | "kernelspec": { 291 | "display_name": "Python 3", 292 | "language": "python", 293 | "name": "python3" 294 | }, 295 | "language_info": { 296 | "codemirror_mode": { 297 | "name": "ipython", 298 | "version": 3 299 | }, 300 | "file_extension": ".py", 301 | "mimetype": "text/x-python", 302 | "name": "python", 303 | "nbconvert_exporter": "python", 304 | "pygments_lexer": "ipython3", 305 | "version": "3.6.5" 306 | } 307 | }, 308 | "nbformat": 4, 309 | "nbformat_minor": 2 310 | } 311 | -------------------------------------------------------------------------------- /CNN手写字符识别.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## CNN手写字符识别" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 36, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import torch\n", 17 | "import torch.nn as nn\n", 18 | "from torch import optim\n", 19 | "from torch.autograd import Variable\n", 20 | "import torch.utils.data as Data\n", 21 | "import torchvision\n", 22 | "import numpy as np\n", 23 | "import matplotlib.pyplot as plt" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 28, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "# Hyper parameters\n", 33 | "EPOCH = 1\n", 34 | "BATCH_SIZE = 50\n", 35 | "LR = 0.001\n", 36 | "DOWNLOAD_MNIST = True\n", 37 | "learning_rate = 0.05" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "### 数据加载" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 29, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "train_data = torchvision.datasets.MNIST(\n", 54 | " root='./mnist',\n", 55 | " train=True,\n", 56 | " transform=torchvision.transforms.ToTensor(),\n", 57 | " download=DOWNLOAD_MNIST\n", 58 | ")\n", 59 | "\n", 60 | "#\n", 61 | "train_loader = Data.DataLoader(\n", 62 | " dataset=train_data,\n", 63 | " batch_size=BATCH_SIZE,\n", 64 | " shuffle=True,\n", 65 | " num_workers=2\n", 66 | ")\n", 67 | "\n", 68 | "test_data = torchvision.datasets.MNIST(\n", 69 | " root='./mnist',\n", 70 | " train=False,\n", 71 | " transform=torchvision.transforms.ToTensor(),\n", 72 | " download=DOWNLOAD_MNIST\n", 73 | ")\n", 74 | "\n", 75 | "test_loader = Data.DataLoader(\n", 76 | " dataset=test_data,\n", 77 | " batch_size=BATCH_SIZE,\n", 78 | " shuffle=False,\n", 79 | " num_workers=2\n", 80 | ")\n" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "metadata": {}, 86 | "source": [ 87 | "### CNN" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 30, 93 | "metadata": {}, 94 | "outputs": [], 95 | "source": [ 96 | "class CNN(nn.Module):\n", 97 | " def __init__(self):\n", 98 | " super(CNN, self).__init__()\n", 99 | " self.layer1 = nn.Sequential(\n", 100 | " nn.Conv2d(1, 25, kernel_size=3),\n", 101 | " nn.BatchNorm2d(25),\n", 102 | " nn.ReLU(inplace=True)\n", 103 | " )\n", 104 | "\n", 105 | " self.layer2 = nn.Sequential(\n", 106 | " nn.MaxPool2d(kernel_size=2, stride=2)\n", 107 | " )\n", 108 | "\n", 109 | " self.layer3 = nn.Sequential(\n", 110 | " nn.Conv2d(25, 50, kernel_size=3),\n", 111 | " nn.BatchNorm2d(50),\n", 112 | " nn.ReLU(inplace=True)\n", 113 | " )\n", 114 | "\n", 115 | " self.layer4 = nn.Sequential(\n", 116 | " nn.MaxPool2d(kernel_size=2, stride=2)\n", 117 | " )\n", 118 | "\n", 119 | " self.fc = nn.Sequential(\n", 120 | " nn.Linear(50 * 5 * 5, 1024),\n", 121 | " nn.ReLU(inplace=True),\n", 122 | " nn.Linear(1024, 128),\n", 123 | " nn.ReLU(inplace=True),\n", 124 | " nn.Linear(128, 10)\n", 125 | " )\n", 126 | "\n", 127 | " def forward(self, x):\n", 128 | " x = self.layer1(x)\n", 129 | " x = self.layer2(x)\n", 130 | " x = self.layer3(x)\n", 131 | " x = self.layer4(x)\n", 132 | " x = x.view(x.size(0), -1)\n", 133 | " x = self.fc(x)\n", 134 | " return x\n" 135 | ] 136 | }, 137 | { 138 | "cell_type": "markdown", 139 | "metadata": {}, 140 | "source": [ 141 | "### 训练" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": 48, 147 | "metadata": {}, 148 | "outputs": [ 149 | { 150 | "name": "stdout", 151 | "output_type": "stream", 152 | "text": [ 153 | "epoch: 50, loss: 1.055 , acc : 0.74\n", 154 | "epoch: 100, loss: 0.3286 , acc : 0.94\n", 155 | "epoch: 150, loss: 0.213 , acc : 0.9\n", 156 | "epoch: 200, loss: 0.1972 , acc : 0.92\n", 157 | "epoch: 250, loss: 0.2012 , acc : 0.94\n", 158 | "epoch: 300, loss: 0.1404 , acc : 0.98\n", 159 | "epoch: 350, loss: 0.08106 , acc : 0.96\n", 160 | "epoch: 400, loss: 0.06412 , acc : 1.0\n", 161 | "epoch: 450, loss: 0.09025 , acc : 0.96\n", 162 | "epoch: 500, loss: 0.04844 , acc : 1.0\n", 163 | "epoch: 550, loss: 0.07852 , acc : 0.98\n", 164 | "epoch: 600, loss: 0.1218 , acc : 0.96\n", 165 | "epoch: 650, loss: 0.06274 , acc : 0.96\n", 166 | "epoch: 700, loss: 0.2031 , acc : 0.96\n", 167 | "epoch: 750, loss: 0.09254 , acc : 0.96\n", 168 | "epoch: 800, loss: 0.02973 , acc : 1.0\n", 169 | "epoch: 850, loss: 0.1219 , acc : 0.94\n", 170 | "epoch: 900, loss: 0.0804 , acc : 0.96\n", 171 | "epoch: 950, loss: 0.02437 , acc : 1.0\n", 172 | "epoch: 1000, loss: 0.03325 , acc : 0.98\n", 173 | "epoch: 1050, loss: 0.05944 , acc : 0.98\n", 174 | "epoch: 1100, loss: 0.008377 , acc : 1.0\n", 175 | "epoch: 1150, loss: 0.02196 , acc : 1.0\n", 176 | "epoch: 1200, loss: 0.1424 , acc : 0.96\n" 177 | ] 178 | } 179 | ], 180 | "source": [ 181 | "losses = []\n", 182 | "acces = []\n", 183 | "\n", 184 | "# 选择模型\n", 185 | "model = CNN()\n", 186 | "# model = net.Activation_Net(28 * 28, 300, 100, 10)\n", 187 | "# model = net.Batch_Net(28 * 28, 300, 100, 10)\n", 188 | "if torch.cuda.is_available():\n", 189 | " model = model.cuda()\n", 190 | "\n", 191 | "# 定义损失函数和优化器\n", 192 | "criterion = nn.CrossEntropyLoss()\n", 193 | "optimizer = optim.SGD(model.parameters(), lr=learning_rate)\n", 194 | "\n", 195 | "# 训练模型\n", 196 | "epoch = 0\n", 197 | "for data in train_loader:\n", 198 | " img, label = data\n", 199 | " # img = img.view(img.size(0), -1)\n", 200 | " img = Variable(img)\n", 201 | " if torch.cuda.is_available():\n", 202 | " img = img.cuda()\n", 203 | " label = label.cuda()\n", 204 | " else:\n", 205 | " img = Variable(img)\n", 206 | " label = Variable(label)\n", 207 | " out = model(img)\n", 208 | " loss = criterion(out, label)\n", 209 | " print_loss = loss.data.item()\n", 210 | " \n", 211 | " _, pred = torch.max(out, 1)\n", 212 | " num_correct = (pred == label).sum()\n", 213 | " eval_acc = num_correct.item()/len(pred)\n", 214 | " \n", 215 | " optimizer.zero_grad()\n", 216 | " loss.backward()\n", 217 | " optimizer.step()\n", 218 | " epoch+=1\n", 219 | " losses.append(loss.data.item())\n", 220 | " acces.append(eval_acc)\n", 221 | " if epoch%50 == 0:\n", 222 | " print('epoch: {}, loss: {:.4} , acc : {}'.format(epoch, loss.data.item(),eval_acc))\n" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 49, 228 | "metadata": {}, 229 | "outputs": [ 230 | { 231 | "name": "stdout", 232 | "output_type": "stream", 233 | "text": [ 234 | "Test Loss: 0.053868, Acc: 0.982600\n" 235 | ] 236 | } 237 | ], 238 | "source": [ 239 | "# 模型评估\n", 240 | "model.eval()\n", 241 | "eval_loss = 0\n", 242 | "eval_acc = 0\n", 243 | "for data in test_loader:\n", 244 | " img, label = data\n", 245 | " # img = img.view(img.size(0), -1)\n", 246 | " img = Variable(img)\n", 247 | " if torch.cuda.is_available():\n", 248 | " img = img.cuda()\n", 249 | " label = label.cuda()\n", 250 | "\n", 251 | " out = model(img)\n", 252 | " loss = criterion(out, label)\n", 253 | " eval_loss += loss.data.item()*label.size(0)\n", 254 | " _, pred = torch.max(out, 1)\n", 255 | " num_correct = (pred == label).sum()\n", 256 | " eval_acc += num_correct.item()\n", 257 | "print('Test Loss: {:.6f}, Acc: {:.6f}'.format(\n", 258 | " eval_loss / (len(test_data)),\n", 259 | " eval_acc / (len(test_data))\n", 260 | "))" 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "execution_count": 50, 266 | "metadata": {}, 267 | "outputs": [ 268 | { 269 | "data": { 270 | "text/plain": [ 271 | "[]" 272 | ] 273 | }, 274 | "execution_count": 50, 275 | "metadata": {}, 276 | "output_type": "execute_result" 277 | }, 278 | { 279 | "data": { 280 | "image/png": "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\n", 281 | "text/plain": [ 282 | "
" 283 | ] 284 | }, 285 | "metadata": {}, 286 | "output_type": "display_data" 287 | } 288 | ], 289 | "source": [ 290 | "x = np.arange(0,len(losses),1)\n", 291 | "plt.plot(x,losses,\"-\")" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 51, 297 | "metadata": {}, 298 | "outputs": [ 299 | { 300 | "data": { 301 | "text/plain": [ 302 | "[]" 303 | ] 304 | }, 305 | "execution_count": 51, 306 | "metadata": {}, 307 | "output_type": "execute_result" 308 | }, 309 | { 310 | "data": { 311 | "image/png": "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\n", 312 | "text/plain": [ 313 | "
" 314 | ] 315 | }, 316 | "metadata": {}, 317 | "output_type": "display_data" 318 | } 319 | ], 320 | "source": [ 321 | "x = np.arange(0,len(acces),1)\n", 322 | "plt.plot(x,acces,\"-\")" 323 | ] 324 | } 325 | ], 326 | "metadata": { 327 | "kernelspec": { 328 | "display_name": "Python 3", 329 | "language": "python", 330 | "name": "python3" 331 | }, 332 | "language_info": { 333 | "codemirror_mode": { 334 | "name": "ipython", 335 | "version": 3 336 | }, 337 | "file_extension": ".py", 338 | "mimetype": "text/x-python", 339 | "name": "python", 340 | "nbconvert_exporter": "python", 341 | "pygments_lexer": "ipython3", 342 | "version": "3.6.5" 343 | } 344 | }, 345 | "nbformat": 4, 346 | "nbformat_minor": 2 347 | } 348 | -------------------------------------------------------------------------------- /Discrete_Hopfield_Network.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Discrete Hopfield Network(离散Hopfield网络)" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [ 15 | { 16 | "name": "stderr", 17 | "output_type": "stream", 18 | "text": [ 19 | "/dl_data/zhouyang/anaconda3/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n", 20 | " from ._conv import register_converters as _register_converters\n" 21 | ] 22 | } 23 | ], 24 | "source": [ 25 | "import numpy as np\n", 26 | "from neupy import algorithms" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "def draw_bin_image(image_matrix):\n", 36 | " for row in image_matrix.tolist():\n", 37 | " print('| ' + ' '.join(' *'[val] for val in row))" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 150, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "def add_noise(x,threshold):\n", 47 | " if len(x.shape) >2:\n", 48 | " for i in range(x.shape[1]):\n", 49 | " random_c = np.random.randint(0,1000)\n", 50 | " if random_c < threshold*1000:\n", 51 | " x[0,i] = 1-x[0,i]\n", 52 | " else:\n", 53 | " for i in range(len(x)):\n", 54 | " random_c = np.random.randint(0,1000)\n", 55 | " if random_c < threshold*1000:\n", 56 | " x[i] = 1-x[i]\n", 57 | " return x" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 136, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "zero = np.matrix([\n", 67 | " 0, 1, 1, 1, 0,\n", 68 | " 1, 0, 0, 0, 1,\n", 69 | " 1, 0, 0, 0, 1,\n", 70 | " 1, 0, 0, 0, 1,\n", 71 | " 1, 0, 0, 0, 1,\n", 72 | " 0, 1, 1, 1, 0\n", 73 | "])\n", 74 | "one = np.matrix([\n", 75 | " 0, 1, 1, 0, 0,\n", 76 | " 0, 0, 1, 0, 0,\n", 77 | " 0, 0, 1, 0, 0,\n", 78 | " 0, 0, 1, 0, 0,\n", 79 | " 0, 0, 1, 0, 0,\n", 80 | " 0, 0, 1, 0, 0\n", 81 | "])\n", 82 | "two = np.matrix([\n", 83 | " 1, 1, 1, 0, 0,\n", 84 | " 0, 0, 0, 1, 0,\n", 85 | " 0, 0, 0, 1, 0,\n", 86 | " 0, 1, 1, 0, 0,\n", 87 | " 1, 0, 0, 0, 0,\n", 88 | " 1, 1, 1, 1, 1,\n", 89 | "])" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 4, 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "name": "stdout", 99 | "output_type": "stream", 100 | "text": [ 101 | "| * * * \n", 102 | "| * *\n", 103 | "| * *\n", 104 | "| * *\n", 105 | "| * *\n", 106 | "| * * * \n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "draw_bin_image(zero.reshape((6, 5)))" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "## Hopfield 训练与使用\n", 119 | "* 训练:即简单拟合\n", 120 | "* 使用:噪声数据输入 激活对应部分 输出" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 15, 126 | "metadata": {}, 127 | "outputs": [], 128 | "source": [ 129 | "data = np.concatenate([zero, one, two], axis=0)\n", 130 | "dhnet = algorithms.DiscreteHopfieldNetwork(mode='sync')\n", 131 | "dhnet.train(data)" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 7, 137 | "metadata": {}, 138 | "outputs": [ 139 | { 140 | "name": "stdout", 141 | "output_type": "stream", 142 | "text": [ 143 | "| * * * \n", 144 | "| * *\n", 145 | "| * *\n", 146 | "| \n", 147 | "| \n", 148 | "| \n" 149 | ] 150 | } 151 | ], 152 | "source": [ 153 | "half_zero = np.matrix([\n", 154 | " 0, 1, 1, 1, 0,\n", 155 | " 1, 0, 0, 0, 1,\n", 156 | " 1, 0, 0, 0, 1,\n", 157 | " 0, 0, 0, 0, 0,\n", 158 | " 0, 0, 0, 0, 0,\n", 159 | " 0, 0, 0, 0, 0,\n", 160 | "])\n", 161 | "draw_bin_image(half_zero.reshape((6, 5)))\n" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 8, 167 | "metadata": {}, 168 | "outputs": [ 169 | { 170 | "name": "stdout", 171 | "output_type": "stream", 172 | "text": [ 173 | "| \n", 174 | "| \n", 175 | "| \n", 176 | "| * * \n", 177 | "| * \n", 178 | "| * * * * *\n" 179 | ] 180 | } 181 | ], 182 | "source": [ 183 | "half_two = np.matrix([\n", 184 | " 0, 0, 0, 0, 0,\n", 185 | " 0, 0, 0, 0, 0,\n", 186 | " 0, 0, 0, 0, 0,\n", 187 | " 0, 1, 1, 0, 0,\n", 188 | " 1, 0, 0, 0, 0,\n", 189 | " 1, 1, 1, 1, 1,\n", 190 | "])\n", 191 | "draw_bin_image(half_two.reshape((6, 5)))" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 10, 197 | "metadata": {}, 198 | "outputs": [ 199 | { 200 | "name": "stdout", 201 | "output_type": "stream", 202 | "text": [ 203 | "| * * * \n", 204 | "| * *\n", 205 | "| * *\n", 206 | "| * *\n", 207 | "| * *\n", 208 | "| * * * \n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "result = dhnet.predict(half_zero)\n", 214 | "draw_bin_image(result.reshape((6, 5)))" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": 11, 220 | "metadata": {}, 221 | "outputs": [ 222 | { 223 | "name": "stdout", 224 | "output_type": "stream", 225 | "text": [ 226 | "| * * * \n", 227 | "| * \n", 228 | "| * \n", 229 | "| * * \n", 230 | "| * \n", 231 | "| * * * * *\n" 232 | ] 233 | } 234 | ], 235 | "source": [ 236 | "result = dhnet.predict(half_two)\n", 237 | "draw_bin_image(result.reshape((6, 5)))" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": 12, 243 | "metadata": {}, 244 | "outputs": [ 245 | { 246 | "name": "stdout", 247 | "output_type": "stream", 248 | "text": [ 249 | "| * * \n", 250 | "| * \n", 251 | "| * \n", 252 | "| * * \n", 253 | "| * * \n", 254 | "| * * * * *\n" 255 | ] 256 | } 257 | ], 258 | "source": [ 259 | "half_two = np.matrix([\n", 260 | " 1, 1, 1, 0, 0,\n", 261 | " 0, 0, 0, 1, 0,\n", 262 | " 0, 0, 0, 1, 0,\n", 263 | " 0, 0, 0, 0, 0,\n", 264 | " 0, 0, 0, 0, 0,\n", 265 | " 0, 0, 0, 0, 0,\n", 266 | "])\n", 267 | "\n", 268 | "result = dhnet.predict(half_two)\n", 269 | "draw_bin_image(result.reshape((6, 5)))" 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": 116, 275 | "metadata": {}, 276 | "outputs": [ 277 | { 278 | "name": "stdout", 279 | "output_type": "stream", 280 | "text": [ 281 | "| * * *\n", 282 | "| * * \n", 283 | "| * * * \n", 284 | "| * \n", 285 | "| * * \n", 286 | "| * * * \n" 287 | ] 288 | } 289 | ], 290 | "source": [ 291 | "noise_two = add_noise(two,0.2)\n", 292 | "draw_bin_image(noise_two.reshape(6,5))" 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": 117, 298 | "metadata": {}, 299 | "outputs": [ 300 | { 301 | "name": "stdout", 302 | "output_type": "stream", 303 | "text": [ 304 | "| * * \n", 305 | "| * \n", 306 | "| * \n", 307 | "| * * \n", 308 | "| * * \n", 309 | "| * * * * *\n" 310 | ] 311 | } 312 | ], 313 | "source": [ 314 | "result = dhnet.predict(half_two)\n", 315 | "draw_bin_image(result.reshape((6, 5)))" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "## Hopfield 实现" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": 137, 328 | "metadata": {}, 329 | "outputs": [], 330 | "source": [ 331 | "\n", 332 | "class HOP(object):\n", 333 | " def __init__(self, N):\n", 334 | "\n", 335 | " self.N = N\n", 336 | " # Weight Matrix\n", 337 | " self.W = np.zeros((N, N), dtype = floatType)\n", 338 | "\n", 339 | "\n", 340 | " def kroneckerSquareProduct(self, factor):\n", 341 | " ksProduct = np.zeros((self.N, self.N), dtype = floatType)\n", 342 | "\n", 343 | " \n", 344 | " for i in range(0, self.N):\n", 345 | " ksProduct[i] = factor[i] * factor\n", 346 | "\n", 347 | " return ksProduct\n", 348 | "\n", 349 | "\n", 350 | " def trainOnce(self, inputArray):\n", 351 | "\n", 352 | " mean = float(inputArray.sum()) / inputArray.shape[0]\n", 353 | " self.W = self.W + self.kroneckerSquareProduct(inputArray - mean) / (self.N * self.N) / mean / (1 - mean)\n", 354 | "\n", 355 | "\n", 356 | " index = range(0, self.N)\n", 357 | " self.W[index, index] = 0.\n", 358 | "\n", 359 | " def hopTrain(self, stableStateList):\n", 360 | "\n", 361 | " stableState = np.asarray(stableStateList, dtype = uintType)\n", 362 | "\n", 363 | "\n", 364 | " if np.amin(stableState) < 0 or np.amax(stableState) > 1:\n", 365 | " print ('Vector Range ERROR!')\n", 366 | " return\n", 367 | "\n", 368 | " print(stableState.shape,\"shape\")\n", 369 | " if len(stableState.shape) == 1 and stableState.shape[0] == self.N:\n", 370 | " print ('stableState count: 1')\n", 371 | " self.trainOnce(stableState)\n", 372 | " elif len(stableState.shape) == 2 and stableState.shape[1] == self.N:\n", 373 | " print ('stableState count: ' + str(stableState.shape[0])) \n", 374 | " for i in range(0, stableState.shape[0]):\n", 375 | " self.trainOnce(stableState[i])\n", 376 | " else:\n", 377 | " print ('SS Dimension ERROR! Training Aborted.')\n", 378 | " return\n", 379 | " print ('Hopfield Training Complete.')\n", 380 | "\n", 381 | " def hopRun(self, inputList):\n", 382 | "\n", 383 | " inputArray = np.asarray(inputList, dtype = floatType)\n", 384 | " inputArray = inputArray.squeeze()\n", 385 | "\n", 386 | " if len(inputArray.shape) != 1 or inputArray.shape[0] != self.N:\n", 387 | " print ('Input Dimension ERROR! Runing Aborted.')\n", 388 | " return\n", 389 | "\n", 390 | "\n", 391 | " matrix = np.tile(inputArray, (self.N, 1))\n", 392 | " matrix = self.W * matrix\n", 393 | " ouputArray = matrix.sum(1)\n", 394 | "\n", 395 | " m = float(np.amin(ouputArray))\n", 396 | " M = float(np.amax(ouputArray))\n", 397 | " ouputArray = (ouputArray - m) / (M - m)\n", 398 | "\n", 399 | "\n", 400 | " ouputArray[ouputArray < 0.5] = 0.\n", 401 | " ouputArray[ouputArray > 0] = 1.\n", 402 | "\n", 403 | " return np.asarray(ouputArray, dtype = uintType)\n", 404 | "\n", 405 | "\n", 406 | " def hopReset(self):\n", 407 | "\n", 408 | " self.W = np.zeros((self.N, self.N), dtype = floatType)" 409 | ] 410 | }, 411 | { 412 | "cell_type": "code", 413 | "execution_count": 138, 414 | "metadata": {}, 415 | "outputs": [], 416 | "source": [ 417 | "uintType = np.uint8\n", 418 | "floatType = np.float32\n", 419 | "hop = HOP(5 * 6)" 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": 139, 425 | "metadata": {}, 426 | "outputs": [ 427 | { 428 | "name": "stdout", 429 | "output_type": "stream", 430 | "text": [ 431 | "(3, 30) shape\n", 432 | "stableState count: 3\n", 433 | "Hopfield Training Complete.\n" 434 | ] 435 | } 436 | ], 437 | "source": [ 438 | "hop.hopTrain([zero, one, two])" 439 | ] 440 | }, 441 | { 442 | "cell_type": "code", 443 | "execution_count": 140, 444 | "metadata": {}, 445 | "outputs": [ 446 | { 447 | "name": "stdout", 448 | "output_type": "stream", 449 | "text": [ 450 | "| * * * \n", 451 | "| * \n", 452 | "| * \n", 453 | "| \n", 454 | "| \n", 455 | "| \n" 456 | ] 457 | } 458 | ], 459 | "source": [ 460 | "draw_bin_image(half_two.reshape((6, 5)))" 461 | ] 462 | }, 463 | { 464 | "cell_type": "code", 465 | "execution_count": 141, 466 | "metadata": {}, 467 | "outputs": [ 468 | { 469 | "name": "stdout", 470 | "output_type": "stream", 471 | "text": [ 472 | "| * * * \n", 473 | "| * \n", 474 | "| * \n", 475 | "| * * \n", 476 | "| * \n", 477 | "| * * * * *\n" 478 | ] 479 | } 480 | ], 481 | "source": [ 482 | "result = hop.hopRun(half_two)\n", 483 | "draw_bin_image(result.reshape((6, 5)))" 484 | ] 485 | }, 486 | { 487 | "cell_type": "code", 488 | "execution_count": 142, 489 | "metadata": {}, 490 | "outputs": [ 491 | { 492 | "name": "stdout", 493 | "output_type": "stream", 494 | "text": [ 495 | "| * * * \n", 496 | "| * \n", 497 | "| * * \n", 498 | "| * * * \n", 499 | "| * \n", 500 | "| * * *\n" 501 | ] 502 | } 503 | ], 504 | "source": [ 505 | "noise_two = add_noise(two,0.2)\n", 506 | "draw_bin_image(noise_two.reshape(6,5))" 507 | ] 508 | }, 509 | { 510 | "cell_type": "code", 511 | "execution_count": 143, 512 | "metadata": {}, 513 | "outputs": [ 514 | { 515 | "name": "stdout", 516 | "output_type": "stream", 517 | "text": [ 518 | "| * * * \n", 519 | "| * \n", 520 | "| * \n", 521 | "| * * \n", 522 | "| * \n", 523 | "| * * * * *\n" 524 | ] 525 | } 526 | ], 527 | "source": [ 528 | "result = hop.hopRun(noise_two)\n", 529 | "draw_bin_image(result.reshape((6, 5)))" 530 | ] 531 | }, 532 | { 533 | "cell_type": "code", 534 | "execution_count": 144, 535 | "metadata": {}, 536 | "outputs": [ 537 | { 538 | "name": "stdout", 539 | "output_type": "stream", 540 | "text": [ 541 | "| * * * \n", 542 | "| * * *\n", 543 | "| * * *\n", 544 | "| * *\n", 545 | "| * * *\n", 546 | "| * * \n" 547 | ] 548 | } 549 | ], 550 | "source": [ 551 | "noise_zero = add_noise(zero,0.2)\n", 552 | "draw_bin_image(noise_zero.reshape(6,5))" 553 | ] 554 | }, 555 | { 556 | "cell_type": "code", 557 | "execution_count": 146, 558 | "metadata": {}, 559 | "outputs": [ 560 | { 561 | "name": "stdout", 562 | "output_type": "stream", 563 | "text": [ 564 | "| * * * \n", 565 | "| * *\n", 566 | "| * *\n", 567 | "| * *\n", 568 | "| * *\n", 569 | "| * * * \n" 570 | ] 571 | } 572 | ], 573 | "source": [ 574 | "result = hop.hopRun(noise_zero)\n", 575 | "draw_bin_image(result.reshape((6, 5)))" 576 | ] 577 | }, 578 | { 579 | "cell_type": "markdown", 580 | "metadata": {}, 581 | "source": [ 582 | "## Mnist 手写数字" 583 | ] 584 | }, 585 | { 586 | "cell_type": "code", 587 | "execution_count": 156, 588 | "metadata": {}, 589 | "outputs": [ 590 | { 591 | "name": "stdout", 592 | "output_type": "stream", 593 | "text": [ 594 | "Extracting MNIST_data/train-images-idx3-ubyte.gz\n", 595 | "Extracting MNIST_data/train-labels-idx1-ubyte.gz\n", 596 | "Extracting MNIST_data/t10k-images-idx3-ubyte.gz\n", 597 | "Extracting MNIST_data/t10k-labels-idx1-ubyte.gz\n" 598 | ] 599 | } 600 | ], 601 | "source": [ 602 | "import tensorflow as tf\n", 603 | "from tensorflow.examples.tutorials.mnist import input_data\n", 604 | "from matplotlib import pyplot as plt\n", 605 | "# 获取数据\n", 606 | "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot=True)" 607 | ] 608 | }, 609 | { 610 | "cell_type": "code", 611 | "execution_count": 160, 612 | "metadata": {}, 613 | "outputs": [ 614 | { 615 | "data": { 616 | "image/png": "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\n", 617 | "text/plain": [ 618 | "
" 619 | ] 620 | }, 621 | "metadata": {}, 622 | "output_type": "display_data" 623 | }, 624 | { 625 | "data": { 626 | "image/png": "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\n", 627 | "text/plain": [ 628 | "
" 629 | ] 630 | }, 631 | "metadata": {}, 632 | "output_type": "display_data" 633 | }, 634 | { 635 | "name": "stdout", 636 | "output_type": "stream", 637 | "text": [ 638 | "| \n", 639 | "| \n", 640 | "| \n", 641 | "| \n", 642 | "| \n", 643 | "| * * * * * * * * * * \n", 644 | "| * * * * * * * * * * * * \n", 645 | "| * * * * * * * * * * * * \n", 646 | "| * * * * * * * * * * \n", 647 | "| * * * * * * * * * \n", 648 | "| * * * * * * * * * \n", 649 | "| * * * * * * * * \n", 650 | "| * * * * * * * * \n", 651 | "| * * * * * * * * \n", 652 | "| * * * * * * * * \n", 653 | "| * * * * * * * * \n", 654 | "| * * * * * * * * \n", 655 | "| * * * * * * * * \n", 656 | "| * * * * * * * * * \n", 657 | "| * * * * * * * * * \n", 658 | "| * * * * * * * * * \n", 659 | "| * * * * * * * * * * * \n", 660 | "| * * * * * * * * * * * * \n", 661 | "| * * * * * * * * * * * \n", 662 | "| * * * * * * * * \n", 663 | "| \n", 664 | "| \n", 665 | "| \n" 666 | ] 667 | } 668 | ], 669 | "source": [ 670 | "eight = mnist.train.images[5]>0\n", 671 | "one = mnist.train.images[6]>0\n", 672 | "nine = mnist.train.images[8]>0\n", 673 | "zero = mnist.train.images[10]>0\n", 674 | "plt.imshow(one.reshape(28,28))\n", 675 | "plt.show()\n", 676 | "plt.imshow(mnist.train.images[6].reshape(28,28))\n", 677 | "plt.show()\n", 678 | "draw_bin_image(zero.reshape(28,28)>0)" 679 | ] 680 | }, 681 | { 682 | "cell_type": "code", 683 | "execution_count": 148, 684 | "metadata": {}, 685 | "outputs": [ 686 | { 687 | "name": "stdout", 688 | "output_type": "stream", 689 | "text": [ 690 | "(4, 784) shape\n", 691 | "stableState count: 4\n", 692 | "Hopfield Training Complete.\n" 693 | ] 694 | } 695 | ], 696 | "source": [ 697 | "hop = HOP(28 * 28)\n", 698 | "hop.hopTrain([one, nine, zero,eight])" 699 | ] 700 | }, 701 | { 702 | "cell_type": "code", 703 | "execution_count": 151, 704 | "metadata": {}, 705 | "outputs": [ 706 | { 707 | "name": "stdout", 708 | "output_type": "stream", 709 | "text": [ 710 | "| * * * \n", 711 | "| * * * * * * \n", 712 | "| * * * * * * \n", 713 | "| * * * * * * * \n", 714 | "| * * * * \n", 715 | "| * * * * * * * * * * * * \n", 716 | "| * * * * * * * * * * * * * \n", 717 | "| * * * * * * * * * * * * * * \n", 718 | "| * * * * * * * * * * * * * * \n", 719 | "| * * * * * * * * *\n", 720 | "| * * * * * * * * * * * * * * \n", 721 | "| * * * * * * * * * * * \n", 722 | "| * * * * * * * * * * * * * * * * * \n", 723 | "| * * * * * * * * \n", 724 | "| * * * * * * * * \n", 725 | "| * * * * * * * * \n", 726 | "| * * * * * * * * * * * * * * * * *\n", 727 | "| * * * * * * * * * * * \n", 728 | "| * * * * * * * * \n", 729 | "| * * * * * * * * * * * * * * \n", 730 | "| * * * * * * * * *\n", 731 | "| * * * * * * * * * * * * * \n", 732 | "| * * * * * * * * * * * \n", 733 | "| * * * * * * * * * * * * * * * * * *\n", 734 | "| * * * * * * * * * * * *\n", 735 | "| * * * * \n", 736 | "| * * * * * * * * \n", 737 | "| * * * \n" 738 | ] 739 | } 740 | ], 741 | "source": [ 742 | "noise_zero = add_noise(zero,0.2)\n", 743 | "draw_bin_image(noise_zero.reshape(28,28))" 744 | ] 745 | }, 746 | { 747 | "cell_type": "code", 748 | "execution_count": 153, 749 | "metadata": {}, 750 | "outputs": [ 751 | { 752 | "name": "stdout", 753 | "output_type": "stream", 754 | "text": [ 755 | "| \n", 756 | "| \n", 757 | "| \n", 758 | "| \n", 759 | "| \n", 760 | "| * * * * * * * * * * \n", 761 | "| * * * * * * * * * * * * \n", 762 | "| * * * * * * * * * * * * \n", 763 | "| * * * * * * * * * * \n", 764 | "| * * * * * * * * * \n", 765 | "| * * * * * * * * * \n", 766 | "| * * * * * * * * \n", 767 | "| * * * * * * * * \n", 768 | "| * * * * * * * * \n", 769 | "| * * * * * * * * \n", 770 | "| * * * * * * * * \n", 771 | "| * * * * * * * * \n", 772 | "| * * * * * * * * \n", 773 | "| * * * * * * * * * \n", 774 | "| * * * * * * * * * \n", 775 | "| * * * * * * * * * \n", 776 | "| * * * * * * * * * * * \n", 777 | "| * * * * * * * * * * * * \n", 778 | "| * * * * * * * * * * * \n", 779 | "| * * * * * * * * \n", 780 | "| \n", 781 | "| \n", 782 | "| \n" 783 | ] 784 | } 785 | ], 786 | "source": [ 787 | "result = hop.hopRun(noise_zero)\n", 788 | "draw_bin_image(result.reshape((28, 28)))" 789 | ] 790 | }, 791 | { 792 | "cell_type": "code", 793 | "execution_count": 154, 794 | "metadata": {}, 795 | "outputs": [ 796 | { 797 | "name": "stdout", 798 | "output_type": "stream", 799 | "text": [ 800 | "| * * * * * * * \n", 801 | "| * * \n", 802 | "| * * * * * *\n", 803 | "| * * * * * * \n", 804 | "| * * * * * * \n", 805 | "| * * * * * * * * \n", 806 | "| * * * * * * * * * * * * \n", 807 | "| * * * * * * * * * * * * * * \n", 808 | "| * * * * * * * * * * * * * * \n", 809 | "| * * * * * * * * * * \n", 810 | "| * * * * * * * *\n", 811 | "| * * * * * * * * * * * \n", 812 | "| * * * * * * * * * \n", 813 | "| * * * * * * * * * * * * * \n", 814 | "| * * * * * * * * * * * \n", 815 | "| * * * * * * * * * * \n", 816 | "| * * * * * * * * * * * \n", 817 | "| * * * * * * * * * * * * * * * \n", 818 | "| * * * * * * * * * * * * \n", 819 | "| * * * * * * * * * * \n", 820 | "| * * * * * * * * * * * * * * \n", 821 | "| * * * * * * * * * * * * * * * \n", 822 | "| * * * * * * * * * * *\n", 823 | "| * * * * * * * * * * *\n", 824 | "| * * * * * * * * * * * * \n", 825 | "| * * * * * \n", 826 | "| * * * * * \n", 827 | "| * * * * * * * * * *\n" 828 | ] 829 | } 830 | ], 831 | "source": [ 832 | "noise_eight = add_noise(eight,0.2)\n", 833 | "draw_bin_image(noise_eight.reshape(28,28))" 834 | ] 835 | }, 836 | { 837 | "cell_type": "code", 838 | "execution_count": 155, 839 | "metadata": {}, 840 | "outputs": [ 841 | { 842 | "name": "stdout", 843 | "output_type": "stream", 844 | "text": [ 845 | "| \n", 846 | "| \n", 847 | "| \n", 848 | "| \n", 849 | "| \n", 850 | "| * * * * * \n", 851 | "| * * * * * * * * \n", 852 | "| * * * * * * * * * \n", 853 | "| * * * * * * * * * * * \n", 854 | "| * * * * * * * \n", 855 | "| * * * * * * * \n", 856 | "| * * * * * * * \n", 857 | "| * * * * * * * \n", 858 | "| * * * * * * * * \n", 859 | "| * * * * * * * * \n", 860 | "| * * * * * * * * \n", 861 | "| * * * * * * * * * * \n", 862 | "| * * * * * * * * * * * \n", 863 | "| * * * * * * * * * * \n", 864 | "| * * * * * * * \n", 865 | "| * * * * * * * \n", 866 | "| * * * * * * * * * * * \n", 867 | "| * * * * * * * * * * * \n", 868 | "| * * * * * * * * * \n", 869 | "| * * * * * \n", 870 | "| \n", 871 | "| \n", 872 | "| \n" 873 | ] 874 | } 875 | ], 876 | "source": [ 877 | "result = hop.hopRun(noise_eight)\n", 878 | "draw_bin_image(result.reshape((28, 28)))" 879 | ] 880 | }, 881 | { 882 | "cell_type": "markdown", 883 | "metadata": {}, 884 | "source": [ 885 | "### 使用mnist 相同数字但是不同图像作为“噪声”输入" 886 | ] 887 | }, 888 | { 889 | "cell_type": "code", 890 | "execution_count": 180, 891 | "metadata": {}, 892 | "outputs": [ 893 | { 894 | "data": { 895 | "image/png": "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\n", 896 | "text/plain": [ 897 | "
" 898 | ] 899 | }, 900 | "metadata": {}, 901 | "output_type": "display_data" 902 | }, 903 | { 904 | "name": "stdout", 905 | "output_type": "stream", 906 | "text": [ 907 | "| \n", 908 | "| \n", 909 | "| \n", 910 | "| \n", 911 | "| \n", 912 | "| \n", 913 | "| * * * * * * * * * \n", 914 | "| * * * * * * * * * * * * \n", 915 | "| * * * * * * * * * * * * * * \n", 916 | "| * * * * * * * * * * * * \n", 917 | "| * * * * * * * * * * * * * * \n", 918 | "| * * * * * * * * * * * * * * * * * \n", 919 | "| * * * * * * * * * * * * * * \n", 920 | "| * * * * * * * * * * * \n", 921 | "| * * * * * * * * * \n", 922 | "| * * * * * * * * * * \n", 923 | "| * * * * * * * * * \n", 924 | "| * * * * * * * * * \n", 925 | "| * * * * * * * \n", 926 | "| * * * * * * \n", 927 | "| * * * * * * * \n", 928 | "| * * * * * * * \n", 929 | "| * * * * * * * * * * \n", 930 | "| * * * * * * * * * * * \n", 931 | "| * * * * * * * * \n", 932 | "| * * * * * * \n", 933 | "| \n", 934 | "| \n" 935 | ] 936 | } 937 | ], 938 | "source": [ 939 | "new_eight = mnist.train.images[29]>0\n", 940 | "plt.imshow(new_eight.reshape(28,28))\n", 941 | "plt.show()\n", 942 | "draw_bin_image(new_eight.reshape((28, 28)))" 943 | ] 944 | }, 945 | { 946 | "cell_type": "code", 947 | "execution_count": 181, 948 | "metadata": {}, 949 | "outputs": [ 950 | { 951 | "name": "stdout", 952 | "output_type": "stream", 953 | "text": [ 954 | "| \n", 955 | "| \n", 956 | "| \n", 957 | "| \n", 958 | "| \n", 959 | "| * * * * * \n", 960 | "| * * * * * * * * \n", 961 | "| * * * * * * * * * \n", 962 | "| * * * * * * * * * * * \n", 963 | "| * * * * * * * \n", 964 | "| * * * * * * * \n", 965 | "| * * * * * * * \n", 966 | "| * * * * * * * \n", 967 | "| * * * * * * * * \n", 968 | "| * * * * * * * * \n", 969 | "| * * * * * * * * \n", 970 | "| * * * * * * * * * * \n", 971 | "| * * * * * * * * * * * \n", 972 | "| * * * * * * * * * * \n", 973 | "| * * * * * * * \n", 974 | "| * * * * * * * \n", 975 | "| * * * * * * * * * * * \n", 976 | "| * * * * * * * * * * * \n", 977 | "| * * * * * * * * * \n", 978 | "| * * * * * \n", 979 | "| \n", 980 | "| \n", 981 | "| \n" 982 | ] 983 | } 984 | ], 985 | "source": [ 986 | "result = hop.hopRun(new_eight)\n", 987 | "draw_bin_image(result.reshape((28, 28)))" 988 | ] 989 | } 990 | ], 991 | "metadata": { 992 | "kernelspec": { 993 | "display_name": "Python 3", 994 | "language": "python", 995 | "name": "python3" 996 | }, 997 | "language_info": { 998 | "codemirror_mode": { 999 | "name": "ipython", 1000 | "version": 3 1001 | }, 1002 | "file_extension": ".py", 1003 | "mimetype": "text/x-python", 1004 | "name": "python", 1005 | "nbconvert_exporter": "python", 1006 | "pygments_lexer": "ipython3", 1007 | "version": "3.6.5" 1008 | } 1009 | }, 1010 | "nbformat": 4, 1011 | "nbformat_minor": 2 1012 | } 1013 | -------------------------------------------------------------------------------- /LSTM.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# LSTM" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import numpy as np\n", 17 | "from matplotlib import pyplot as plt" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 2, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "# 输出单元激活函数\n", 27 | "def softmax(x):\n", 28 | " x = np.array(x)\n", 29 | " max_x = np.max(x)\n", 30 | " return np.exp(x-max_x) / np.sum(np.exp(x-max_x))\n", 31 | " \n", 32 | "def sigmoid(x):\n", 33 | " return 1.0/(1.0 + np.exp(-x))\n", 34 | " \n", 35 | "def tanh(x):\n", 36 | " return (np.exp(x) - np.exp(-x))/(np.exp(x) + np.exp(-x))\n" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 3, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "class myLSTM(object):\n", 46 | " def __init__(self, data_dim, hidden_dim=100):\n", 47 | " # data_dim: 词向量维度,即词典长度; hidden_dim: 隐单元维度\n", 48 | " self.data_dim = data_dim\n", 49 | " self.hidden_dim = hidden_dim\n", 50 | " \n", 51 | " # 初始化权重向量 \n", 52 | " self.whi, self.wxi, self.bi = self._init_wh_wx()\n", 53 | " \n", 54 | " print(self.wxi.shape)\n", 55 | " self.whf, self.wxf, self.bf = self._init_wh_wx() \n", 56 | " self.who, self.wxo, self.bo = self._init_wh_wx()\n", 57 | " self.wha, self.wxa, self.ba = self._init_wh_wx()\n", 58 | " self.wy, self.by = np.random.uniform(-np.sqrt(1.0/self.hidden_dim), np.sqrt(1.0/self.hidden_dim), \n", 59 | " (self.data_dim, self.hidden_dim)), \\\n", 60 | " np.random.uniform(-np.sqrt(1.0/self.hidden_dim), np.sqrt(1.0/self.hidden_dim), \n", 61 | " (self.data_dim, 1))\n", 62 | " \n", 63 | " # 初始化 wh, wx, b\n", 64 | " def _init_wh_wx(self):\n", 65 | " wh = np.random.uniform(-np.sqrt(1.0/self.hidden_dim), np.sqrt(1.0/self.hidden_dim), \n", 66 | " (self.hidden_dim, self.hidden_dim))\n", 67 | " wx = np.random.uniform(-np.sqrt(1.0/self.data_dim), np.sqrt(1.0/self.data_dim), \n", 68 | " (self.hidden_dim, self.data_dim))\n", 69 | " b = np.random.uniform(-np.sqrt(1.0/self.data_dim), np.sqrt(1.0/self.data_dim), \n", 70 | " (self.hidden_dim, 1))\n", 71 | " \n", 72 | " return wh, wx, b\n", 73 | " \n", 74 | " # 初始化各个状态向量\n", 75 | " def _init_s(self, T):\n", 76 | " iss = np.array([np.zeros((self.hidden_dim, 1))] * (T + 1)) # input gate\n", 77 | " fss = np.array([np.zeros((self.hidden_dim, 1))] * (T + 1)) # forget gate\n", 78 | " oss = np.array([np.zeros((self.hidden_dim, 1))] * (T + 1)) # output gate\n", 79 | " ass = np.array([np.zeros((self.hidden_dim, 1))] * (T + 1)) # current inputstate\n", 80 | " hss = np.array([np.zeros((self.hidden_dim, 1))] * (T + 1)) # hidden state\n", 81 | " css = np.array([np.zeros((self.hidden_dim, 1))] * (T + 1)) # cell state\n", 82 | " ys = np.array([np.zeros((self.data_dim, 1))] * T) # output value\n", 83 | " \n", 84 | " return {'iss': iss, 'fss': fss, 'oss': oss, \n", 85 | " 'ass': ass, 'hss': hss, 'css': css, \n", 86 | " 'ys': ys}\n", 87 | " \n", 88 | " def plot_loss():\n", 89 | " x = np.arange(0,len(self.losses))\n", 90 | " plt.plot(x,losses)\n", 91 | " plt.show()\n", 92 | " \n", 93 | " # 前向传播,单个x\n", 94 | " def forward(self, x):\n", 95 | " # 向量时间长度\n", 96 | " T = len(x) \n", 97 | " # 初始化各个状态向量\n", 98 | " stats = self._init_s(T) \n", 99 | " \n", 100 | " for t in range(T):\n", 101 | " # 前一时刻隐藏状态\n", 102 | " ht_pre = np.array(stats['hss'][t-1]).reshape(-1, 1)\n", 103 | " \n", 104 | " # input gate\n", 105 | " stats['iss'][t] = self._cal_gate(self.whi, self.wxi, self.bi, ht_pre, x[t], sigmoid)\n", 106 | " # forget gate\n", 107 | " stats['fss'][t] = self._cal_gate(self.whf, self.wxf, self.bf, ht_pre, x[t], sigmoid)\n", 108 | " # output gate\n", 109 | " stats['oss'][t] = self._cal_gate(self.who, self.wxo, self.bo, ht_pre, x[t], sigmoid)\n", 110 | " # current inputstate\n", 111 | " stats['ass'][t] = self._cal_gate(self.wha, self.wxa, self.ba, ht_pre, x[t], tanh)\n", 112 | " \n", 113 | " # cell state, ct = ft * ct_pre + it * at\n", 114 | " stats['css'][t] = stats['fss'][t] * stats['css'][t-1] + stats['iss'][t] * stats['ass'][t] \n", 115 | " # hidden state, ht = ot * tanh(ct)\n", 116 | " stats['hss'][t] = stats['oss'][t] * tanh(stats['css'][t])\n", 117 | " \n", 118 | " # output value, yt = softmax(self.wy.dot(ht) + self.by)\n", 119 | " stats['ys'][t] = softmax(self.wy.dot(stats['hss'][t]) + self.by)\n", 120 | " \n", 121 | " return stats\n", 122 | " \n", 123 | " # 计算各个门的输出\n", 124 | " def _cal_gate(self, wh, wx, b, ht_pre, x, activation):\n", 125 | " return activation(wh.dot(ht_pre) + wx[:, x].reshape(-1,1) + b)\n", 126 | " \n", 127 | " # 预测输出,单个x \n", 128 | " def predict(self, x):\n", 129 | " stats = self.forward(x)\n", 130 | " pre_y = np.argmax(stats['ys'].reshape(len(x), -1), axis=1) \n", 131 | " return pre_y\n", 132 | " \n", 133 | " # 计算损失, softmax交叉熵损失函数, (x,y)为多个样本\n", 134 | " def loss(self, x, y):\n", 135 | " cost = 0 \n", 136 | " for i in range(len(y)):\n", 137 | " stats = self.forward(x[i])\n", 138 | " # 取出 y[i] 中每一时刻对应的预测值\n", 139 | " pre_yi = stats['ys'][range(len(y[i])), y[i]]\n", 140 | " cost -= np.sum(np.log(pre_yi))\n", 141 | " \n", 142 | " # 统计所有y中词的个数, 计算平均损失\n", 143 | " N = np.sum([len(yi) for yi in y])\n", 144 | " ave_loss = cost / N\n", 145 | " \n", 146 | " return ave_loss\n", 147 | " \n", 148 | " # 初始化偏导数 dwh, dwx, db\n", 149 | " def _init_wh_wx_grad(self):\n", 150 | " dwh = np.zeros(self.whi.shape)\n", 151 | " dwx = np.zeros(self.wxi.shape)\n", 152 | " db = np.zeros(self.bi.shape)\n", 153 | " \n", 154 | " return dwh, dwx, db\n", 155 | " \n", 156 | " # 求梯度, (x,y)为一个样本\n", 157 | " def bptt(self, x, y):\n", 158 | " dwhi, dwxi, dbi = self._init_wh_wx_grad()\n", 159 | " dwhf, dwxf, dbf = self._init_wh_wx_grad() \n", 160 | " dwho, dwxo, dbo = self._init_wh_wx_grad()\n", 161 | " dwha, dwxa, dba = self._init_wh_wx_grad()\n", 162 | " dwy, dby = np.zeros(self.wy.shape), np.zeros(self.by.shape)\n", 163 | " \n", 164 | " # 初始化 delta_ct,因为后向传播过程中,此值需要累加\n", 165 | " delta_ct = np.zeros((self.hidden_dim, 1))\n", 166 | " \n", 167 | " # 前向计算\n", 168 | " stats = self.forward(x)\n", 169 | " # 目标函数对输出 y 的偏导数\n", 170 | " delta_o = stats['ys']\n", 171 | " delta_o[np.arange(len(y)), y] -= 1\n", 172 | " \n", 173 | " for t in np.arange(len(y))[::-1]:\n", 174 | " # 输出层wy, by的偏导数,由于所有时刻的输出共享输出权值矩阵,故所有时刻累加\n", 175 | " dwy += delta_o[t].dot(stats['hss'][t].reshape(1, -1)) \n", 176 | " dby += delta_o[t]\n", 177 | " \n", 178 | " # 目标函数对隐藏状态的偏导数\n", 179 | " delta_ht = self.wy.T.dot(delta_o[t])\n", 180 | " \n", 181 | " # 各个门及状态单元的偏导数\n", 182 | " delta_ot = delta_ht * tanh(stats['css'][t])\n", 183 | " delta_ct += delta_ht * stats['oss'][t] * (1-tanh(stats['css'][t])**2)\n", 184 | " delta_it = delta_ct * stats['ass'][t]\n", 185 | " delta_ft = delta_ct * stats['css'][t-1]\n", 186 | " delta_at = delta_ct * stats['iss'][t]\n", 187 | " \n", 188 | " delta_at_net = delta_at * (1-stats['ass'][t]**2)\n", 189 | " delta_it_net = delta_it * stats['iss'][t] * (1-stats['iss'][t])\n", 190 | " delta_ft_net = delta_ft * stats['fss'][t] * (1-stats['fss'][t])\n", 191 | " delta_ot_net = delta_ot * stats['oss'][t] * (1-stats['oss'][t])\n", 192 | " \n", 193 | " # 更新各权重矩阵的偏导数,由于所有时刻共享权值,故所有时刻累加\n", 194 | " dwhf, dwxf, dbf = self._cal_grad_delta(dwhf, dwxf, dbf, delta_ft_net, stats['hss'][t-1], x[t]) \n", 195 | " dwhi, dwxi, dbi = self._cal_grad_delta(dwhi, dwxi, dbi, delta_it_net, stats['hss'][t-1], x[t]) \n", 196 | " dwha, dwxa, dba = self._cal_grad_delta(dwha, dwxa, dba, delta_at_net, stats['hss'][t-1], x[t]) \n", 197 | " dwho, dwxo, dbo = self._cal_grad_delta(dwho, dwxo, dbo, delta_ot_net, stats['hss'][t-1], x[t])\n", 198 | " \n", 199 | " return [dwhf, dwxf, dbf, \n", 200 | " dwhi, dwxi, dbi, \n", 201 | " dwha, dwxa, dba, \n", 202 | " dwho, dwxo, dbo, \n", 203 | " dwy, dby]\n", 204 | " \n", 205 | " # 更新各权重矩阵的偏导数 \n", 206 | " def _cal_grad_delta(self, dwh, dwx, db, delta_net, ht_pre, x):\n", 207 | " dwh += delta_net * ht_pre\n", 208 | " dwx += delta_net * x\n", 209 | " db += delta_net\n", 210 | " \n", 211 | " return dwh, dwx, db\n", 212 | " \n", 213 | " # 计算梯度, (x,y)为一个样本\n", 214 | " def sgd_step(self, x, y, learning_rate):\n", 215 | " dwhf, dwxf, dbf, \\\n", 216 | " dwhi, dwxi, dbi, \\\n", 217 | " dwha, dwxa, dba, \\\n", 218 | " dwho, dwxo, dbo, \\\n", 219 | " dwy, dby = self.bptt(x, y)\n", 220 | " \n", 221 | " # 更新权重矩阵\n", 222 | " self.whf, self.wxf, self.bf = self._update_wh_wx(learning_rate, self.whf, self.wxf, self.bf, dwhf, dwxf, dbf)\n", 223 | " self.whi, self.wxi, self.bi = self._update_wh_wx(learning_rate, self.whi, self.wxi, self.bi, dwhi, dwxi, dbi)\n", 224 | " self.wha, self.wxa, self.ba = self._update_wh_wx(learning_rate, self.wha, self.wxa, self.ba, dwha, dwxa, dba)\n", 225 | " self.who, self.wxo, self.bo = self._update_wh_wx(learning_rate, self.who, self.wxo, self.bo, dwho, dwxo, dbo)\n", 226 | " \n", 227 | " self.wy, self.by = self.wy - learning_rate * dwy, self.by - learning_rate * dby\n", 228 | " \n", 229 | " # 更新权重矩阵\n", 230 | " def _update_wh_wx(self, learning_rate, wh, wx, b, dwh, dwx, db):\n", 231 | " wh -= learning_rate * dwh\n", 232 | " wx -= learning_rate * dwx\n", 233 | " b -= learning_rate * db\n", 234 | " \n", 235 | " return wh, wx, b\n", 236 | " # 训练 LSTM\n", 237 | " def train(self, X_train, y_train, learning_rate=0.005, n_epoch=5):\n", 238 | " losses = []\n", 239 | " num_examples = 0\n", 240 | " \n", 241 | " for epoch in range(n_epoch): \n", 242 | " for i in range(len(y_train)):\n", 243 | " self.sgd_step(X_train[i], y_train[i], learning_rate)\n", 244 | " num_examples += 1\n", 245 | " if i%200 ==0:\n", 246 | " \n", 247 | " loss = self.loss(X_train, y_train)\n", 248 | " print ('-'*8+'epoch {0} batch = {1}: loss = {2}'.format(epoch+1, i , loss)+'-'*8)\n", 249 | " losses.append(loss)\n", 250 | "\n", 251 | " loss = self.loss(X_train, y_train)\n", 252 | " losses.append(loss)\n", 253 | " print ('-'*15+'epoch {0}: loss = {1}'.format(epoch+1, loss)+'-'*15)\n", 254 | " if len(losses) > 1 and losses[-1] > losses[-2]:\n", 255 | " learning_rate *= 0.5\n", 256 | " print( 'decrease learning_rate to', learning_rate)\n", 257 | " self.losses = losses" 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "metadata": {}, 263 | "source": [ 264 | "### 数据准备\n" 265 | ] 266 | }, 267 | { 268 | "cell_type": "code", 269 | "execution_count": 18, 270 | "metadata": {}, 271 | "outputs": [ 272 | { 273 | "name": "stdout", 274 | "output_type": "stream", 275 | "text": [ 276 | "65536\n", 277 | "16\n", 278 | "9\n" 279 | ] 280 | } 281 | ], 282 | "source": [ 283 | "# 最多8位二进制\n", 284 | "BINARY_DIM = 8\n", 285 | "\n", 286 | "# 将整数表示成为binary_dim位的二进制数,高位用0补齐\n", 287 | "def int_2_binary(number, binary_dim):\n", 288 | " binary_list = list(map(lambda x: int(x), bin(number)[2:]))\n", 289 | " number_dim = len(binary_list)\n", 290 | " result_list = [0]*(binary_dim-number_dim)+binary_list\n", 291 | " return result_list\n", 292 | "\n", 293 | "# 将一个二进制数组转为整数\n", 294 | "def binary2int(binary_array):\n", 295 | " out = 0\n", 296 | " for index, x in enumerate(reversed(binary_array)):\n", 297 | " out += x * pow(2, index)\n", 298 | " return out\n", 299 | "\n", 300 | "# 将[0,2**BINARY_DIM)所有数表示成二进制\n", 301 | "binary = np.array([int_2_binary(x, BINARY_DIM) for x in range(2**BINARY_DIM)])\n", 302 | "# print(binary)\n", 303 | "\n", 304 | "# 样本的输入向量和输出向量\n", 305 | "dataX = []\n", 306 | "dataY = []\n", 307 | "for i in range(binary.shape[0]):\n", 308 | " for j in range(binary.shape[0]):\n", 309 | " dataX.append(np.append(binary[i], binary[j]))\n", 310 | " dataY.append(int_2_binary(i+j, BINARY_DIM+1))\n", 311 | "\n", 312 | "print(len(dataX)) ## 2**16 个样本\n", 313 | "print(len(dataX[0]))\n", 314 | "print(len(dataY[0]))\n", 315 | "# print(dataY)\n", 316 | "\n", 317 | "# 重新特征X和目标变量Y数组,适应LSTM模型的输入和输出\n", 318 | "X = np.reshape(dataX, (len(dataX), 2*BINARY_DIM, 1))\n", 319 | "# print(X.shape)\n", 320 | "Y = np.array(dataY)\n", 321 | "# print(dataY.shape)" 322 | ] 323 | }, 324 | { 325 | "cell_type": "markdown", 326 | "metadata": {}, 327 | "source": [ 328 | "### 使用keras实现" 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": 22, 334 | "metadata": {}, 335 | "outputs": [], 336 | "source": [ 337 | "from keras.models import Sequential\n", 338 | "from keras.layers import Dense\n", 339 | "from keras.layers import Dropout\n", 340 | "from keras.layers import LSTM\n", 341 | "from keras import losses\n", 342 | "from keras.utils import plot_model\n", 343 | "import keras" 344 | ] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "execution_count": 23, 349 | "metadata": {}, 350 | "outputs": [], 351 | "source": [ 352 | "#写一个LossHistory类,保存loss和acc\n", 353 | "class LossHistory(keras.callbacks.Callback):\n", 354 | " def on_train_begin(self, logs={}):\n", 355 | " self.losses = {'batch':[], 'epoch':[]}\n", 356 | " self.accuracy = {'batch':[], 'epoch':[]}\n", 357 | " self.val_loss = {'batch':[], 'epoch':[]}\n", 358 | " self.val_acc = {'batch':[], 'epoch':[]}\n", 359 | "\n", 360 | " def on_batch_end(self, batch, logs={}):\n", 361 | " self.losses['batch'].append(logs.get('loss'))\n", 362 | " self.accuracy['batch'].append(logs.get('acc'))\n", 363 | " self.val_loss['batch'].append(logs.get('val_loss'))\n", 364 | " self.val_acc['batch'].append(logs.get('val_acc'))\n", 365 | "\n", 366 | " def on_epoch_end(self, batch, logs={}):\n", 367 | " self.losses['epoch'].append(logs.get('loss'))\n", 368 | " self.accuracy['epoch'].append(logs.get('acc'))\n", 369 | " self.val_loss['epoch'].append(logs.get('val_loss'))\n", 370 | " self.val_acc['epoch'].append(logs.get('val_acc'))\n", 371 | "\n", 372 | " def loss_plot(self, loss_type):\n", 373 | " iters = range(len(self.losses[loss_type]))\n", 374 | " plt.figure()\n", 375 | " # acc\n", 376 | " plt.plot(iters, self.accuracy[loss_type], 'r', label='train acc')\n", 377 | " # loss\n", 378 | " plt.plot(iters, self.losses[loss_type], 'g', label='train loss')\n", 379 | " if loss_type == 'epoch':\n", 380 | " # val_acc\n", 381 | " plt.plot(iters, self.val_acc[loss_type], 'b', label='val acc')\n", 382 | " # val_loss\n", 383 | " plt.plot(iters, self.val_loss[loss_type], 'k', label='val loss')\n", 384 | " plt.grid(True)\n", 385 | " plt.xlabel(loss_type)\n", 386 | " plt.ylabel('acc-loss')\n", 387 | " plt.legend(loc=\"upper right\")\n", 388 | " plt.show()" 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "execution_count": 24, 394 | "metadata": {}, 395 | "outputs": [ 396 | { 397 | "name": "stdout", 398 | "output_type": "stream", 399 | "text": [ 400 | "Epoch 1/5\n", 401 | "65536/65536 [==============================] - 44s - loss: 0.2350 - acc: 0.5409 \n", 402 | "Epoch 2/5\n", 403 | "65536/65536 [==============================] - 42s - loss: 0.1907 - acc: 0.8422 \n", 404 | "Epoch 3/5\n", 405 | "65536/65536 [==============================] - 42s - loss: 0.1457 - acc: 0.8435 \n", 406 | "Epoch 4/5\n", 407 | "65536/65536 [==============================] - 42s - loss: 0.1315 - acc: 0.7942 \n", 408 | "Epoch 5/5\n", 409 | "65536/65536 [==============================] - 42s - loss: 0.1248 - acc: 0.7291 \n" 410 | ] 411 | }, 412 | { 413 | "data": { 414 | "image/png": "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\n", 415 | "text/plain": [ 416 | "
" 417 | ] 418 | }, 419 | "metadata": {}, 420 | "output_type": "display_data" 421 | } 422 | ], 423 | "source": [ 424 | "# 定义LSTM模型\n", 425 | "model = Sequential()\n", 426 | "model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2])))\n", 427 | "model.add(Dropout(0.2))\n", 428 | "model.add(Dense(Y.shape[1], activation='sigmoid'))\n", 429 | "model.compile(loss=losses.mean_squared_error, optimizer='adam',metrics=['accuracy'])\n", 430 | "#创建一个实例history\n", 431 | "history = LossHistory()\n", 432 | "\n", 433 | "# print(model.summary())\n", 434 | "\n", 435 | "# plot model\n", 436 | "plot_model(model, to_file=r'./model.png', show_shapes=True)\n", 437 | "# train model\n", 438 | "epochs = 5\n", 439 | "model.fit(X, Y, epochs=epochs, batch_size=128,callbacks=[history])\n", 440 | "history.loss_plot('batch')" 441 | ] 442 | }, 443 | { 444 | "cell_type": "markdown", 445 | "metadata": {}, 446 | "source": [ 447 | "##### 模型\n", 448 | "\n", 449 | "" 450 | ] 451 | }, 452 | { 453 | "cell_type": "markdown", 454 | "metadata": {}, 455 | "source": [ 456 | "## Test 测试" 457 | ] 458 | }, 459 | { 460 | "cell_type": "code", 461 | "execution_count": 25, 462 | "metadata": {}, 463 | "outputs": [ 464 | { 465 | "name": "stdout", 466 | "output_type": "stream", 467 | "text": [ 468 | "==============================\n", 469 | "[1 0 1 1 0 0 1 0]: 178\n", 470 | "[0 0 0 0 1 0 1 1]: 11\n", 471 | "[0 1 0 1 1 0 1 0 1]: 181\n", 472 | "==============================\n", 473 | "[0 0 1 0 0 1 0 1]: 37\n", 474 | "[1 1 0 0 0 0 1 1]: 195\n", 475 | "[0 1 1 1 1 1 1 1 0]: 254\n", 476 | "==============================\n", 477 | "[0 1 0 0 1 1 1 1]: 79\n", 478 | "[0 1 0 0 0 1 0 1]: 69\n", 479 | "[0 1 0 0 1 0 1 0 0]: 148\n", 480 | "==============================\n", 481 | "[1 1 0 1 1 0 1 1]: 219\n", 482 | "[1 1 0 1 0 0 0 1]: 209\n", 483 | "[1 1 0 1 1 1 0 0 0]: 440\n", 484 | "==============================\n", 485 | "[1 0 1 1 0 0 1 1]: 179\n", 486 | "[0 1 1 1 0 1 0 0]: 116\n", 487 | "[1 0 0 1 1 0 0 0 1]: 305\n", 488 | "==============================\n", 489 | "[1 0 1 0 0 1 1 0]: 166\n", 490 | "[1 1 0 0 1 0 0 0]: 200\n", 491 | "[1 0 1 1 0 1 0 1 0]: 362\n", 492 | "==============================\n", 493 | "[0 1 0 1 0 1 1 1]: 87\n", 494 | "[1 1 0 1 0 1 1 1]: 215\n", 495 | "[1 0 0 1 1 0 1 0 0]: 308\n", 496 | "==============================\n", 497 | "[1 1 1 0 0 0 0 1]: 225\n", 498 | "[1 0 0 1 0 1 0 1]: 149\n", 499 | "[1 0 1 1 1 1 0 0 0]: 376\n", 500 | "==============================\n", 501 | "[1 1 0 1 1 1 1 1]: 223\n", 502 | "[0 0 1 1 1 1 0 0]: 60\n", 503 | "[1 0 0 0 1 0 1 0 1]: 277\n", 504 | "==============================\n", 505 | "[1 1 0 1 1 1 1 0]: 222\n", 506 | "[1 1 0 0 0 1 1 0]: 198\n", 507 | "[1 1 0 0 1 0 0 0 0]: 400\n", 508 | "==============================\n", 509 | "[0 0 1 0 0 1 0 1]: 37\n", 510 | "[1 0 1 1 0 1 0 1]: 181\n", 511 | "[0 1 1 0 1 0 1 1 0]: 214\n", 512 | "==============================\n", 513 | "[1 0 0 0 0 1 1 1]: 135\n", 514 | "[0 1 0 0 0 1 0 0]: 68\n", 515 | "[0 1 1 0 0 0 1 0 1]: 197\n", 516 | "==============================\n", 517 | "[0 0 0 0 1 1 1 1]: 15\n", 518 | "[1 1 1 1 1 0 0 1]: 249\n", 519 | "[1 0 0 0 0 0 1 0 0]: 260\n", 520 | "==============================\n", 521 | "[0 1 1 0 0 1 1 1]: 103\n", 522 | "[1 1 1 1 0 1 1 0]: 246\n", 523 | "[1 0 1 0 0 1 0 1 1]: 331\n", 524 | "==============================\n", 525 | "[0 0 1 0 0 1 1 0]: 38\n", 526 | "[0 1 0 1 0 0 1 1]: 83\n", 527 | "[0 0 1 1 1 1 1 0 1]: 125\n", 528 | "==============================\n", 529 | "[0 1 0 1 0 1 0 1]: 85\n", 530 | "[1 1 0 0 1 1 1 1]: 207\n", 531 | "[1 0 0 1 1 0 0 0 0]: 304\n", 532 | "==============================\n", 533 | "[0 1 1 0 1 0 1 1]: 107\n", 534 | "[0 0 1 1 1 1 0 0]: 60\n", 535 | "[0 1 0 0 1 0 1 0 1]: 149\n", 536 | "==============================\n", 537 | "[0 1 1 0 1 0 0 0]: 104\n", 538 | "[1 1 1 0 1 1 1 0]: 238\n", 539 | "[1 0 1 0 0 1 1 1 0]: 334\n", 540 | "==============================\n", 541 | "[1 1 1 0 0 1 1 1]: 231\n", 542 | "[0 1 1 0 1 1 1 0]: 110\n", 543 | "[1 0 1 0 0 1 1 1 1]: 335\n", 544 | "==============================\n", 545 | "[1 1 0 0 0 0 0 1]: 193\n", 546 | "[0 1 0 1 0 0 1 1]: 83\n", 547 | "[1 0 0 0 1 0 0 0 0]: 272\n", 548 | "==============================\n", 549 | "[1 0 1 1 0 1 0 0]: 180\n", 550 | "[0 1 1 1 1 1 1 0]: 126\n", 551 | "[1 0 0 1 1 0 0 1 0]: 306\n", 552 | "==============================\n", 553 | "[1 0 0 0 1 1 0 0]: 140\n", 554 | "[1 0 0 1 0 1 1 0]: 150\n", 555 | "[1 0 0 1 1 0 0 1 0]: 306\n", 556 | "==============================\n", 557 | "[0 1 1 1 0 1 1 0]: 118\n", 558 | "[1 1 1 0 1 1 1 0]: 238\n", 559 | "[1 0 1 0 1 0 1 0 0]: 340\n", 560 | "==============================\n", 561 | "[1 1 1 1 1 0 0 1]: 249\n", 562 | "[0 0 0 1 1 0 1 1]: 27\n", 563 | "[1 0 0 0 1 0 0 0 0]: 272\n", 564 | "==============================\n", 565 | "[1 0 1 1 1 1 1 1]: 191\n", 566 | "[0 0 1 0 1 1 0 0]: 44\n", 567 | "[0 1 1 1 0 0 1 0 1]: 229\n", 568 | "==============================\n", 569 | "[0 0 0 0 1 0 0 1]: 9\n", 570 | "[0 1 0 1 1 1 0 1]: 93\n", 571 | "[0 0 1 0 1 1 0 1 0]: 90\n", 572 | "==============================\n", 573 | "[1 1 0 0 1 1 0 1]: 205\n", 574 | "[0 1 0 1 1 0 1 0]: 90\n", 575 | "[1 0 0 1 1 0 1 0 1]: 309\n", 576 | "==============================\n", 577 | "[1 0 0 1 1 0 1 0]: 154\n", 578 | "[0 1 0 1 1 0 0 1]: 89\n", 579 | "[0 1 1 1 1 0 1 1 1]: 247\n", 580 | "==============================\n", 581 | "[1 0 0 1 0 1 1 0]: 150\n", 582 | "[0 0 0 1 1 1 1 0]: 30\n", 583 | "[0 1 0 1 1 0 1 0 0]: 180\n", 584 | "==============================\n", 585 | "[1 1 0 0 0 1 0 0]: 196\n", 586 | "[1 1 1 0 1 1 1 0]: 238\n", 587 | "[1 1 0 0 0 0 0 1 0]: 386\n", 588 | "==============================\n", 589 | "[1 0 0 1 0 0 0 1]: 145\n", 590 | "[1 1 1 1 0 0 1 0]: 242\n", 591 | "[1 1 0 0 1 1 0 1 1]: 411\n", 592 | "==============================\n", 593 | "[0 1 1 0 1 1 1 0]: 110\n", 594 | "[0 0 1 1 1 0 1 1]: 59\n", 595 | "[0 1 0 1 1 0 1 0 1]: 181\n", 596 | "==============================\n", 597 | "[0 0 1 1 0 0 0 0]: 48\n", 598 | "[0 1 0 0 0 1 0 1]: 69\n", 599 | "[0 0 1 1 1 1 1 0 1]: 125\n", 600 | "==============================\n", 601 | "[0 1 0 1 1 0 1 1]: 91\n", 602 | "[0 1 1 0 1 0 0 0]: 104\n", 603 | "[0 1 0 1 1 0 1 0 1]: 181\n", 604 | "==============================\n", 605 | "[0 0 0 1 1 0 1 1]: 27\n", 606 | "[0 1 0 1 0 1 1 1]: 87\n", 607 | "[0 0 1 1 1 1 1 1 0]: 126\n", 608 | "==============================\n", 609 | "[1 1 1 0 1 1 1 1]: 239\n", 610 | "[0 0 0 0 0 0 0 1]: 1\n", 611 | "[0 1 1 1 1 0 1 0 0]: 244\n", 612 | "==============================\n", 613 | "[0 1 0 0 1 0 0 0]: 72\n", 614 | "[1 1 1 0 1 1 0 1]: 237\n", 615 | "[1 0 0 1 1 1 1 0 1]: 317\n", 616 | "==============================\n", 617 | "[1 0 0 1 1 1 0 0]: 156\n", 618 | "[1 0 1 1 1 1 1 1]: 191\n", 619 | "[1 0 1 0 0 0 0 1 1]: 323\n", 620 | "==============================\n", 621 | "[1 0 1 1 1 1 0 1]: 189\n", 622 | "[1 1 1 0 1 0 0 0]: 232\n", 623 | "[1 1 0 0 1 1 0 0 1]: 409\n", 624 | "==============================\n", 625 | "[0 1 1 1 0 1 0 0]: 116\n", 626 | "[1 1 0 0 1 1 0 1]: 205\n", 627 | "[1 0 1 1 1 0 0 0 1]: 369\n", 628 | "==============================\n", 629 | "[1 1 1 0 1 0 1 0]: 234\n", 630 | "[0 0 0 1 0 1 0 0]: 20\n", 631 | "[0 1 1 1 1 0 1 1 0]: 246\n", 632 | "==============================\n", 633 | "[0 0 0 0 0 0 0 0]: 0\n", 634 | "[0 1 1 0 1 1 1 0]: 110\n", 635 | "[0 0 1 1 1 1 1 1 0]: 126\n", 636 | "==============================\n", 637 | "[1 0 1 1 0 1 0 0]: 180\n", 638 | "[1 1 1 0 1 0 1 0]: 234\n", 639 | "[1 1 0 0 0 1 1 1 0]: 398\n", 640 | "==============================\n", 641 | "[0 1 1 1 1 0 1 0]: 122\n", 642 | "[1 0 1 1 1 0 0 1]: 185\n", 643 | "[1 0 0 1 1 1 1 1 1]: 319\n", 644 | "==============================\n", 645 | "[1 0 1 1 0 0 0 1]: 177\n", 646 | "[1 0 0 1 0 1 0 1]: 149\n", 647 | "[1 0 1 0 0 1 0 0 0]: 328\n", 648 | "==============================\n", 649 | "[1 1 1 0 1 1 0 1]: 237\n", 650 | "[1 0 1 1 1 1 0 0]: 188\n", 651 | "[1 1 0 1 1 1 0 0 1]: 441\n", 652 | "==============================\n", 653 | "[0 0 1 1 0 0 0 1]: 49\n", 654 | "[1 0 1 1 0 0 1 0]: 178\n", 655 | "[0 1 1 1 1 0 1 1 1]: 247\n", 656 | "==============================\n", 657 | "[0 1 1 1 1 0 0 1]: 121\n", 658 | "[1 1 1 0 0 0 0 0]: 224\n", 659 | "[1 0 1 0 0 1 1 1 1]: 335\n", 660 | "==============================\n", 661 | "[1 0 0 0 1 0 0 0]: 136\n", 662 | "[0 1 1 1 0 0 1 0]: 114\n", 663 | "[0 1 1 1 1 0 0 1 0]: 242\n", 664 | "==============================\n", 665 | "[1 1 0 0 0 1 1 0]: 198\n", 666 | "[1 1 1 1 1 0 0 0]: 248\n", 667 | "[1 1 0 0 0 0 0 1 0]: 386\n", 668 | "==============================\n", 669 | "[1 0 1 0 1 0 0 1]: 169\n", 670 | "[0 0 1 1 1 1 1 1]: 63\n", 671 | "[0 1 1 1 1 0 0 1 0]: 242\n", 672 | "==============================\n", 673 | "[0 0 0 1 1 0 0 1]: 25\n", 674 | "[0 0 1 1 0 1 1 0]: 54\n", 675 | "[0 0 1 0 1 1 0 1 1]: 91\n", 676 | "==============================\n", 677 | "[0 1 1 1 1 0 0 1]: 121\n", 678 | "[0 1 0 0 1 0 0 1]: 73\n", 679 | "[0 1 1 0 1 0 1 1 0]: 214\n", 680 | "==============================\n", 681 | "[1 1 1 0 0 1 0 0]: 228\n", 682 | "[1 0 1 1 1 0 0 1]: 185\n", 683 | "[1 1 0 0 1 1 1 0 1]: 413\n", 684 | "==============================\n", 685 | "[1 0 0 0 0 1 0 0]: 132\n", 686 | "[0 1 0 1 0 0 1 0]: 82\n", 687 | "[0 1 1 0 0 0 1 1 0]: 198\n", 688 | "==============================\n", 689 | "[1 0 0 0 1 0 0 1]: 137\n", 690 | "[1 1 1 1 0 1 0 1]: 245\n", 691 | "[1 0 1 1 1 1 0 1 0]: 378\n", 692 | "==============================\n", 693 | "[1 1 1 0 1 1 1 1]: 239\n", 694 | "[1 1 1 1 0 0 1 1]: 243\n", 695 | "[1 1 1 0 1 0 0 1 0]: 466\n", 696 | "==============================\n", 697 | "[1 0 0 1 0 0 0 1]: 145\n", 698 | "[0 0 1 0 1 1 1 0]: 46\n", 699 | "[0 1 0 1 1 0 1 1 1]: 183\n", 700 | "==============================\n", 701 | "[1 1 0 1 0 0 1 0]: 210\n", 702 | "[1 0 0 1 1 1 1 1]: 159\n", 703 | "[1 0 1 1 1 1 1 0 1]: 381\n", 704 | "==============================\n", 705 | "[0 0 1 1 1 1 0 1]: 61\n", 706 | "[1 0 0 1 1 1 0 0]: 156\n", 707 | "[0 1 1 0 1 0 1 1 1]: 215\n", 708 | "==============================\n", 709 | "[0 1 0 1 1 0 1 1]: 91\n", 710 | "[0 0 0 0 0 0 1 1]: 3\n", 711 | "[0 0 1 0 1 0 1 1 0]: 86\n", 712 | "==============================\n", 713 | "[1 0 1 1 1 0 0 0]: 184\n", 714 | "[0 0 1 1 0 1 0 1]: 53\n", 715 | "[0 1 1 1 1 0 1 0 1]: 245\n", 716 | "==============================\n", 717 | "[1 1 1 1 0 0 0 1]: 241\n", 718 | "[1 1 0 1 0 0 1 0]: 210\n", 719 | "[1 1 0 1 1 0 1 0 1]: 437\n", 720 | "==============================\n", 721 | "[1 1 1 0 1 0 0 0]: 232\n", 722 | "[1 1 1 0 1 0 0 1]: 233\n", 723 | "[1 1 1 1 1 0 0 0 1]: 497\n", 724 | "==============================\n", 725 | "[1 0 0 1 0 0 1 1]: 147\n", 726 | "[1 0 0 0 0 0 1 0]: 130\n", 727 | "[1 0 0 0 0 0 1 0 1]: 261\n", 728 | "==============================\n", 729 | "[0 0 1 0 1 0 0 1]: 41\n", 730 | "[0 0 1 0 0 1 1 1]: 39\n", 731 | "[0 0 1 0 1 1 0 1 0]: 90\n", 732 | "==============================\n", 733 | "[1 0 0 1 0 1 0 0]: 148\n", 734 | "[1 1 0 0 0 1 0 1]: 197\n", 735 | "[1 0 1 0 1 0 0 0 1]: 337\n", 736 | "==============================\n", 737 | "[0 0 0 1 1 0 1 0]: 26\n", 738 | "[1 0 1 0 1 0 0 1]: 169\n", 739 | "[0 1 0 1 1 1 0 1 1]: 187\n", 740 | "==============================\n", 741 | "[1 0 1 1 0 0 0 1]: 177\n", 742 | "[0 0 1 0 1 1 1 1]: 47\n", 743 | "[0 1 1 0 0 0 0 1 0]: 194\n", 744 | "==============================\n", 745 | "[0 0 0 1 0 1 0 1]: 21\n", 746 | "[0 0 0 1 0 1 1 0]: 22\n", 747 | "[0 0 0 1 1 1 1 0 1]: 61\n", 748 | "==============================\n", 749 | "[0 0 1 1 0 0 0 0]: 48\n", 750 | "[0 1 1 1 0 0 1 0]: 114\n", 751 | "[0 1 0 1 1 0 0 1 0]: 178\n", 752 | "==============================\n", 753 | "[0 1 1 0 0 1 1 1]: 103\n", 754 | "[0 1 0 0 1 1 0 1]: 77\n", 755 | "[0 1 0 1 1 0 1 0 0]: 180\n", 756 | "==============================\n", 757 | "[1 0 1 1 1 1 1 1]: 191\n", 758 | "[1 1 1 0 0 0 1 0]: 226\n", 759 | "[1 1 0 0 1 1 0 1 1]: 411\n", 760 | "==============================\n", 761 | "[0 1 0 0 1 1 0 1]: 77\n", 762 | "[0 1 1 0 0 1 1 0]: 102\n", 763 | "[0 1 0 1 1 0 1 1 1]: 183\n", 764 | "==============================\n", 765 | "[1 1 1 1 1 0 1 1]: 251\n", 766 | "[1 1 1 0 0 1 0 0]: 228\n", 767 | "[1 1 1 0 0 0 1 1 1]: 455\n", 768 | "==============================\n", 769 | "[0 0 0 1 0 1 1 0]: 22\n", 770 | "[1 0 1 1 0 0 0 0]: 176\n", 771 | "[0 1 1 0 1 1 0 1 0]: 218\n", 772 | "==============================\n", 773 | "[0 0 0 0 0 1 1 1]: 7\n", 774 | "[1 0 1 0 0 0 1 0]: 162\n", 775 | "[0 1 0 1 0 1 1 1 1]: 175\n", 776 | "==============================\n", 777 | "[0 1 0 0 1 1 1 1]: 79\n", 778 | "[1 1 0 0 0 0 0 1]: 193\n", 779 | "[1 0 0 0 1 0 0 0 0]: 272\n", 780 | "==============================\n", 781 | "[1 1 1 1 0 0 1 1]: 243\n", 782 | "[0 1 1 1 0 0 1 0]: 114\n", 783 | "[1 0 1 0 0 1 0 1 1]: 331\n", 784 | "==============================\n", 785 | "[1 1 0 1 0 0 1 1]: 211\n", 786 | "[0 1 0 0 1 1 0 0]: 76\n", 787 | "[1 0 0 0 1 0 0 0 1]: 273\n", 788 | "==============================\n", 789 | "[0 0 1 0 0 1 0 1]: 37\n", 790 | "[1 0 1 1 1 1 1 1]: 191\n", 791 | "[0 1 1 1 1 0 1 0 0]: 244\n", 792 | "==============================\n", 793 | "[1 1 1 0 0 1 1 1]: 231\n", 794 | "[0 0 0 1 1 0 1 0]: 26\n", 795 | "[0 1 1 1 1 0 1 0 1]: 245\n", 796 | "==============================\n", 797 | "[1 1 0 1 1 1 1 0]: 222\n", 798 | "[1 0 0 1 0 0 1 1]: 147\n", 799 | "[1 0 1 1 1 1 1 0 1]: 381\n", 800 | "==============================\n", 801 | "[0 1 1 1 1 1 0 0]: 124\n", 802 | "[1 1 1 0 1 1 0 0]: 236\n", 803 | "[1 0 1 1 1 0 0 0 0]: 368\n", 804 | "==============================\n", 805 | "[0 1 0 1 1 0 0 1]: 89\n", 806 | "[0 0 0 1 0 1 1 1]: 23\n", 807 | "[0 0 1 1 1 1 0 1 0]: 122\n", 808 | "==============================\n", 809 | "[1 0 1 0 0 0 0 1]: 161\n", 810 | "[1 0 1 0 1 0 1 0]: 170\n", 811 | "[1 0 1 0 0 1 0 0 1]: 329\n", 812 | "==============================\n", 813 | "[1 0 0 1 0 0 1 0]: 146\n", 814 | "[1 0 1 0 0 0 0 1]: 161\n", 815 | "[1 0 0 1 1 0 1 1 1]: 311\n", 816 | "==============================\n", 817 | "[1 0 1 1 1 1 0 1]: 189\n", 818 | "[1 0 1 1 0 1 0 1]: 181\n", 819 | "[1 0 1 1 1 1 0 1 0]: 378\n", 820 | "==============================\n", 821 | "[0 0 0 0 1 1 0 1]: 13\n", 822 | "[1 1 0 0 1 1 0 0]: 204\n", 823 | "[0 1 1 0 1 1 1 1 1]: 223\n", 824 | "==============================\n", 825 | "[1 1 0 1 1 1 1 0]: 222\n", 826 | "[1 1 1 1 0 0 1 0]: 242\n", 827 | "[1 1 0 1 1 1 1 0 0]: 444\n", 828 | "==============================\n", 829 | "[1 0 0 1 1 0 1 1]: 155\n", 830 | "[0 1 1 1 1 0 1 0]: 122\n", 831 | "[1 0 0 0 1 0 1 0 1]: 277\n", 832 | "==============================\n", 833 | "[1 1 0 0 0 1 0 1]: 197\n", 834 | "[1 1 1 1 1 0 1 1]: 251\n", 835 | "[1 1 0 1 1 1 0 0 0]: 440\n", 836 | "==============================\n", 837 | "[1 0 1 1 0 1 0 0]: 180\n", 838 | "[1 1 0 1 0 1 1 0]: 214\n", 839 | "[1 1 0 0 1 0 0 1 0]: 402\n", 840 | "==============================\n", 841 | "[0 0 0 0 1 0 1 0]: 10\n", 842 | "[1 1 0 0 0 0 1 1]: 195\n", 843 | "[0 1 1 0 1 1 1 0 1]: 221\n", 844 | "==============================\n", 845 | "[0 1 0 0 1 0 1 0]: 74\n", 846 | "[1 1 0 1 0 0 1 0]: 210\n", 847 | "[1 0 0 0 1 0 1 0 0]: 276\n", 848 | "==============================\n", 849 | "[0 0 1 1 1 1 1 0]: 62\n", 850 | "[0 1 0 0 1 0 0 1]: 73\n", 851 | "[0 1 0 0 1 1 1 1 1]: 159\n", 852 | "==============================\n", 853 | "[0 0 0 0 0 1 0 1]: 5\n", 854 | "[1 0 0 1 1 0 0 1]: 153\n", 855 | "[0 1 0 0 1 1 1 1 0]: 158\n", 856 | "==============================\n", 857 | "[1 1 0 0 0 1 0 1]: 197\n", 858 | "[1 1 0 1 0 0 0 1]: 209\n", 859 | "[1 1 0 0 0 1 0 1 0]: 394\n", 860 | "==============================\n", 861 | "[0 1 1 1 0 0 1 0]: 114\n", 862 | "[1 1 0 1 0 0 1 1]: 211\n", 863 | "[1 0 1 0 1 0 1 0 1]: 341\n", 864 | "==============================\n", 865 | "[0 1 1 0 1 0 1 0]: 106\n", 866 | "[1 0 1 1 0 0 0 0]: 176\n", 867 | "[1 0 0 0 0 0 1 1 0]: 262\n" 868 | ] 869 | } 870 | ], 871 | "source": [ 872 | "for _ in range(100):\n", 873 | " start = np.random.randint(0, len(dataX)-1)\n", 874 | " # print(dataX[start])\n", 875 | " number1 = dataX[start][0:BINARY_DIM]\n", 876 | " number2 = dataX[start][BINARY_DIM:]\n", 877 | " print('='*30)\n", 878 | " print('%s: %s'%(number1, binary2int(number1)))\n", 879 | " print('%s: %s'%(number2, binary2int(number2)))\n", 880 | " sample = np.reshape(X[start], (1, 2*BINARY_DIM, 1))\n", 881 | " predict = np.round(model.predict(sample), 0).astype(np.int32)[0]\n", 882 | " print('%s: %s'%(predict, binary2int(predict)))" 883 | ] 884 | } 885 | ], 886 | "metadata": { 887 | "kernelspec": { 888 | "display_name": "Python 3", 889 | "language": "python", 890 | "name": "python3" 891 | }, 892 | "language_info": { 893 | "codemirror_mode": { 894 | "name": "ipython", 895 | "version": 3 896 | }, 897 | "file_extension": ".py", 898 | "mimetype": "text/x-python", 899 | "name": "python", 900 | "nbconvert_exporter": "python", 901 | "pygments_lexer": "ipython3", 902 | "version": "3.6.5" 903 | } 904 | }, 905 | "nbformat": 4, 906 | "nbformat_minor": 2 907 | } 908 | --------------------------------------------------------------------------------