{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport numpy as np\nimport pandas as pd\nimport torch.utils.data\nimport matplotlib.pyplot as plt\n# ref: https://www.kaggle.com/code/t0m0ff3l/top-score-using-nearest-neighbours","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = pd.read_csv('./datasets/digit-recognizer/train.csv')\ntest_data = pd.read_csv('./datasets/digit-recognizer/test.csv')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train = train_data.loc[:,'pixel0':'pixel783'].values\ny_train = train_data['label'].values","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_test = test_data.values\nX_train.shape, y_train.shape, X_test.shape","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*||X_i - Y_j||^2 = ||X_i||^2 + ||Y_j||^2 - 2<X_i, Y_j>*\n\n- ||v||^2 is the squared Euclidean norm of vector v.\n- <X_i, Y_j> is the dot product between X_i and Y_j\n\nwe can use **pairwise_distances** to calculate the distances between the given point and all other points, and then select the nearest neighbors based on these distances.","metadata":{}},{"cell_type":"code","source":"# view: reshapes the tensor without copying memory, similar to numpy's reshape.\n# mm: matmal  \n# clamp: set bouding box make sure that's not negative distance : \n# torch.clamp(torch.tensor([-10,2000]), 0 , 5000) -> tensor([   0, 2000])\ndef pairwise_distances(x, y):\n    x_norm = (x**2).sum(1).view(-1, 1)\n    y_norm = (y**2).sum(1).view(1, -1)\n    y_t = torch.transpose(y, 0, 1)\n    \n    dist = x_norm + y_norm - 2.0 * torch.mm(x, y_t)\n    return torch.clamp(dist, 0.0, np.inf)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"pin_memory : When we **transfer data** from CPU memory to GPU memory, the data is first copied from the CPU to a pinned memory location, and then from there to GPU memory. Pinned memory has several advantages over regular memory, including faster data transfer rates and reduced CPU overhead.","metadata":{}},{"cell_type":"code","source":"%%time\nX_train = torch.from_numpy(X_train).float()\nX_test = torch.from_numpy(X_test).float()\n\nBATCH_SIZE = 128\ndataset = torch.utils.data.TensorDataset(X_test) # compare what's the most nearest or looklike X_train\ndataloader = torch.utils.data.DataLoader(dataset, batch_size=BATCH_SIZE, pin_memory=False)\n_min_dists = []\n_arg_min_dists = []\n\n# min: return -> minimum values and argmin \n# axis=0 : along/each column\nfor batch, in dataloader : # , = x[0]\n    min_distance, arg_min_distance = pairwise_distances(X_train, batch).min(axis=0)\n    _min_dists.append(min_distance)\n    _arg_min_dists.append(arg_min_distance)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"min_dists = torch.cat(_min_dists, axis=0)\narg_min_dists = torch.cat(_arg_min_dists, axis=0)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"min_dists.shape, arg_min_dists.shape","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# find the most looklike in X_train then see what that X_train label is.\nprint(f'this X_test: {arg_min_dists[0]} look like -> {y_train[arg_min_dists[0]]}')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub = pd.read_csv('./datasets/digit-recognizer/sample_submission.csv')\nsub.Label = y_train[arg_min_dists] # what is X_test loolike X_train index the most  \nsub.to_csv('./datasets/digit-recognizer/submission.csv', index=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(15, 15, figsize=(25,25))\nfor i, ax in enumerate(axs.flatten()):\n    ax.set_title(sub.Label[i])\n    ax.imshow(X_test[i].reshape(28,28), cmap='binary')\n    ax.axis('off')","metadata":{},"execution_count":null,"outputs":[]}]}