{"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":"markdown","source":"# ASHRAE with fast.ai, Part 3: Inference","metadata":{}},{"cell_type":"markdown","source":"This kernel leverages the convenient fast.ai API to prepare the test set for inference in just a few lines of code.\n\nIn order to combine the large size of the ASHRAE dataset and the overhead of fast.ai's objects with the limited memory of Kaggle sessions, this kernel is part of a series which further includes:\n\n- https://www.kaggle.com/michelezoccali/ashrae-with-fast-ai-part-1 (preprocessing)\n- https://www.kaggle.com/michelezoccali/ashrae-with-fast-ai-part-2 (training)","metadata":{}},{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"import os\nimport gc\nimport sys\nimport pickle\n\nimport numpy as np\nimport pandas as pd\n\nfrom tqdm.notebook import tqdm\nfrom fastai.tabular.all import *\n\n# plotting\nimport seaborn as sns","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-07-03T14:56:09.538427Z","iopub.execute_input":"2021-07-03T14:56:09.538890Z","iopub.status.idle":"2021-07-03T14:56:10.569155Z","shell.execute_reply.started":"2021-07-03T14:56:09.538792Z","shell.execute_reply":"2021-07-03T14:56:10.568262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_path = '../input/ashrae-with-fast-ai-part-1/'\nmodel_path = '../input/ashrae-with-fast-ai-part-2/'\n\nfor path in [data_path, model_path]:\n    for dirname, _, filenames in os.walk(path):\n        for filename in filenames:\n            print(os.path.join(dirname, filename))","metadata":{"execution":{"iopub.status.busy":"2021-07-03T14:56:10.570746Z","iopub.execute_input":"2021-07-03T14:56:10.571109Z","iopub.status.idle":"2021-07-03T14:56:10.589501Z","shell.execute_reply.started":"2021-07-03T14:56:10.571071Z","shell.execute_reply":"2021-07-03T14:56:10.588744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prepare test dataset","metadata":{}},{"cell_type":"code","source":"#%%time\nX_test = pd.read_hdf(data_path + 'preprocessing_no_lag.h5', 'test')\nX_test.info()","metadata":{"execution":{"iopub.status.busy":"2021-07-03T14:56:10.591450Z","iopub.execute_input":"2021-07-03T14:56:10.591810Z","iopub.status.idle":"2021-07-03T14:56:28.172873Z","shell.execute_reply.started":"2021-07-03T14:56:10.591773Z","shell.execute_reply":"2021-07-03T14:56:28.170904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"row_ids = X_test.row_id # for submission file\nX_test = X_test.drop(columns='row_id')\n\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-07-03T14:56:28.174818Z","iopub.execute_input":"2021-07-03T14:56:28.175195Z","iopub.status.idle":"2021-07-03T14:56:29.300704Z","shell.execute_reply.started":"2021-07-03T14:56:28.175154Z","shell.execute_reply":"2021-07-03T14:56:29.299708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"procs_nn = [Categorify, Normalize]\ncont = ['building_id','square_feet','year_built','floor_count','air_temperature','cloud_coverage',\n       'dew_temperature','precip_depth_1_hr']\ncat = ['meter','site_id','primary_use','hour','weekday']","metadata":{"execution":{"iopub.status.busy":"2021-07-03T14:56:29.302187Z","iopub.execute_input":"2021-07-03T14:56:29.302556Z","iopub.status.idle":"2021-07-03T14:56:30.779934Z","shell.execute_reply.started":"2021-07-03T14:56:29.302517Z","shell.execute_reply":"2021-07-03T14:56:30.779024Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's create a TabularPandas instance with the same transforms of the training set.","metadata":{}},{"cell_type":"code","source":"test = TabularPandas(X_test, procs_nn, cat, cont, inplace=True, reduce_memory=True)\n\ndel X_test, procs_nn, cat, cont\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-07-03T14:56:30.781347Z","iopub.execute_input":"2021-07-03T14:56:30.781723Z","iopub.status.idle":"2021-07-03T14:57:09.971405Z","shell.execute_reply.started":"2021-07-03T14:56:30.781660Z","shell.execute_reply":"2021-07-03T14:57:09.970434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can now load our trained neural network back in...","metadata":{}},{"cell_type":"code","source":"with open(f'{model_path}/tabular_nn.pickle', mode='rb') as f:\n    learn = pickle.load(f)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"...and predict with it.","metadata":{}},{"cell_type":"code","source":"n_iterations = 30\nbatch_size = len(test) // n_iterations\n\npreds = []\nfor i in tqdm(range(n_iterations)):\n    start = i * batch_size\n    test_batch = test.iloc[start:start + batch_size]\n    test_dl = TabDataLoader(test_batch, bs=batch_size, shuffle=False, drop_last=False)\n    \n    del test_batch; gc.collect()\n    \n    batch_preds, _ = learn.get_preds(dl=test_dl)\n    batch_preds = to_np(batch_preds.squeeze())\n    preds.extend(np.expm1(batch_preds))\n    \n    del test_dl, batch_preds; gc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-07-03T14:58:01.891118Z","iopub.execute_input":"2021-07-03T14:58:01.891625Z","iopub.status.idle":"2021-07-03T15:00:02.744975Z","shell.execute_reply.started":"2021-07-03T14:58:01.891572Z","shell.execute_reply":"2021-07-03T15:00:02.744053Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"At last, we can save our predictions (clipped at 0 on the left as negative meter readings do not make much sense) and inspect their distribution.","metadata":{}},{"cell_type":"code","source":"submission = pd.DataFrame({'row_id':row_ids, 'meter_reading':np.clip(preds, 0, a_max=None)})\nsubmission.to_csv('submission.csv', index=False)\n\ndel preds","metadata":{"execution":{"iopub.status.busy":"2021-07-03T15:00:43.797564Z","iopub.execute_input":"2021-07-03T15:00:43.797969Z","iopub.status.idle":"2021-07-03T15:03:00.386841Z","shell.execute_reply.started":"2021-07-03T15:00:43.797935Z","shell.execute_reply":"2021-07-03T15:03:00.385787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"logs = np.log1p(submission.meter_reading)\nprint(logs.shape)\nnp.log1p(submission.meter_reading).hist(bins=100);","metadata":{"execution":{"iopub.status.busy":"2021-07-03T15:03:17.547197Z","iopub.execute_input":"2021-07-03T15:03:17.547600Z","iopub.status.idle":"2021-07-03T15:03:20.053109Z","shell.execute_reply.started":"2021-07-03T15:03:17.547566Z","shell.execute_reply":"2021-07-03T15:03:20.052194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#sns.displot(logs);","metadata":{"execution":{"iopub.status.busy":"2021-07-03T15:03:25.960734Z","iopub.execute_input":"2021-07-03T15:03:25.961076Z","iopub.status.idle":"2021-07-03T15:03:59.598434Z","shell.execute_reply.started":"2021-07-03T15:03:25.961047Z","shell.execute_reply":"2021-07-03T15:03:59.597578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.meter_reading.min(), submission.meter_reading.max(), submission.meter_reading.mean()","metadata":{"execution":{"iopub.status.busy":"2021-07-03T15:04:28.332888Z","iopub.execute_input":"2021-07-03T15:04:28.333276Z","iopub.status.idle":"2021-07-03T15:04:28.789061Z","shell.execute_reply.started":"2021-07-03T15:04:28.333243Z","shell.execute_reply":"2021-07-03T15:04:28.788001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"And now we are done!\n\nIf anyone has any tips regarding a better management of memory resources (with or without fast.ai classes), so as to fit all of this in a single kernel for instance, they'd be greatly appreciated! 😉","metadata":{}}]}