{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.autograd import Variable\nimport torch\nfrom tqdm import tqdm\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def evolve(x): \n    # Weights for layer 1\n    weight1 = torch.tensor([[[1, 1, 1], [1, 0.1, 1], [1, 1, 1]],\n                            [[1, 1, 1], [1, 1, 1], [1, 1, 1]]]).view(2, 1, 3, 3).float()\n    b1 = torch.tensor([-3, -2]).float()\n    # Weights for layer 2\n    weight2 = torch.tensor([-10, 1]).view(1, 2, 1, 1).float()\n    # Weights for layer 3\n    s = 20\n    weight3 = torch.tensor([2*s]).view(1, 1, 1, 1).float()\n    b3 = torch.tensor([-s]).float()\n  \n    x = F.pad(x.float(), (1, 1, 1, 1), mode='circular')\n    x = F.relu(F.conv2d(x, weight1, b1))\n    x = F.relu(F.conv2d(x, weight2))\n    x = torch.sigmoid(F.conv2d(x, weight3, b3))\n    return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_data(train=True):\n    if train:\n        df = pd.read_csv('/kaggle/input/conways-reverse-game-of-life-2020/train.csv')\n    else:\n        df = pd.read_csv('/kaggle/input/conways-reverse-game-of-life-2020/test.csv')\n    n = len(df)\n    columns = df.columns\n    delta = df.delta.to_numpy()\n    stop_boards = df[[col for col in columns if col.startswith('stop')]].to_numpy()\n    stop_boards = stop_boards.reshape(n, 1, 25, 25)\n    if train:\n        start_boards = df[[col for col in columns if col.startswith('start')]].to_numpy()\n        start_boards = start_boards.reshape(n, 1, 25, 25)\n        return delta, start_boards, stop_boards\n    \n    return delta, stop_boards","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train_deltas, train_start_boards, train_stop_boards = get_data()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def advance(boards, deltas, num_iters=5):\n    \"\"\" Advance boards that have delta less than num_iters.\n    \"\"\"\n    advanced_boards = np.zeros_like(boards)\n    for i, delta in enumerate(deltas):\n        tmp_board = torch.tensor(boards[i,0,:,:]).reshape(1,1,25,25).int()\n        for _ in range(num_iters - delta):\n            tmp_board = evolve(tmp_board)\n        advanced_boards[i,0,:,:] = tmp_board.int().numpy()\n    return advanced_boards","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_boards = advance(train_stop_boards, train_deltas)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class ReverseNet(nn.Module):\n    def __init__(self):\n        super(ReverseNet, self).__init__()\n        # in channels, out channels, kernel size\n        self.conv1 = nn.Conv2d(1, 16, (5, 5), padding=(2, 2), padding_mode='circular')\n        self.activ1 = nn.PReLU()\n        self.conv2 = nn.Conv2d(16, 8, (5, 5), padding=(2, 2), padding_mode='circular')\n        self.activ2 = nn.PReLU()\n        self.conv3 = nn.Conv2d(8, 4, (3, 3), padding=(1, 1), padding_mode='circular')\n        self.activ3 = nn.PReLU()\n        self.conv4 = nn.Conv2d(4, 1, (3, 3), padding=(1, 1), padding_mode='circular')\n\n    def forward(self, x):\n        x = self.reverse(x)\n        return x\n\n    def reverse(self, x):\n        x = self.activ1(self.conv1(x))\n        x = self.activ2(self.conv2(x))\n        x = self.activ3(self.conv3(x))\n        x = torch.sigmoid(self.conv4(x))\n        return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"net = ReverseNet()\nif torch.cuda.is_available():\n    net.cuda()\nprint(net)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = nn.BCELoss()\noptimizer = optim.Adam(net.parameters()) #, lr=0.001, momentum=0.9)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X = Variable(torch.tensor(train_boards).float(), requires_grad=True).cuda()\ny = Variable(torch.tensor(train_start_boards).float()).cuda()\nnum_epochs = 60\nbatch_size = 500\nfor epoch in tqdm(range(num_epochs)): \n    permutation = torch.randperm(X.size()[0])\n    running_loss = 0.0\n    for i in range(0, X.size()[0], batch_size):\n        indices = permutation[i:i+batch_size]\n        batch = X[indices]\n        target = y[indices]\n        \n        optimizer.zero_grad()\n        outputs = net(batch)\n        # loss = criterion(outputs, batch)\n        loss = criterion(outputs, target)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        if i % 1000 == 0 and i > 0:\n            print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 10))\n        running_loss = 0.0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_deltas, test_stop_boards = get_data(False)\ntest_boards = advance(test_stop_boards, test_deltas)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_test = Variable(torch.tensor(test_boards).float()).cuda()\nwith torch.no_grad():\n    net.eval()\n    predictions = (net(X_test) > 0.5).int()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/conways-reverse-game-of-life-2020/test.csv')\nsample_submission = pd.read_csv('/kaggle/input/conways-reverse-game-of-life-2020/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred_df = df[['id']].copy()\nn = len(pred_df)\npred = predictions.cpu().numpy().reshape(n, 625)\nfor i in range(625):\n    pred_df['start_{}'.format(i)] = pred[:,i]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred_df.to_csv('/kaggle/working/submission.csv', index=False)","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}