{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"},{"sourceId":12718848,"sourceType":"datasetVersion","datasetId":7957110}],"dockerImageVersionId":31090,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true},"colab":{"provenance":[]},"widgets":{"application/vnd.jupyter.widget-state+json":{"f5024ac085654bf7a278be4a2cab0deb":{"model_module":"@jupyter-widgets/controls","model_name":"HBoxModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e55293785b4f415fb3c614a336d321f9","IPY_MODEL_e81ebfde57f343fbaa2f547d8585f356","IPY_MODEL_92915cf19b314ebc8f515d0d73042d7c"],"layout":"IPY_MODEL_7da211e8ee35498ea11ab22ec051013d"}},"e55293785b4f415fb3c614a336d321f9":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_5e27a01a52894ce99ed7650dec19ae03","placeholder":"​","style":"IPY_MODEL_79d28a6237444f33a843a00cf13ac5b7","value":"Testing: 100%"}},"e81ebfde57f343fbaa2f547d8585f356":{"model_module":"@jupyter-widgets/controls","model_name":"FloatProgressModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_26e8547c66784859b7554a12a8686c54","max":26,"min":0,"orientation":"horizontal","style":"IPY_MODEL_f12f1115c0c546cbae05ade0f2504f71","value":26}},"92915cf19b314ebc8f515d0d73042d7c":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_724743b5f8be46b8b67881bf653138ce","placeholder":"​","style":"IPY_MODEL_70052737eb22489b8a2f5953cbccef5b","value":" 26/26 [00:02&lt;00:00, 12.01it/s]"}},"7da211e8ee35498ea11ab22ec051013d":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5e27a01a52894ce99ed7650dec19ae03":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"79d28a6237444f33a843a00cf13ac5b7":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"26e8547c66784859b7554a12a8686c54":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f12f1115c0c546cbae05ade0f2504f71":{"model_module":"@jupyter-widgets/controls","model_name":"ProgressStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"724743b5f8be46b8b67881bf653138ce":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"70052737eb22489b8a2f5953cbccef5b":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"94aaa879fcfc4592a9555294a27a51f2":{"model_module":"@jupyter-widgets/controls","model_name":"VBoxModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_57ad032890014d52b245577cda49c650"],"layout":"IPY_MODEL_09edad9ae5ae4975975c4dcabf4c7d73"}},"9498f6998a664fe5acfc66fb5c207740":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_b544d539f65a45b4ae6a57d77febe633","placeholder":"​","style":"IPY_MODEL_255f7af55c0049409b71ff185ee8fc23","value":"<center> <img\nsrc=https://www.kaggle.com/static/images/site-logo.png\nalt='Kaggle'> <br> Create an API token from <a\nhref=\"https://www.kaggle.com/settings/account\" target=\"_blank\">your Kaggle\nsettings page</a> and paste it below along with your Kaggle username. <br> </center>"}},"02450833be6044dbb88ca1e1afb936b4":{"model_module":"@jupyter-widgets/controls","model_name":"TextModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"TextModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"TextView","continuous_update":true,"description":"Username:","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_8fbc89a2ee7c4233bf3a7c29d58d7a7d","placeholder":"​","style":"IPY_MODEL_ae892c1278ee45a99691ab57cea02158","value":"yassermessahli"}},"f0d78ede966441638f065d21197a9741":{"model_module":"@jupyter-widgets/controls","model_name":"PasswordModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"PasswordModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"PasswordView","continuous_update":true,"description":"Token:","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_e6c6d9e0ed2b495085d82e1c82a9f7c1","placeholder":"​","style":"IPY_MODEL_2c21c7e36f924865bcd20ade1f826c0e","value":""}},"90737dda99d140648bc7f1caddac4273":{"model_module":"@jupyter-widgets/controls","model_name":"ButtonModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"","description":"Login","disabled":false,"icon":"","layout":"IPY_MODEL_4454c90ccaed446893f2328b3be1c933","style":"IPY_MODEL_b8f06af6c44443a3b932558459dedaa4","tooltip":""}},"6e2648a288f845488982eb89d5b33e2a":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_4502339609a64c62b1826354a3ad57fa","placeholder":"​","style":"IPY_MODEL_9df3e2ada2954ac8b3b384c7225c9dc1","value":"\n<b>Thank You</b></center>"}},"09edad9ae5ae4975975c4dcabf4c7d73":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":"center","align_self":null,"border":null,"bottom":null,"display":"flex","flex":null,"flex_flow":"column","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50%"}},"b544d539f65a45b4ae6a57d77febe633":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"255f7af55c0049409b71ff185ee8fc23":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"8fbc89a2ee7c4233bf3a7c29d58d7a7d":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ae892c1278ee45a99691ab57cea02158":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e6c6d9e0ed2b495085d82e1c82a9f7c1":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2c21c7e36f924865bcd20ade1f826c0e":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"4454c90ccaed446893f2328b3be1c933":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b8f06af6c44443a3b932558459dedaa4":{"model_module":"@jupyter-widgets/controls","model_name":"ButtonStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":null,"font_weight":""}},"4502339609a64c62b1826354a3ad57fa":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9df3e2ada2954ac8b3b384c7225c9dc1":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"ff2ce045b6b148a9a9d0d500b2ccc8e0":{"model_module":"@jupyter-widgets/controls","model_name":"LabelModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_2c87002455fa46a49be6c20250403637","placeholder":"​","style":"IPY_MODEL_56dd14a76cb04c239ad993a694cbd3ec","value":"Connecting..."}},"2c87002455fa46a49be6c20250403637":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"56dd14a76cb04c239ad993a694cbd3ec":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"57ad032890014d52b245577cda49c650":{"model_module":"@jupyter-widgets/controls","model_name":"LabelModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_313cb5ae923a49c3b38ea3b30b66fcf3","placeholder":"​","style":"IPY_MODEL_2c116e456fbd44b99415f6d6aa29edbc","value":"Kaggle credentials successfully validated."}},"313cb5ae923a49c3b38ea3b30b66fcf3":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2c116e456fbd44b99415f6d6aa29edbc":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"c0afb281961a4f37a9507b8d4cda2603":{"model_module":"@jupyter-widgets/controls","model_name":"HBoxModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_005a2423fa0746d0aae03c82a92be21c","IPY_MODEL_924f83c1d8f64a499017908f81f60a94","IPY_MODEL_615db22036094ee1b0370c26eeb2186e"],"layout":"IPY_MODEL_91e41748782e4a588ca0fd62395e3fff"}},"005a2423fa0746d0aae03c82a92be21c":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_bd5db335f65b4360b3a76af6f29c0207","placeholder":"​","style":"IPY_MODEL_2590d690b9d140c0978a82fe540acf83","value":"💠Progress: 100%"}},"924f83c1d8f64a499017908f81f60a94":{"model_module":"@jupyter-widgets/controls","model_name":"FloatProgressModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_f3308464fb9847818eb19ffdf4d4548e","max":7593,"min":0,"orientation":"horizontal","style":"IPY_MODEL_ceb85fe5210446db9608b966b56309ad","value":7593}},"615db22036094ee1b0370c26eeb2186e":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_bc12cae96d6346e2afa1a5a3c9644052","placeholder":"​","style":"IPY_MODEL_c15d23dcac9f43a88e824ec6d86d9d3c","value":" 7593/7593 [00:25&lt;00:00, 442.24it/s]"}},"91e41748782e4a588ca0fd62395e3fff":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bd5db335f65b4360b3a76af6f29c0207":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2590d690b9d140c0978a82fe540acf83":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f3308464fb9847818eb19ffdf4d4548e":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ceb85fe5210446db9608b966b56309ad":{"model_module":"@jupyter-widgets/controls","model_name":"ProgressStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"bc12cae96d6346e2afa1a5a3c9644052":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c15d23dcac9f43a88e824ec6d86d9d3c":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"08cd18e84d2544ebaf20818b552fdadf":{"model_module":"@jupyter-widgets/controls","model_name":"HBoxModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_d69c7bd03383484284cfec1857042047","IPY_MODEL_bf46fcc542324885a4d1cff4243f8d69","IPY_MODEL_16a83d90133147389b3d99dc2d73924e"],"layout":"IPY_MODEL_69fef33be2ce489894b2309bbead0e65"}},"d69c7bd03383484284cfec1857042047":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_d38d86761a984e5da3587a6be51b2c90","placeholder":"​","style":"IPY_MODEL_2ccbf7231f294688bf208870a6bc5b76","value":"💠Epoch 1/70:   1%"}},"bf46fcc542324885a4d1cff4243f8d69":{"model_module":"@jupyter-widgets/controls","model_name":"FloatProgressModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"danger","description":"","description_tooltip":null,"layout":"IPY_MODEL_769aaaeb3fc4494289345a2f86d641e2","max":192,"min":0,"orientation":"horizontal","style":"IPY_MODEL_319c01956a214c75a22d9ec58a9bf657","value":2}},"16a83d90133147389b3d99dc2d73924e":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_ed8a4b1aa0c8499cad8a012fe51aef30","placeholder":"​","style":"IPY_MODEL_2e4d6c094fad4b5988b64e42a316d30e","value":" 2/192 [00:45&lt;52:54, 16.71s/it]"}},"69fef33be2ce489894b2309bbead0e65":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d38d86761a984e5da3587a6be51b2c90":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2ccbf7231f294688bf208870a6bc5b76":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"769aaaeb3fc4494289345a2f86d641e2":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"319c01956a214c75a22d9ec58a9bf657":{"model_module":"@jupyter-widgets/controls","model_name":"ProgressStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"ed8a4b1aa0c8499cad8a012fe51aef30":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2e4d6c094fad4b5988b64e42a316d30e":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}}}}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# CMI - Detect Behavior with Sensor Data\nPredicting Body Focused Repetitive Behaviors from a Wrist-Worn Device.\n\nThis is my main development notebook\n\n","metadata":{"id":"b1rGYPsk_ORp"}},{"cell_type":"markdown","source":"## Background and Competition Overview\nI should fill it laer","metadata":{"id":"zF1tZMFbAQAi"}},{"cell_type":"markdown","source":"## Technics\n\n##### All\n1. variable-length with masking\n2. x4 filter-based batch mixup (32 -> 128), try with different dist for LAMBDA\n3. IMU only + feature enginieering\n\n4. binary + multiclass classification\n5. (IMU+THM+TOF) + orchestration\n6. Ensemble methods\n7. feature enginieering\n\n##### Resutls (technique : score)\n","metadata":{"id":"hhHKRKFF7luP"}},{"cell_type":"markdown","source":"## 1. Setup\n- Download necessary dependancies (tools, datasets, models, libraries, etc)\n- Import libraries\n- Setup development environment","metadata":{"id":"G8M5zE48-uy8"}},{"cell_type":"markdown","source":"### Data source Downloading\nDownload the competition datasets from kaggle - For Colab environment","metadata":{"id":"AHgK6XGKAe_u"}},{"cell_type":"code","source":"# # IMPORTANT: SOME KAGGLE DATA SOURCES ARE PRIVATE\n# # RUN THIS CELL IN ORDER TO IMPORT YOUR KAGGLE DATA SOURCES.\n# import kagglehub\n# kagglehub.login()","metadata":{"id":"lHhR41C7CQjL","trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:19.389783Z","iopub.execute_input":"2025-08-09T13:51:19.390085Z","iopub.status.idle":"2025-08-09T13:51:19.394531Z","shell.execute_reply.started":"2025-08-09T13:51:19.390063Z","shell.execute_reply":"2025-08-09T13:51:19.393790Z"},"outputId":"c789a8f4-c12d-474a-c512-be40fa1335e0"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # IMPORTANT: RUN THIS CELL IN ORDER TO IMPORT YOUR KAGGLE DATA SOURCES,\n# # THEN FEEL FREE TO DELETE THIS CELL.\n# # NOTE: THIS NOTEBOOK ENVIRONMENT DIFFERS FROM KAGGLE'S PYTHON\n# # ENVIRONMENT SO THERE MAY BE MISSING LIBRARIES USED BY YOUR\n# # NOTEBOOK.\n# ENVIRONMENT = 'kaggle'\n\n# if ENVIRONMENT == 'colab':\n#     DATA_PATH = kagglehub.competition_download('cmi-detect-behavior-with-sensor-data')\n# elif ENVIRONMENT == 'kaggle':\n#     DATA_PATH = \"/kaggle/input/cmi-detect-behavior-with-sensor-data\"\n# else:\n#     print(\"ENvironment is not recognized\")\n# print('Data source imported to: ', DATA_PATH)","metadata":{"id":"pctO2A7vCQjR","outputId":"a399d56f-57f2-4216-d19b-910807be58ba","trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:19.399648Z","iopub.execute_input":"2025-08-09T13:51:19.400390Z","iopub.status.idle":"2025-08-09T13:51:19.411507Z","shell.execute_reply.started":"2025-08-09T13:51:19.400320Z","shell.execute_reply":"2025-08-09T13:51:19.410885Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Load modules","metadata":{"id":"_nMs80kE95Yu"}},{"cell_type":"code","source":"print(\"import libraries...\")\n\n# statistical modules\nimport numpy as np\nimport pandas as pd\n\n# visualization moodules\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\n\n# machine learning modules\nimport tensorflow as tf\nfrom tensorflow.keras import layers, regularizers, optimizers, losses, metrics, initializers\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.utils import pad_sequences, to_categorical\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom sklearn.metrics import classification_report\n\n# other modules\nfrom tqdm.notebook import tqdm\nfrom pprint import pprint\nimport warnings\nimport joblib\nimport random\nimport sys\nimport os\nimport gc # garbage collection module","metadata":{"id":"0lGacRadAKMP","trusted":true,"outputId":"105ba911-a20f-448f-f202-342c77fbe641","execution":{"iopub.status.busy":"2025-08-09T13:51:19.414780Z","iopub.execute_input":"2025-08-09T13:51:19.415044Z","iopub.status.idle":"2025-08-09T13:51:37.134176Z","shell.execute_reply.started":"2025-08-09T13:51:19.415026Z","shell.execute_reply":"2025-08-09T13:51:37.133570Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Setup environment","metadata":{"id":"z2FBGGnLB37s"}},{"cell_type":"code","source":"DEBUG_MODE = \"ignore\"\nwarnings.filterwarnings(action=DEBUG_MODE)\n\n# Enable Mixed Precision Training\n# This can significantly speed up training on modern GPUs/TPUs by using float16 for computations\n# policy = tf.keras.mixed_precision.Policy('mixed_float16')\n# tf.keras.mixed_precision.set_global_policy(policy)\n\n\n# Enable XLA\n# tf.config.optimizer.set_jit(True)\n\n\n# Sets a uniform random seed for reproducibility across different libraries.\ndef seed_everything(seed=42):\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    random.seed(seed)\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    tf.experimental.numpy.random.seed(seed)\n\nseed_everything(42)\n\n# print tensorflow metrics\nprint(\"TensorFlow version:\", tf.__version__)\nprint(\"Num GPUs Available: \", len(tf.config.list_physical_devices('GPU')))","metadata":{"id":"JrpCAyODB4Q3","trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:37.135598Z","iopub.execute_input":"2025-08-09T13:51:37.136180Z","iopub.status.idle":"2025-08-09T13:51:38.176680Z","shell.execute_reply.started":"2025-08-09T13:51:37.136152Z","shell.execute_reply":"2025-08-09T13:51:38.176013Z"},"outputId":"9bb67691-09cb-4f7c-f651-efa76d668f2e"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2. Data","metadata":{"id":"wxg53z2q98UN"}},{"cell_type":"markdown","source":"### Import data","metadata":{"id":"4Y6X8UrZ-ebY"}},{"cell_type":"code","source":"# # load tain dataset\n# train_df = pd.read_csv(os.path.join(DATA_PATH, 'train.csv'))\n\n# # Optional unimportant datasets\n# # test_df = pd.read_csv(os.path.join(DATA_PATH, 'test.csv'))\n# # train_demographics_df = pd.read_csv(os.path.join(DATA_PATH, 'train_demographics.csv'))\n# # test_demographics_df = pd.read_csv(os.path.join(DATA_PATH, 'test_demographics.csv'))","metadata":{"trusted":true,"id":"AFVUUHecCQjX","execution":{"iopub.status.busy":"2025-08-09T13:51:38.177560Z","iopub.execute_input":"2025-08-09T13:51:38.177878Z","iopub.status.idle":"2025-08-09T13:51:38.215152Z","shell.execute_reply.started":"2025-08-09T13:51:38.177850Z","shell.execute_reply":"2025-08-09T13:51:38.214286Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### EDA","metadata":{"id":"SmMtqShe-j3e"}},{"cell_type":"code","source":"# implemented in another notebook","metadata":{"id":"OQ3eFCJ4EBOc","trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:38.217302Z","iopub.execute_input":"2025-08-09T13:51:38.217574Z","iopub.status.idle":"2025-08-09T13:51:38.231222Z","shell.execute_reply.started":"2025-08-09T13:51:38.217555Z","shell.execute_reply":"2025-08-09T13:51:38.230466Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# train_df.groupby(\"sequence_id\").agg({\"sequence_counter\":\"count\"}).hist(bins=100)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:38.231985Z","iopub.execute_input":"2025-08-09T13:51:38.232232Z","iopub.status.idle":"2025-08-09T13:51:38.247179Z","shell.execute_reply.started":"2025-08-09T13:51:38.232214Z","shell.execute_reply":"2025-08-09T13:51:38.246281Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Preprocessing","metadata":{"id":"ZN1B5Jsx-mTl"}},{"cell_type":"code","source":"# imu_thm_cols = [c for c in train_df.columns if c.startswith(('acc_','rot_', 'thm_'))]\n# tof_cols = [c for c in train_df.columns if c.startswith('tof_')]\n\n\n# # Nulls ratio per IMU/THM column per sequence_id\n# imu_thm_nulls_ratio = train_df.groupby('sequence_id')[imu_thm_cols].apply(lambda x: x.isna().mean())\n# # All-TOF-Pixels Nulls ratio per sequence_id\n# tof_nulls_ratio = (\n#     train_df.groupby('sequence_id')[tof_cols]\n#     .apply(lambda x: x.isna().sum().sum() / x.size)\n#     .rename('tof')\n# )\n# # Nulls ratio summary\n# summary = pd.concat([imu_thm_nulls_ratio, tof_nulls_ratio], axis=1)\n\n# # final mask: any ratio >= 10%\n# mask = summary[imu_thm_cols].ge(0.1).any(axis=1) | summary['tof'].ge(0.1)\n# to_ignore = summary.index[mask].tolist()\n\n# # Clean train_df\n# train_df = train_df[~train_df['sequence_id'].isin(to_ignore)]\n# train_df[imu_thm_cols+tof_cols] = train_df[imu_thm_cols+tof_cols].interpolate().ffill().bfill()","metadata":{"id":"dUWIgmETj071","trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:38.248059Z","iopub.execute_input":"2025-08-09T13:51:38.248429Z","iopub.status.idle":"2025-08-09T13:51:38.263632Z","shell.execute_reply.started":"2025-08-09T13:51:38.248401Z","shell.execute_reply":"2025-08-09T13:51:38.262987Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Utility functions\n\ndef mixup_data(x, y, alpha=0.2):\n    if alpha > 0:\n        LAMBDA = np.random.beta(a=alpha, b=alpha)\n    else:\n        LAMBDA = tf.constant(1.0, dtype=tf.float32) # Use tf.constant for consistency\n\n    batch_size = tf.shape(x)[0]\n    # Use tf.random.shuffle for shuffling within TensorFlow graph\n    indices = tf.random.shuffle(tf.range(batch_size))\n\n    mixed_x = LAMBDA * x + (1 - LAMBDA) * tf.gather(x, indices)\n    mixed_y = LAMBDA * y + (1 - LAMBDA) * tf.gather(y, indices)\n    return mixed_x, mixed_y\n\ndef plot_interactive_history(history):\n    epochs = list(range(1, len(history['train_loss']) + 1))\n    fig = make_subplots(\n        rows=4, cols=1,\n        shared_xaxes=True,\n        vertical_spacing=0.02,  # minimal gap between rows :contentReference[oaicite:1]{index=1}\n        subplot_titles=[\"Learning Rate\", \"Loss\", \"F1 Score\", \"Accuracy\"]\n    )\n    # Loss\n    fig.add_trace(go.Scatter(x=epochs, y=history['train_loss'], name='Train Loss', line=dict(color='#098C18')), row=2, col=1)\n    fig.add_trace(go.Scatter(x=epochs, y=history['val_loss'], name='Val Loss', line=dict(color='#33B84E', dash='dash')), row=2, col=1)\n\n    # Accuracy\n    # fig.add_trace(go.Scatter(x=epochs, y=history['train_acc'], name='Train Acc', line=dict(color='#A34833')), row=4, col=1)\n    # fig.add_trace(go.Scatter(x=epochs, y=history['val_acc'], name='Val Acc', line=dict(color='#CF796C', dash='dash')), row=4, col=1)\n\n    # F1 Score\n    fig.add_trace(go.Scatter(x=epochs, y=history['train_f1'], name='Train F1', line=dict(color='#3AA69F')), row=3, col=1)\n    fig.add_trace(go.Scatter(x=epochs, y=history['val_f1'], name='Val F1', line=dict(color='#64D9D4', dash='dash')), row=3, col=1)\n\n    # Learning Rate\n    fig.add_trace(go.Scatter(x=epochs, y=history['learning_rate'], name='Learning Rate', line=dict(color='#A9B033')), row=1, col=1)\n\n    fig.update_layout(\n        height=1200, width=800,\n        margin=dict(t=50, b=50, l=50, r=50),  # smaller margins :contentReference[oaicite:2]{index=2}\n        showlegend=False\n    )    \n    fig.update_xaxes(title_text=\"Epoch\", row=4, col=1)\n    fig.update_yaxes(title_text=\"Lr\", row=1, col=1)\n    fig.update_yaxes(title_text=\"Loss\", row=2, col=1)\n    fig.update_yaxes(title_text=\"F1\", row=3, col=1)\n    fig.update_yaxes(title_text=\"Accuracy\", row=4, col=1)\n    \n    fig.show()\n\ndef unify_len(seq_df: pd.DataFrame, unified_len: int, padding_strategy: str = \"post\", padding_value = 0.0) -> pd.DataFrame:\n    \"\"\"\n    Processes a single sequence in a DataFrame to a unified length by truncating or padding.\n    Returns A new DataFrame with the sequence processed to the unified length.\n    \"\"\"\n    if padding_strategy not in [\"pre\", \"post\"]:\n        raise ValueError(\"padding_strategy must be either 'pre' or 'post'\")\n\n    n_rows = len(seq_df)\n    processed_df = seq_df # Default to no change\n\n    if n_rows > unified_len:\n        # Truncation: Keep the last `unified_len` rows\n        processed_df = seq_df.tail(unified_len)\n        \n    elif n_rows < unified_len:\n        # Padding: Add rows of NaNs to meet the unified_len\n        pad_size = unified_len - n_rows\n        \n        # Create a padding DataFrame with NaN values\n        pad_df = pd.DataFrame(padding_value, index=range(pad_size), columns=seq_df.columns)\n\n        if padding_strategy == \"pre\":\n            # Add padding before the sequence data\n            processed_df = pd.concat([pad_df, seq_df], ignore_index=True)\n        else:  # \"post\"\n            # Add padding after the sequence data\n            processed_df = pd.concat([seq_df, pad_df], ignore_index=True)\n            \n    return processed_df.reset_index(drop=True)\n\n# macro F1Score for multiclass classification\nclass F1ScoreMacro(metrics.Metric):\n    \"\"\"\n    Computes the macro F1 score from a confusion matrix.\n    \"\"\"\n    def __init__(self, num_classes, name='f1_score_macro', **kwargs):\n        super().__init__(name=name, **kwargs)\n        self.num_classes = num_classes\n        # State variable for the confusion matrix\n        self.confusion_matrix = self.add_weight(\n            name='cm',\n            shape=(num_classes, num_classes),\n            initializer='zeros',\n            dtype=tf.int32\n        )\n\n    def update_state(self, y_true, y_pred, sample_weight=None):\n        # Convert predictions and labels to indices\n        y_true_labels = tf.argmax(y_true, axis=-1)\n        y_pred_labels = tf.argmax(y_pred, axis=-1)\n\n        # Update the confusion matrix for the current batch\n        batch_cm = tf.math.confusion_matrix(\n            y_true_labels, y_pred_labels, num_classes=self.num_classes, dtype=tf.int32\n        )\n        self.confusion_matrix.assign_add(batch_cm)\n\n    def result(self):\n        cm = self.confusion_matrix\n        # Calculate True Positives, False Positives, False Negatives for each class\n        tp = tf.cast(tf.linalg.tensor_diag_part(cm), dtype=tf.float32)\n        fp = tf.cast(tf.reduce_sum(cm, axis=0), dtype=tf.float32) - tp\n        fn = tf.cast(tf.reduce_sum(cm, axis=1), dtype=tf.float32) - tp\n\n\n        # Calculate precision and recall for each class\n        precision = tp / (tp + fp + tf.keras.backend.epsilon())\n        recall = tp / (tp + fn + tf.keras.backend.epsilon())\n\n        # Calculate F1 score for each class\n        f1 = 2 * (precision * recall) / (precision + recall + tf.keras.backend.epsilon())\n\n        # Handle cases where a class has no examples by masking out NaN values.\n        f1 = tf.where(tf.math.is_nan(f1), tf.zeros_like(f1), f1)\n\n        # Compute the macro average\n        macro_f1 = tf.reduce_mean(f1)\n        return macro_f1\n\n    def reset_state(self):\n        # Reset the confusion matrix to zeros\n        for v in self.variables:\n            v.assign(tf.zeros(shape=v.shape, dtype=v.dtype))\n\n\nclass AttentionResampler(layers.Layer):\n    def __init__(self, pad_len, out_dim, key_dim=64, **kw):\n        super().__init__(**kw)\n        self.pad_len = pad_len\n        self.key_dim = key_dim\n        self.query = self.add_weight(\"queries\", shape=(pad_len, key_dim),\n                                     initializer=initializers.TruncatedNormal(stddev=0.02))\n        self.to_k = layers.Dense(key_dim, use_bias=False)\n        self.to_v = layers.Dense(out_dim, use_bias=False)\n\n    def call(self, x, mask=None):\n        # x: [B, T, C]\n        K = self.to_k(x)          # [B, T, key_dim]\n        V = self.to_v(x)          # [B, T, out_dim]\n        Q = tf.expand_dims(self.query, axis=0)  # [1, pad_len, key_dim]\n        Q = tf.tile(Q, [tf.shape(x)[0], 1, 1])  # [B, pad_len, key_dim]\n\n        # Scaled dot-product attention\n        attn_logits = tf.matmul(Q, K, transpose_b=True) / tf.math.sqrt(tf.cast(self.key_dim, tf.float32))\n        if mask is not None:\n            # mask: [B, T] with 1 = valid. Convert to addable mask\n            mask = tf.cast(mask, tf.float32)\n            mask = tf.expand_dims(mask, axis=1)   # [B, 1, T]\n            attn_logits += (1.0 - mask) * -1e9\n\n        attn = tf.nn.softmax(attn_logits, axis=-1)  # [B, pad_len, T]\n        out = tf.matmul(attn, V)                    # [B, pad_len, out_dim]\n        return out","metadata":{"id":"8MNE2zd2hdQr","trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:38.264433Z","iopub.execute_input":"2025-08-09T13:51:38.264681Z","iopub.status.idle":"2025-08-09T13:51:38.291140Z","shell.execute_reply.started":"2025-08-09T13:51:38.264651Z","shell.execute_reply":"2025-08-09T13:51:38.290501Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Prepare labels\n# print(\"Label encoding ...\")\n# label_encoder = LabelEncoder()\n# train_df['gesture'] = label_encoder.fit_transform(train_df['gesture'].astype(str))\n\n# gesture_classes = label_encoder.classes_\n# num_classes = len(gesture_classes)\n# np.save('./gesture_classes.npy', gesture_classes)\n\n# # Get relevan features\n# imu_cols = [c for c in train_df.columns if (c.startswith('acc_') or c.startswith('rot_'))]\n# tof_thm_cols = [c for c in train_df.columns if (c.startswith('thm_') or c.startswith('tof_'))]\n# feature_cols = imu_cols + tof_thm_cols\n\n# np.save(\"./feature_cols.npy\", feature_cols)\n# num_features = len(feature_cols)\n# print(f\"Got {num_features} features.\")\n\n\n# # Prepare Global Scaler\n# print(\"Fitting StandardScaler...\")\n# values_for_scaling = train_df[feature_cols].astype('float32').interpolate().ffill().bfill().fillna(0).values\n# scaler = StandardScaler().fit(values_for_scaling)\n# joblib.dump(scaler, './global_scaler.pkl')\n\n# del values_for_scaling\n# gc.collect()\n\n\n# # Sequence-wise Processing\n# print(\"Sequences-wise Processing Started...\")\n# print(\"Flow: [Sort -> Scale -> Pad]\")\n\n# # get seuqnces\n# sequences_grouped = train_df.groupby('sequence_id')\n# n_samples = len(sequences_grouped)\n# print(f\"Found {n_samples} sequences.\")\n\n# # del train_df\n# gc.collect()\n\n# # Get Pad length\n# # pad_len = int(sequences_grouped.size().max())\n# pad_len = 200\n# np.save(\"./sequence_maxlen.npy\", pad_len)\n\n# # Prepare X and y\n# X = np.zeros((n_samples, pad_len, num_features), dtype='float32')\n# y = np.zeros(n_samples, dtype='int32')\n\n# for i, (_, seq_df) in tqdm(enumerate(sequences_grouped), total=n_samples, desc=\"💠Progress\"):\n\n#     # 1. Sorting\n#     _sequence = seq_df.sort_values(by=\"sequence_counter\")[feature_cols].astype('float32')\n\n#     # unify length\n#     _sequence = unify_len(_sequence, unified_len= pad_len)\n    \n#     # clean\n#     _sequence = _sequence.interpolate().ffill().bfill().fillna(0)\n    \n#     # 3. Scaling\n#     _sequence = scaler.transform(_sequence.values)\n\n#     # 4. Padding\n#     _sequence = pad_sequences(\n#         [_sequence],\n#         maxlen=pad_len,\n#         dtype='float32',\n#         padding='post',\n#         truncating='post'\n#     )[0]\n\n#     # Resutls\n#     X[i] = _sequence\n#     y[i] = seq_df['gesture'].iloc[0]\n\n# # Cleanup\n# del sequences_grouped\n# gc.collect()","metadata":{"trusted":true,"id":"wGwLAbCxCQjY","outputId":"a77fae90-307f-485f-c57d-707e79baf779","execution":{"iopub.status.busy":"2025-08-09T13:51:38.291940Z","iopub.execute_input":"2025-08-09T13:51:38.292200Z","iopub.status.idle":"2025-08-09T13:51:38.314150Z","shell.execute_reply.started":"2025-08-09T13:51:38.292174Z","shell.execute_reply":"2025-08-09T13:51:38.313375Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Data splitting","metadata":{"id":"DYVPcYB_9M2w"}},{"cell_type":"code","source":"# # Split the entire dataset into 90% dev and 10% test\n# print(\"Splitting data into 90% dev and 10% test...\")\n# X_dev, X_test, y_dev, y_test = train_test_split(X, y, test_size=0.1, stratify=y)\n# print(f\"Dev set shape: {X_dev.shape}, Test set shape: {X_test.shape}\")\n\n# del X, y\n# gc.collect()\n\n\n# # Split the dev set into 90% train and 10% validation\n# print(\"Splitting dev set into 90% train and 10% validation...\")\n# X_train, X_val, y_train, y_val = train_test_split(X_dev, y_dev, test_size=0.1, stratify=y_dev)\n# total_train_samples = X_train.shape[0]\n# print(f\"Train set shape: {X_train.shape}, Validation set shape: {X_val.shape}\")\n\n# del X_dev, y_dev\n# gc.collect()\n\n\n# # Create tf.data.Dataset pipelines for train, validation, and test sets\n# print(\"Creating tf.data.Dataset for train, validation, and test sets...\")\n# AUTOTUNE = tf.data.AUTOTUNE\n# BATCH_SIZE = 64\n\n# # Train Dataset\n# train_dataset = tf.data.Dataset.from_tensor_slices((X_train, y_train))\n# train_dataset = (\n#     train_dataset\n#     .shuffle(buffer_size=len(y_train))\n#     .map(lambda features, label: (features, tf.one_hot(label, depth=num_classes)), num_parallel_calls=AUTOTUNE)\n#     .batch(BATCH_SIZE, drop_remainder=True)\n#     .prefetch(AUTOTUNE)\n# )\n# print(\"✔️Train Dataset Ready.\")\n# del X_train, y_train\n# gc.collect()\n\n\n# # Validation Dataset\n# val_dataset = tf.data.Dataset.from_tensor_slices((X_val, y_val))\n# val_dataset = (\n#     val_dataset\n#     .map(lambda features, label: (features, tf.one_hot(label, depth=num_classes)), num_parallel_calls=AUTOTUNE)\n#     .batch(BATCH_SIZE)\n#     .prefetch(AUTOTUNE)\n# )\n# print(\"✔️Validation Dataset Ready.\")\n# del X_val, y_val\n# gc.collect()\n\n\n# # Test Dataset\n# test_dataset = tf.data.Dataset.from_tensor_slices((X_test, y_test))\n# test_dataset = (\n#     test_dataset\n#     .map(lambda features, label: (features, tf.one_hot(label, depth=num_classes)), num_parallel_calls=AUTOTUNE)\n#     .batch(BATCH_SIZE)\n#     .prefetch(AUTOTUNE)\n# )\n# print(\"✔️Test Dataset Ready.\")\n# del X_test, y_test\n# gc.collect()","metadata":{"trusted":true,"id":"FRZ8mBJJ9M2x","outputId":"5346e4e4-baac-41da-e413-81d8c1f713c8","execution":{"iopub.status.busy":"2025-08-09T13:51:38.315275Z","iopub.execute_input":"2025-08-09T13:51:38.315860Z","iopub.status.idle":"2025-08-09T13:51:38.333502Z","shell.execute_reply.started":"2025-08-09T13:51:38.315840Z","shell.execute_reply":"2025-08-09T13:51:38.332856Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3. Model","metadata":{"id":"6tbMb19q-EVN"}},{"cell_type":"markdown","source":"### Build","metadata":{"id":"5Nf5waoZ-TCI"}},{"cell_type":"code","source":"# 4. Model definition \n# Two-branche: IMU: SE-CNN + TOF/Thm: CNN -> BiLSTM -> Attention -> Densely Head\nprint(\"Model definition...\")\n\nclass SEBlock(layers.Layer):\n    def __init__(self, channels, reduction=8, **kwargs):\n        super(SEBlock, self).__init__(**kwargs)\n        self.channels = channels\n        self.reduction = reduction\n        self.fc1 = layers.Dense(channels // reduction, activation='relu')\n        self.fc2 = layers.Dense(channels, activation='sigmoid')\n\n    def call(self, x):                  # x: (batch, seq_len, channels)\n        se = tf.reduce_mean(x, axis=1)  # (batch, channels)\n        se = self.fc1(se)               # (batch, channels//reduction)\n        se = self.fc2(se)               # (batch, channels)\n        se = tf.expand_dims(se, axis=1) # (batch, 1, channels)\n        return x * se                   # scale channels: (batch, seq_len, channels) * (batch, 1, channels)\n\nclass ResidualSEBlock(layers.Layer):\n    def __init__(self, out_channels, kernel_size=3, pool_size=2, dropout_rate=0.3, reg=regularizers.l2(5e-4), **kwargs):\n        super(ResidualSEBlock, self).__init__(**kwargs)\n        self.conv1 = layers.Conv1D(out_channels, kernel_size, padding='same', use_bias=False, kernel_regularizer=reg)\n        self.bn1 = layers.BatchNormalization()\n        self.relu = layers.ReLU()\n        self.conv2 = layers.Conv1D(out_channels, kernel_size, padding='same', use_bias=False, kernel_regularizer=reg)\n        self.bn2 = layers.BatchNormalization() \n        self.se = SEBlock(out_channels, reduction=8)\n        self.pool = layers.MaxPooling1D(pool_size=pool_size)\n        self.dropout = layers.Dropout(dropout_rate)\n        self.shortcut_conv = None\n        self.shortcut_bn = None\n\n    def build(self, input_shape):\n        in_channels = input_shape[-1]\n        out_channels = self.conv1.filters\n        if in_channels != out_channels:\n            self.shortcut_conv = layers.Conv1D(out_channels, kernel_size=1, use_bias=False)\n            self.shortcut_bn = layers.BatchNormalization()\n\n    def call(self, x, training=False):\n\n        # prepare shortcut (for skip connection)\n        if self.shortcut_conv:\n            shortcut = self.shortcut_conv(x)\n            shortcut = self.shortcut_bn(shortcut, training=training)\n        else:\n            shortcut = x\n\n        out = self.conv1(x)\n        out = self.bn1(out, training=training)\n        out = self.relu(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out, training=training)\n        # out = self.relu(out)\n\n        # Squeeze-and-Excitation\n        out = self.se(out)\n\n        # Skip connection\n        out = layers.add([out, shortcut])\n\n        # Head\n        out = self.relu(out)\n        out = self.pool(out)\n        out = self.dropout(out, training=training)\n\n        return out\n\nclass Attention(layers.Layer):\n    def __init__(self, **kwargs):\n        super(Attention, self).__init__(**kwargs)\n        self.score_fc = layers.Dense(1, activation='tanh')\n\n    def call(self, x):                              # x: (batch, seq_len, features)\n        scores = self.score_fc(x)                   # (batch, seq_len, 1)\n        weights = layers.Softmax(axis=1)(scores)    # (batch, seq_len, 1)\n        context = x * weights                       # (batch, seq_len, features)\n        context = tf.reduce_sum(context, axis=1)    # (batch, features)\n        return context\n\ndef TwoBranchModel(\n    total_features, imu_dim, tof_thm_dim, \n    pad_len, num_classes, reg=regularizers.l2(5e-4)):\n    \n    # Input shape: (batch, seq_len, features)\n    input_layer = layers.Input(shape=(pad_len, total_features))\n\n    # Mask zero padding (experimental)\n    # mask = layers.Masking(mask_value=0.0)(input_layer)\n\n    # Split inputs\n    x_imu = input_layer[:, :, :imu_dim]\n    x_ttf = input_layer[:, :, imu_dim:]\n\n    # IMU branch\n    # b1 = ResidualSEBlock(64, kernel_size=3, pool_size=2, dropout_rate=0.3)(x_imu)\n    b1 = ResidualSEBlock(64, kernel_size=5, pool_size=4, dropout_rate=0.3, reg=reg)(x_imu)\n\n    # TOF/Thermal branch\n    b2 = layers.Conv1D(32, kernel_size=3, padding='same', use_bias=False, kernel_regularizer=reg)(x_ttf)\n    b2 = layers.BatchNormalization()(b2)\n    b2 = layers.ReLU()(b2)\n    b2 = layers.MaxPooling1D(pool_size=2)(b2)\n    b2 = layers.Dropout(0.3)(b2)\n\n    b2 = layers.Conv1D(64, kernel_size=3, padding='same', use_bias=False, kernel_regularizer=reg)(b2)\n    b2 = layers.BatchNormalization()(b2)\n    b2 = layers.ReLU()(b2)\n    b2 = layers.MaxPooling1D(pool_size=2)(b2)\n    b2 = layers.Dropout(0.3)(b2)\n\n    # Concatenate branches along channel dimension\n    merged = layers.Concatenate(axis=-1)([b1, b2])\n\n    # BiLSTM\n    lstm_out = layers.Bidirectional(layers.LSTM(64, return_sequences=True))(merged)\n    lstm_out = layers.Dropout(0.4)(lstm_out)\n\n    # Attention\n    context = Attention()(lstm_out)\n\n    # Dense head\n    x = layers.Dense(128, use_bias=False, kernel_regularizer=reg)(context)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n    x = layers.Dropout(0.3)(x)\n\n    x = layers.Dense(64, use_bias=False, kernel_regularizer=reg)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)  \n    x = layers.Dropout(0.3)(x)\n\n    # Output layer\n    out = layers.Dense(num_classes)(x) # Logits output\n\n    return Model(inputs=input_layer, outputs=out)","metadata":{"trusted":true,"id":"jxlXv6OUCQja","outputId":"d7691056-1b33-49ee-e7bd-276b040e6ea4","execution":{"iopub.status.busy":"2025-08-09T13:51:38.336136Z","iopub.execute_input":"2025-08-09T13:51:38.336420Z","iopub.status.idle":"2025-08-09T13:51:38.358112Z","shell.execute_reply.started":"2025-08-09T13:51:38.336394Z","shell.execute_reply":"2025-08-09T13:51:38.357401Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training","metadata":{"id":"Y6mlBVsM-Wga"}},{"cell_type":"code","source":"# # 5. Training setup (optimizer, loss, scheduler)\n\n\n# # total_steps = num_epochs * np.ceil(total_train_samples / BATCH_SIZE).astype('int16')\n# # decay_rate = (lr / 100) ** (1 / total_steps)\n# # lr_scheduler = optimizers.schedules.ExponentialDecay(\n# #     initial_learning_rate=lr,\n# #     decay_steps=1,         # apply decay every step\n# #     decay_rate=decay_rate, # tiny per-step multiplicative factor\n# #     staircase=False        # continuous (set True for discrete jumps)\n# # )\n\n# # steps_per_epoch = np.ceil(total_train_samples / BATCH_SIZE).astype('int16')\n# # lr_scheduler = FactorDecay(\n# #     initial_lr=lr, \n# #     steps_per_epoch=steps_per_epoch,\n# #     decay_every_epochs=15, \n# #     decay_factor=2.0)\n\n# # Main Training hyperparamet/erslr = 1e-3\n\n# lr = 2e-3\n# num_epochs = 160\n# patience = 30\n\n# # CosineAnnealingWarmRestarts equivalent\n# first_decay_steps = 5 * np.ceil(total_train_samples / BATCH_SIZE)\n# lr_scheduler = optimizers.schedules.CosineDecayRestarts(\n#     initial_learning_rate=lr,\n#     first_decay_steps=first_decay_steps,  # First Decay after x Epochs\n#     t_mul=1.5,                            # After restart multiply period len by t_mul\n#     m_mul=0.9,                           # After restart multiply current lr by m_mul\n#     alpha=1e-5 / lr                       # Minimum value lr will reach (eta_min)\n# )\n# optimizer = optimizers.AdamW(learning_rate=lr_scheduler)\n# # optimizer = optimizers.Adam(learning_rate=lr_scheduler, weight_decay=5e-4)\n\n# # Loss: CategoricalCrossentropy with from_logits=True handles soft labels and log_softmax\n# loss_fn = losses.CategoricalCrossentropy(from_logits=True)\n\n# # Metrics\n# train_loss_metric = metrics.Mean(name='train_loss')\n# val_loss_metric = metrics.Mean(name='val_loss')\n# train_accuracy_metric = metrics.CategoricalAccuracy(name='train_accuracy')\n# val_accuracy_metric = metrics.CategoricalAccuracy(name='val_accuracy')\n# train_f1_metric = F1ScoreMacro(num_classes=18, name='train_f1')\n# val_f1_metric = F1ScoreMacro(num_classes=18, name='val_f1')","metadata":{"trusted":true,"id":"jcgQt68TCQjb","execution":{"iopub.status.busy":"2025-08-09T13:51:38.358881Z","iopub.execute_input":"2025-08-09T13:51:38.359200Z","iopub.status.idle":"2025-08-09T13:51:38.379758Z","shell.execute_reply.started":"2025-08-09T13:51:38.359169Z","shell.execute_reply":"2025-08-09T13:51:38.378960Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Instantiate model\n# model = TwoBranchModel(\n#     total_features=len(feature_cols),\n#     imu_dim=len(imu_cols),\n#     tof_thm_dim=len(tof_thm_cols),\n#     pad_len=pad_len,\n#     num_classes=18,\n#     reg=regularizers.l2(5e-4)\n# )\n\n# # Reset monitoring indices\n# best_val_loss = np.inf\n# best_f1 = -np.inf\n# epochs_no_improve = 0\n# best_weights = None\n# history = {\n#     'train_loss': [],\n#     'train_f1': [],\n#     'val_loss': [],\n#     'val_f1': [],\n#     'learning_rate': []\n#     # 'train_acc': [],\n#     # 'val_acc': [],\n# }","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:38.380596Z","iopub.execute_input":"2025-08-09T13:51:38.380889Z","iopub.status.idle":"2025-08-09T13:51:38.400054Z","shell.execute_reply.started":"2025-08-09T13:51:38.380864Z","shell.execute_reply":"2025-08-09T13:51:38.399301Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # 6. Training with Mixup\n# @tf.function\n# def train_step(x, y):\n#     with tf.GradientTape() as tape:\n#         predictions = model(x, training=True)\n#         loss = loss_fn(y, predictions)\n\n#     gradients = tape.gradient(loss, model.trainable_variables)\n#     optimizer.apply_gradients(zip(gradients, model.trainable_variables))\n\n#     train_loss_metric.update_state(loss)\n#     train_f1_metric.update_state(y, predictions)\n#     # train_accuracy_metric.update_state(y, predictions)\n\n# @tf.function\n# def val_step(x, y):\n#     predictions = model(x, training=False)\n#     loss = loss_fn(y, predictions)\n\n#     val_loss_metric.update_state(loss)\n#     val_f1_metric.update_state(y, predictions)\n#     # val_accuracy_metric.update_state(y, predictions)\n\n\n# print(\"Train is Starting...\")\n# # For each epoch\n# for epoch in range(1, num_epochs + 1):\n#     # Reset metrics at the start of each epoch\n#     train_loss_metric.reset_state()\n#     train_f1_metric.reset_state()\n#     val_loss_metric.reset_state()\n#     val_f1_metric.reset_state()\n#     # train_accuracy_metric.reset_state()\n#     # val_accuracy_metric.reset_state()\n\n#     # Training loop\n#     for batch_x, batch_y in tqdm(train_dataset, desc=f\"💠Epoch {epoch}/{num_epochs}\"):\n#         mixed_x, mixed_y = mixup_data(batch_x, batch_y, alpha=0.4)\n#         train_step(mixed_x, mixed_y)\n\n#     # Validation loop\n#     for batch_x_val, batch_y_val in val_dataset:\n#         val_step(batch_x_val, batch_y_val)\n\n#     # Metrics monitoring\n#     train_loss = train_loss_metric.result()\n#     train_f1 = train_f1_metric.result()\n#     val_loss = val_loss_metric.result()\n#     val_f1 = val_f1_metric.result()\n#     current_lr = optimizer.learning_rate\n#     # train_acc = train_accuracy_metric.result()\n#     # val_acc = val_accuracy_metric.result()\n    \n#     # Save metrics\n#     history['train_loss'].append(train_loss.numpy())\n#     history['train_f1'].append(train_f1.numpy())\n#     history['val_loss'].append(val_loss.numpy())\n#     history['val_f1'].append(val_f1.numpy())\n#     history['learning_rate'].append(current_lr.numpy())\n#     # history['train_acc'].append(train_acc.numpy())\n#     # history['val_acc'].append(val_acc.numpy())\n    \n#     print(\n#         f\"  Tr Loss = {train_loss:.3f}, Val Loss = {val_loss:.3f}, \",\n#         f\"Tr F1 = {train_f1:.3f},  Val F1 = {val_f1:.3f}, Lr = {current_lr.numpy():.5f}\",\n#     )\n\n#     # Early‑stopping check\n#     if val_loss < best_val_loss:\n#         best_val_loss = val_loss\n#         epochs_no_improve = 0\n#         print(f\"  ↗️ New best val loss: {best_val_loss:.4f}\")\n#         model.save_weights(f\"best_model.weights.h5\") # Save best model weights\n#         if val_f1 > best_f1:\n#             best_f1 = val_f1\n#             model.save_weights(f\"best_model_f1.weights.h5\") # Save best model weights\n#     else:\n#         epochs_no_improve += 1\n#         if epochs_no_improve >= patience:\n#             print(f\"⚠️ Early stopping at epoch {epoch}.\")\n#             model.load_weights(f\"best_model.weights.h5\") # Restore best model weights\n#             break","metadata":{"id":"9nddSvDGMT-8","outputId":"70e4e7bc-58ba-4398-f727-d46a1b1684b2","trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:38.400889Z","iopub.execute_input":"2025-08-09T13:51:38.401110Z","iopub.status.idle":"2025-08-09T13:51:38.421225Z","shell.execute_reply.started":"2025-08-09T13:51:38.401092Z","shell.execute_reply":"2025-08-09T13:51:38.420509Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Evaluation","metadata":{"id":"OE36bBog-YIA"}},{"cell_type":"code","source":"# plot_interactive_history(history)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:38.422179Z","iopub.execute_input":"2025-08-09T13:51:38.422467Z","iopub.status.idle":"2025-08-09T13:51:38.439857Z","shell.execute_reply.started":"2025-08-09T13:51:38.422440Z","shell.execute_reply":"2025-08-09T13:51:38.438816Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Evaluate the model on the test set\n\n# # Initialize metrics for testing\n# test_loss_metric = tf.keras.metrics.Mean(name='test_loss')\n# # test_accuracy_metric = tf.keras.metrics.CategoricalAccuracy(name='test_accuracy')\n# test_f1_metric = F1ScoreMacro(name='test_f1_score', num_classes=18) # Using the custom F1Score metric\n\n# # Reset metrics before evaluation\n# test_loss_metric.reset_state()\n# # test_accuracy_metric.reset_state()\n# test_f1_metric.reset_state()\n\n# # Evaluate the model on the test dataset\n# print(\"Evaluating model on the test dataset...\")\n# y_true = []\n# y_pred = []\n\n# for batch_x_test, batch_y_test in tqdm(test_dataset, desc=\"Testing\"):\n#     predictions = inference_model(batch_x_test, training=False)\n#     loss = loss_fn(batch_y_test, predictions)\n\n#     test_loss_metric.update_state(loss)\n#     # test_accuracy_metric.update_state(batch_y_test, predictions)\n#     test_f1_metric.update_state(batch_y_test, predictions)\n\n#     # Collect true and predicted labels for classification report\n#     y_true.extend(tf.argmax(batch_y_test, axis=-1).numpy())\n#     y_pred.extend(tf.argmax(predictions, axis=-1).numpy())\n\n\n# test_loss = test_loss_metric.result()\n# # test_acc = test_accuracy_metric.result()\n# test_f1 = test_f1_metric.result()\n\n# print(f\"Test Results: Loss = {test_loss:.4f}, F1 Score = {test_f1:.4f}\")\n\n# # Generate and print classification report\n# print(\"\\nClassification Report:\")\n# print(classification_report(y_true, y_pred, target_names=gesture_classes))","metadata":{"id":"2YX6galh-baH","trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:51:38.440829Z","iopub.execute_input":"2025-08-09T13:51:38.441059Z","iopub.status.idle":"2025-08-09T13:51:38.455500Z","shell.execute_reply.started":"2025-08-09T13:51:38.441032Z","shell.execute_reply":"2025-08-09T13:51:38.454646Z"},"outputId":"134c8444-74c0-4f91-a388-563c31dae259"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 4. Prediction","metadata":{"id":"8j0_3Y-y-JKM"}},{"cell_type":"code","source":"# 7. Inference function for Kaggle evaluation\n\nimport kaggle_evaluation.cmi_inference_server\nimport polars as pl\n\n# Load artifacts\nprint(\"load model artifacts...\")\ngesture_classes = np.load(\"/kaggle/input/artifacts/gesture_classes.npy\", allow_pickle=True)\npad_len = 200\n# pad_len = int(np.load(\"/kaggle/input/artifacts/sequence_maxlen.npy\", allow_pickle=True))\nscaler = joblib.load(\"/kaggle/input/artifacts/global_scaler.pkl\")\nfeature_cols = np.load(\"/kaggle/input/artifacts/feature_cols.npy\", allow_pickle=True)\n# Recreate model and load weights\nprint(\"Creating model and loading weights...\")\ninference_model = TwoBranchModel(\n    total_features=332,\n    imu_dim=7,\n    tof_thm_dim=325,\n    pad_len=pad_len,\n    num_classes=len(gesture_classes),\n    reg=regularizers.l2(5e-4)\n)\n# Build the model by calling it on a dummy input\ndummy_input = np.zeros((1, pad_len, 332), dtype=np.float32)\n_ = inference_model(dummy_input)\ninference_model.load_weights(\"/kaggle/input/artifacts/best_model.weights.h5\")\n\n\ndef preprocess_sequence(df_seq: pd.DataFrame):\n    data = df_seq[feature_cols].interpolate().ffill().bfill().fillna(0).values\n    scaled = scaler.transform(data)  # (seq_len_actual, total_features)\n    # Pad/truncate\n    padded = pad_sequences(\n        [scaled],\n        maxlen=pad_len,\n        dtype='float32',\n        padding='post',\n        truncating='post'\n    )  # (1, pad_len, total_features)\n    return tf.convert_to_tensor(padded, dtype=tf.float32)\n\ndef predict(sequence, demographics) -> str:\n    \"\"\"\n    Kaggle evaluation API will call this for each sequence.\n    sequence: polars DataFrame for a single sequence\n    Returns: predicted gesture string\n    \"\"\"\n    df_seq = sequence.to_pandas()\n    x_tensor = preprocess_sequence(df_seq) # (1, pad_len, features)\n\n    outputs = inference_model(x_tensor, training=False) # (1, num_classes)\n    pred_idx = tf.argmax(outputs, axis=1).numpy()[0]\n\n    return str(gesture_classes[pred_idx])\n    return \"Drink from bottle/cup\"\n\n\ninference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n    inference_server.serve()\nelse:\n    print(\"local gateway running...\")\n    inference_server.run_local_gateway(\n        data_paths=(\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv',\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv',\n        )\n    )\n    print(\"Done.\")","metadata":{"id":"H9bYynFb-K53","execution":{"iopub.status.busy":"2025-08-09T13:52:22.825536Z","iopub.execute_input":"2025-08-09T13:52:22.825828Z","iopub.status.idle":"2025-08-09T13:52:24.458183Z","shell.execute_reply.started":"2025-08-09T13:52:22.825809Z","shell.execute_reply":"2025-08-09T13:52:24.457402Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# if not os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n#     print(pd.read_parquet(\"submission.parquet\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-09T13:52:28.626605Z","iopub.execute_input":"2025-08-09T13:52:28.627022Z","iopub.status.idle":"2025-08-09T13:52:28.785381Z","shell.execute_reply.started":"2025-08-09T13:52:28.626987Z","shell.execute_reply":"2025-08-09T13:52:28.784559Z"},"id":"tu9e3ZkYRYA-"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}