{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Iterative CNN approach with Keras"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nfrom matplotlib import pyplot as plt\n\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras import activations\nfrom keras.utils import Sequence","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load train dataset"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train_val = pd.read_csv('/kaggle/input/conways-reverse-game-of-life-2020/train.csv', index_col='id')\ntrain_val['delta'].describe()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"MAX_DELTA = max(train_val['delta'])\nGRID_HEIGHT = 25\nGRID_WIDTH = 25","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"def line2grid(data):\n    return data.to_numpy().reshape((data.shape[0], 1, GRID_HEIGHT, GRID_WIDTH))\n\nstart = line2grid(train_val.iloc[:,1:626])\nstop = line2grid(train_val.iloc[:,626:])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Taken from http://jakevdp.github.io/blog/2013/08/07/conways-game-of-life/\ndef life_step(X):\n    \"\"\"Game of life step using generator expressions\"\"\"\n    nbrs_count = sum(np.roll(np.roll(X, i, 0), j, 1)\n                     for i in (-1, 0, 1) for j in (-1, 0, 1)\n                     if (i != 0 or j != 0))\n    return (nbrs_count == 3) | (X & (nbrs_count == 2))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data exploration"},{"metadata":{"trusted":true},"cell_type":"code","source":"idx = 25\n\n# Start, Stop\nfig, (ax1, ax2) = plt.subplots(1, 2)\nfig.suptitle(f'Delta: {train_val.loc[idx, \"delta\"]}')\nax1.imshow(1-(start[idx, 0, :]), cmap=\"gray\")\nax1.set_title(\"Start Setting\")\nax2.imshow(1-(stop[idx, 0, :]), cmap=\"gray\")\nax2.set_title(\"Stop Setting\")\n\nX = start[idx, 0]\ndelta = train_val.loc[idx, \"delta\"]\n\n# Evolution over time (get missing steps)\nfig, ax = plt.subplots(1, delta+1, figsize=((delta+1)*3 ,4))\nfig.suptitle(f'Evolving over {delta} steps')\nax[0].imshow(1-X, cmap=\"gray\")\nax[0].set_title(\"Start\")\n\nfor i in range(delta):\n    X = life_step(X)\n    ax[i+1].imshow(1-X, cmap=\"gray\")\n    ax[i+1].set_title(f'Delta {i+1}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data preparation"},{"metadata":{"trusted":true},"cell_type":"code","source":"class ImageSequence(Sequence):\n    def __init__(self, start, delta, batch_size):\n        self.start, self.delta = start, delta\n        self.batch_size = batch_size\n\n    def __len__(self):\n        return int(np.ceil(len(self.start) * self.delta / float(self.batch_size))) - 1\n\n    def __getitem__(self, idx):\n        index = idx * self.batch_size // self.delta\n        delta = idx * self.batch_size % self.delta\n        #print(idx, start[index:].shape, delta)\n        for curr_i, X in enumerate(self.start[index:, 0]):\n            for i in range(delta, self.delta):\n                if curr_i == 0 and i == delta:\n                    batch_X = np.expand_dims(life_step(X), axis=0)\n                    batch_Y = np.expand_dims(X, axis=0)\n                else:\n                    batch_X = np.append(batch_X, np.expand_dims(life_step(X), axis=0), axis=0)\n                    batch_Y = np.append(batch_Y, np.expand_dims(X, axis=0), axis=0)\n                X = life_step(X)\n            \n                if len(batch_X) == self.batch_size:\n                    return np.expand_dims(batch_X, axis=-1), np.expand_dims(batch_Y, axis=-1)\n            delta = 0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"generator = ImageSequence(start, delta=5, batch_size=64).__iter__()\nbatch_X, batch_Y = next(generator)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"size = 10\n\nfig, ax = plt.subplots(1, size, figsize=((size)*3 ,4))\nfig.suptitle(f'Batch X extract')\n\nfor i in range(size):\n    ax[i].imshow(1-batch_X[i, :, :, 0], cmap=\"gray\")\n    ax[i].set_title(f'{i}')\n    \nfig, ax = plt.subplots(1, size, figsize=((size)*3 ,4))\nfig.suptitle(f'Batch Y extract')\n\nfor i in range(size):\n    ax[i].imshow(1-batch_Y[i, :, :, 0], cmap=\"gray\")\n    ax[i].set_title(f'{i}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = keras.Sequential(\n    [\n        keras.Input(shape=(GRID_HEIGHT, GRID_WIDTH, 1)),\n        layers.Conv2D(64, kernel_size=(3, 3), padding=\"SAME\"),\n        layers.BatchNormalization(),\n        layers.Activation(activations.relu),\n        layers.Conv2D(64, kernel_size=(3, 3), padding=\"SAME\"),\n        layers.BatchNormalization(),\n        layers.Activation(activations.relu),\n        layers.Conv2D(128, kernel_size=(5, 5), padding=\"SAME\"),\n        layers.BatchNormalization(),\n        layers.Activation(activations.relu),\n        layers.Conv2D(64, kernel_size=(3, 3), padding=\"SAME\"),\n        layers.BatchNormalization(),\n        layers.Activation(activations.relu),\n        layers.Conv2D(64, kernel_size=(3, 3), padding=\"SAME\"),\n        layers.BatchNormalization(),\n        layers.Activation(activations.relu),\n        layers.Conv2D(1, kernel_size=(3, 3), padding=\"SAME\"),\n        layers.Activation(activations.sigmoid)\n    ]\n)\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Train loop"},{"metadata":{"trusted":true},"cell_type":"code","source":"sequence = ImageSequence(start, delta=20, batch_size=512)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = 1\n\nmodel.compile(loss=\"bce\", optimizer=\"rmsprop\", metrics=[\"accuracy\"])\nhistory = model.fit_generator(sequence, epochs=epochs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"# summarize history for accuracy\nplt.plot(history.history['accuracy'])\nplt.title('Model accuracy')\nplt.ylabel('Accuracy')\nplt.xlabel('Epoch')\nplt.legend(['train'], loc='upper left')\nplt.show()\n\n# summarize history for loss\nplt.plot(history.history['loss'])\nplt.title('Model loss')\nplt.ylabel('Loss')\nplt.xlabel('Epoch')\nplt.legend(['train'], loc='upper left')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_predicted_start(stop, delta):\n    predicted = model.predict(stop.reshape((1, GRID_HEIGHT, GRID_WIDTH, 1)))\n    for i in range(delta-1):\n        predicted = model.predict(predicted)\n    return predicted","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"idx = 10\n\npredicted = get_predicted_start(stop[idx], train_val.loc[idx, \"delta\"])\n\nfig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(9 ,4))\nfig.suptitle(f'Delta: {train_val.loc[idx, \"delta\"]}')\nax1.imshow(1-(stop[idx, 0, :]), cmap=\"gray\")\nax1.set_title(\"Stop Setting\")\nax2.imshow(1-(start[idx, 0, :]), cmap=\"gray\")\nax2.set_title(\"Start Setting\")\nax3.imshow(1-(predicted[0, :, :, 0]>=0.5), cmap=\"gray\")\nax3.set_title(\"Predicted Setting\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Prediction"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_val = pd.read_csv('/kaggle/input/conways-reverse-game-of-life-2020/test.csv', index_col='id')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"max_delta = max(test_val['delta'])\nbuckets = {}\n\nfor d in range(1, max_delta+1):\n    buckets[d] = line2grid(test_val.loc[test_val['delta'] == d].iloc[:,1:626])\n    print(d, len(buckets[d]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_predictions(stop, delta):\n    predictions = model.predict(stop.reshape((-1, GRID_HEIGHT, GRID_WIDTH, 1)))\n    for i in range(delta-1):\n        predictions = model.predict(predictions)\n    return predictions","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def prepare_submission(buckets, threshold=0.5, sample_submission_path='/kaggle/input/conways-reverse-game-of-life-2020/sample_submission.csv'):\n    submission_file = pd.read_csv(sample_submission_path, index_col='id', nrows=1)\n    dfs = []\n    for d, imgs in buckets.items():\n        print('Making prediction for bucket', d)\n        predictions = make_predictions(imgs, d)\n        predictions = (predictions > threshold).astype(int).reshape(-1, 25*25)\n        df = pd.DataFrame(predictions, index=test_val.loc[test_val['delta'] == d].index.tolist(), columns=submission_file.columns.tolist())\n        dfs.append(df)\n    return pd.concat(dfs).sort_index()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = prepare_submission(buckets)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_csv('submission.csv', index_label='id')\nsubmission","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}