{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Predicting 3D World position from Car bounding boxes.\n\nThis kernel aims to find a model which, given a 2D bounding box (defined as the center and its height/width), can predict the position of a car in the real world (distance, height and lateral displacement).\n\nHere I test several baseline models and, later, fine tune the best one.\n\nThe dataset I'm going to be using is a derived one (built by me): https://www.kaggle.com/alvaroibrain/carworldpositions, which contains the features mentioned above. The dataset has been made from the Baidu one using YOLO for finding the bounding boxes and then, finding the matches between the BBoxes and the real world points.\n\nHope this approach can serve you to improve your predictions."},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport seaborn as sns\nimport pandas as pd\nimport joblib\n\nimport sklearn\nfrom sklearn import preprocessing\nfrom sklearn import model_selection\nfrom sklearn import tree\nfrom sklearn import ensemble\nfrom sklearn import neighbors\n\nfrom sklearn import multioutput\nfrom sklearn import metrics\nfrom sklearn import svm\nfrom sklearn.gaussian_process.kernels import DotProduct, WhiteKernel, Matern, RBF\n\nfrom matplotlib import pyplot as plt\n\nsns.set(style=\"dark\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMAGE_WIDTH = 3384\nIMAGE_HEIGHT = 2710","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def print_metrics(test_set, predictions):\n    print(\"Test metrics\")\n    print(\"-\"*20)\n    \n    wx_error = sklearn.metrics.mean_absolute_error(test_set['wx'], predictions[:, 0])\n    wy_error = sklearn.metrics.mean_absolute_error(test_set['wy'], predictions[:, 1])\n    wz_error = sklearn.metrics.mean_absolute_error(test_set['wz'], predictions[:, 2])\n    \n    wx_r2 = sklearn.metrics.r2_score(test_set['wx'], predictions[:, 0])\n    wy_r2 = sklearn.metrics.r2_score(test_set['wy'], predictions[:, 1])\n    wz_r2 = sklearn.metrics.r2_score(test_set['wz'], predictions[:, 2])\n\n    print(f\"- WX error {wx_error}\")\n    print(f\"- WY error {wy_error}\")\n    print(f\"- WZ error {wz_error}\")\n\n    print(\"\")\n    print(f\"- WX R2 score {wx_r2}\")\n    print(f\"- WY R2 score {wy_r2}\")\n    print(f\"- WZ R2 score {wz_r2}\")\n    \n    return wx_error, wy_error, wz_error, wx_r2, wy_r2, wz_r2\n          \ndef plot_predictions(test_set, predictions, fig, ax):\n          \n    line_kws = {'color':'black', 'linestyle':'--', 'linewidth':2}\n    scatter_kws = {'s':1}\n    \n    ax[0].set_title('World X')\n    ax[1].set_title('World Y')\n    ax[2].set_title('World Z')\n\n    ax[0] = sns.regplot(test_set['wx'], predictions[:, 0], ax=ax[0], line_kws=line_kws, scatter_kws=scatter_kws)\n    ax[1] = sns.regplot(test_set['wy'], predictions[:, 1], ax=ax[1], line_kws=line_kws, scatter_kws=scatter_kws)\n    ax[2] = sns.regplot(test_set['wz'], predictions[:, 2], ax=ax[2], line_kws=line_kws, scatter_kws=scatter_kws)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataf = pd.read_csv('../input/carworldpositions/data_points.csv').drop('Unnamed: 0', axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataf.describe()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Remove outliers\ndataf = dataf[dataf['wx'] < 100]\ndataf = dataf[dataf['wy'] < 100]\ndataf = dataf[dataf['wz'] < 100]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.pairplot(dataf)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Normalization (and centering) for some of the algorithms (knn, svm or nn)\ndataf['Cx'] /= IMAGE_WIDTH\ndataf['Cy'] /= IMAGE_HEIGHT\n\nscaler = sklearn.preprocessing.StandardScaler()\ndataf[['wx', 'wy', 'wz']] = scaler.fit_transform(dataf[['wx', 'wy', 'wz']])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Train test split\nmask = np.random.random(len(dataf)) > 0.7\n\ndtrain = dataf[mask]\ndtest = dataf[~mask]\n\n# Predictor and target variable names\npredictors = ['Cx', 'Cy', 'bh', 'bw']\ntargets = ['wx', 'wy', 'wz']","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model selection\n\nWe will test baseline models to choose one to do the fine-tuning"},{"metadata":{"trusted":true},"cell_type":"code","source":"# DataFrame to store the results\ntest_metrics = pd.DataFrame(columns=['Method', 'WX_Error', 'WY_Error', 'WZ_Error', 'WX_r2', 'WY_r2', 'WZ_r2'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Random Forest"},{"metadata":{"trusted":true},"cell_type":"code","source":"rf = sklearn.ensemble.RandomForestRegressor(n_estimators=200)\nrf = rf.fit(X=dtrain[predictors], y=dtrain[targets])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = rf.predict(dtest[predictors])","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"results = print_metrics(dtest, preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_metrics = test_metrics.append(pd.Series(('RF', *results), index=test_metrics.columns), ignore_index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(3, figsize=(15,16))\nplot_predictions(dtest, preds, fig, ax)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Boosting"},{"metadata":{"trusted":true},"cell_type":"code","source":"bt = sklearn.ensemble.GradientBoostingRegressor()\n\nmor = sklearn.multioutput.MultiOutputRegressor(bt)\nmor = mor.fit(X=dtrain[predictors], y=dtrain[targets])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = mor.predict(dtest[predictors])","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"results = print_metrics(dtest, preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_metrics = test_metrics.append(pd.Series(('BoostingT', *results), index=test_metrics.columns), \n                                   ignore_index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(3, figsize=(15,16))\nplot_predictions(dtest, preds, fig, ax)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## KNN"},{"metadata":{"trusted":true},"cell_type":"code","source":"knn = neighbors.KNeighborsRegressor(10)\nknn = knn.fit(X=dtrain[predictors], y=dtrain[targets])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = knn.predict(dtest[predictors])","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"results = print_metrics(dtest, preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_metrics = test_metrics.append(pd.Series(('KNN', *results), index=test_metrics.columns), \n                                   ignore_index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(3, figsize=(15,16))\nplot_predictions(dtest, preds, fig, ax)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## SVM"},{"metadata":{"trusted":true},"cell_type":"code","source":"svr = sklearn.svm.SVR(gamma='scale')\n\nmor = sklearn.multioutput.MultiOutputRegressor(svr)\nmor = mor.fit(X=dtrain[predictors], y=dtrain[targets])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = mor.predict(dtest[predictors])","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"results = print_metrics(dtest, preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_metrics = test_metrics.append(pd.Series(('SVM', *results), index=test_metrics.columns), \n                                   ignore_index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(3, figsize=(15,16))\nplot_predictions(dtest, preds, fig, ax)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Neural net"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow import keras as k","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inp = k.layers.Input(shape=(len(predictors),))\nh = k.layers.Dense(300, activation='linear')(inp)\nh = k.layers.Dropout(.3)(h)\nh = k.layers.Dense(500, activation='relu')(h)\nh = k.layers.Dropout(.1)(h)\nh = k.layers.Dense(300, activation='linear')(h)\nh = k.layers.Dense(200, activation='linear')(h)\nh = k.layers.Dense(200, activation='selu')(h)\nout = k.layers.Dense(3, activation='linear')(h)\n\nmodel = k.models.Model(inputs=inp, outputs=out)\n\nmodel.compile(k.optimizers.Adam(), loss='mse')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"h = model.fit(x=dtrain[predictors].values, y=dtrain[targets].values, \n              validation_split=.3, epochs=10, batch_size=16)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = model.predict(dtest[predictors].values)","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"results = print_metrics(dtest, preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_metrics = test_metrics.append(pd.Series(('NN', *results), index=test_metrics.columns), \n                                   ignore_index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(3, figsize=(15,16))\nplot_predictions(dtest, preds, fig, ax)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Results"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_metrics","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Random Forest seems to be the baseline winner. I will finetune it.\n\nThe X position (lateral displacement is well predicted), however, Y and Z have a little more variance. This needs to be improved."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Reload dataset without normalization\ndataf = pd.read_csv('../input/carworldpositions/data_points.csv').drop('Unnamed: 0', axis=1)\n# Remove outliers\ndataf = dataf[dataf['wx'] < 100]\ndataf = dataf[dataf['wy'] < 100]\ndataf = dataf[dataf['wz'] < 100]\n\ndtrain = dataf[mask]\ndtest = dataf[~mask]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"rf = sklearn.ensemble.RandomForestRegressor()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"param_grid = {\n    'n_estimators':[200, 400, 500, 800, 1000, 2000]\n}\n\ngs = sklearn.model_selection.GridSearchCV(rf, n_jobs=4, param_grid=param_grid)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"gs = gs.fit(dtrain[predictors], dtrain[targets])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.concat([pd.DataFrame(gs.cv_results_[\"params\"]),\n           pd.DataFrame(gs.cv_results_[\"mean_test_score\"], columns=[\"MSE\"])],axis=1)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"200 trees seems OK"},{"metadata":{"trusted":true},"cell_type":"code","source":"rf = sklearn.ensemble.RandomForestRegressor(n_estimators=200)\nrf = rf.fit(X=dtrain[predictors], y=dtrain[targets])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = rf.predict(dtest[predictors])","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"results = print_metrics(dtest, preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"# Save the model if you need it\n# joblib.dump(rf, 'pos_predictor.joblib')","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"nbformat":4,"nbformat_minor":1}