[2ff6cc]: / notebooks / model_deployment.ipynb

Download this file

1 lines (1 with data), 22.4 kB

{"cells":[{"cell_type":"code","source":["import mlflow\n","import mlflow.sklearn\n","from sklearn.ensemble import RandomForestClassifier\n","from sklearn.model_selection import train_test_split\n","from sklearn.preprocessing import LabelEncoder, StandardScaler\n","from sklearn.impute import SimpleImputer\n","from sklearn.pipeline import make_pipeline\n","import pandas as pd\n","import numpy as np\n","from notebookutils import mssparkutils\n","\n","def train_and_deploy_model():\n","    \"\"\"\n","    Train and deploy a model with comprehensive NaN handling in Microsoft Fabric\n","    \"\"\"\n","    try:\n","        # 1. Load data from Lakehouse with validation\n","        print(\"๐Ÿ” Loading data from Lakehouse...\")\n","        df = pd.read_csv(\"/lakehouse/default/Files/PDC_biospecimen_manifest_03272025_214257.csv\")\n","        print(f\"โœ… Data loaded successfully. Shape: {df.shape}\")\n","        \n","        # 2. Data validation\n","        print(\"\\n๐Ÿ”Ž Validating data...\")\n","        feature_cols = [\n","            'Aliquot Quantity', \n","            'Aliquot Volume',\n","            'Concentration',\n","            'Days To Collection',\n","            'Days To Sample Procurement',\n","            'Current Weight',\n","            'Initial Weight'\n","        ]\n","        feature_cols = [col for col in feature_cols if col in df.columns]\n","        \n","        if not feature_cols:\n","            raise ValueError(\"โŒ No valid feature columns found\")\n","        \n","        target_col = 'Case Status'\n","        if target_col not in df.columns:\n","            raise ValueError(f\"โŒ Target column '{target_col}' not found\")\n","        \n","        # 3. NaN handling and preprocessing\n","        print(\"\\n๐Ÿงน Handling missing values...\")\n","        \n","        # Show missing values before imputation\n","        print(\"\\nMissing values per feature column:\")\n","        print(df[feature_cols].isnull().sum())\n","        \n","        # Encode target (no NaN handling needed as it's categorical)\n","        le = LabelEncoder()\n","        y = le.fit_transform(df[target_col].astype(str))\n","        \n","        # Create preprocessing pipeline\n","        preprocessor = make_pipeline(\n","            SimpleImputer(strategy='median'),  # Handles NaN values\n","            StandardScaler()                   # Scales features\n","        )\n","        \n","        # Apply preprocessing\n","        X = preprocessor.fit_transform(df[feature_cols])\n","        \n","        # Verify no NaN values remain\n","        if np.isnan(X).any():\n","            raise ValueError(\"โŒ NaN values still present after preprocessing\")\n","        \n","        # 4. Train model with MLflow tracking\n","        print(\"\\n๐Ÿค– Training model...\")\n","        with mlflow.start_run():\n","            # Create and train model\n","            model = RandomForestClassifier(\n","                n_estimators=100,\n","                random_state=42,\n","                n_jobs=-1,\n","                class_weight='balanced'\n","            )\n","            \n","            # Split data\n","            X_train, X_test, y_train, y_test = train_test_split(\n","                X, y, test_size=0.2, random_state=42)\n","            \n","            model.fit(X_train, y_train)\n","            \n","            # Log important information\n","            mlflow.log_param(\"n_estimators\", 100)\n","            mlflow.log_metric(\"train_accuracy\", model.score(X_train, y_train))\n","            mlflow.log_metric(\"test_accuracy\", model.score(X_test, y_test))\n","            \n","            # Log the preprocessing pipeline\n","            mlflow.sklearn.log_model(preprocessor, \"preprocessor\")\n","            \n","            # Log the trained model\n","            mlflow.sklearn.log_model(model, \"model\")\n","            \n","            # Save feature columns as artifact\n","            with open(\"feature_columns.txt\", \"w\") as f:\n","                f.write(\"\\n\".join(feature_cols))\n","            mlflow.log_artifact(\"feature_columns.txt\")\n","            \n","            # Register model\n","            mlflow.register_model(\n","                \"runs:/{}/model\".format(mlflow.active_run().info.run_id),\n","                \"BiospecimenClassifier\"\n","            )\n","            \n","            print(\"โœ… Model trained and registered successfully!\")\n","            \n","            # Return run ID for reference\n","            return mlflow.active_run().info.run_id\n","            \n","    except Exception as e:\n","        print(f\"\\nโŒ Error in model deployment: {str(e)}\")\n","        print(\"\\n๐Ÿ› ๏ธ Troubleshooting steps:\")\n","        print(\"1. Check for missing values in your data\")\n","        print(\"2. Verify all feature columns exist\")\n","        print(\"3. Ensure target column has valid values\")\n","        raise\n","\n","if __name__ == \"__main__\":\n","    train_and_deploy_model()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":15,"statement_ids":[15],"state":"finished","livy_statement_state":"available","session_id":"e50020a4-5e38-4ad5-9b81-a3040d5ab3df","normalized_state":"finished","queued_time":"2025-04-01T11:47:43.2194044Z","session_start_time":null,"execution_start_time":"2025-04-01T11:47:43.2208452Z","execution_finish_time":"2025-04-01T11:48:10.4631319Z","parent_msg_id":"a6da7c3f-34d4-45ab-9bd1-4b04cb4ec9c7"},"text/plain":"StatementMeta(, e50020a4-5e38-4ad5-9b81-a3040d5ab3df, 15, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["๐Ÿ” Loading data from Lakehouse...\nโœ… Data loaded successfully. Shape: (452, 45)\n\n๐Ÿ”Ž Validating data...\n\n๐Ÿงน Handling missing values...\n\nMissing values per feature column:\nAliquot Quantity              452\nAliquot Volume                452\nConcentration                 452\nDays To Collection            347\nDays To Sample Procurement    452\nCurrent Weight                452\nInitial Weight                347\ndtype: int64\n"]},{"output_type":"display_data","data":{"application/vnd.mlflow.run-widget+json":{"info":{"artifact_uri":"sds://onelakesouthafricanorth.pbidedicated.windows.net/cde60769-1208-4712-9d88-602cb5dae476/05fdd04f-1a5d-4785-be80-12ef22e29bba/10d2e4fc-48f9-4f8d-9bd6-7463ed30fdfb/artifacts","end_time":1743508072,"experiment_id":"1bf6b0a4-b874-47b8-a79f-292c615471ec","lifecycle_stage":"active","run_id":"10d2e4fc-48f9-4f8d-9bd6-7463ed30fdfb","run_name":"quiet_box_69mtdgp6","run_uuid":"10d2e4fc-48f9-4f8d-9bd6-7463ed30fdfb","start_time":1743508065,"status":"FINISHED","user_id":"561e81b0-4da1-42c1-b290-381c5782272c"},"data":{"metrics":{},"params":{"memory":"None","steps":"[('simpleimputer', SimpleImputer(strategy='median')), ('standardscaler', StandardScaler())]","verbose":"False","simpleimputer":"SimpleImputer(strategy='median')","standardscaler":"StandardScaler()","simpleimputer__add_indicator":"False","simpleimputer__copy":"True","simpleimputer__fill_value":"None","simpleimputer__keep_empty_features":"False","simpleimputer__missing_values":"nan","simpleimputer__strategy":"median","simpleimputer__verbose":"deprecated","standardscaler__copy":"True","standardscaler__with_mean":"True","standardscaler__with_std":"True"},"tags":{"mlflow.user":"dcaf7b03-32e1-45bc-b03b-2da2786f6cfd","synapseml.notebook.artifactId":"541c9fd0-f54a-44d9-bdb9-a8db2d979286","synapseml.user.name":"danny","synapseml.user.id":"7c38aabf-71be-44a2-8bd1-240d7015d15e","synapseml.livy.id":"e50020a4-5e38-4ad5-9b81-a3040d5ab3df","mlflow.autologging":"sklearn","estimator_name":"Pipeline","estimator_class":"sklearn.pipeline.Pipeline","mlflow.rootRunId":"10d2e4fc-48f9-4f8d-9bd6-7463ed30fdfb","mlflow.runName":"quiet_box_69mtdgp6","synapseml.experimentName":"model_deployment","synapseml.experiment.artifactId":"05fdd04f-1a5d-4785-be80-12ef22e29bba"}},"inputs":{"dataset_inputs":[]}}},"metadata":{}},{"output_type":"stream","name":"stdout","text":["\n๐Ÿค– Training model...\nโœ… Model trained and registered successfully!\n"]},{"output_type":"stream","name":"stderr","text":["2025/04/01 11:47:56 WARNING mlflow.sklearn: Model was missing function: predict. Not logging python_function flavor!\n2025-04-01:11:48:01,946 ERROR    [shared_platform_utils.py:82] Create MLModel failed, status_code: 400, b'{\"requestId\":\"6f84f5ef-22d8-443f-b2b2-f98075bc112b\",\"errorCode\":\"ItemDisplayNameAlreadyInUse\",\"message\":\"Requested \\'BiospecimenClassifier\\' is already in use\"}'\nRegistered model 'BiospecimenClassifier' already exists. Creating a new version of this model...\n"]},{"output_type":"display_data","data":{"application/vnd.mlflow.run-widget+json":{"info":{"artifact_uri":"sds://onelakesouthafricanorth.pbidedicated.windows.net/cde60769-1208-4712-9d88-602cb5dae476/05fdd04f-1a5d-4785-be80-12ef22e29bba/4f7ccc8a-f09a-4a51-a9ee-5a8da1f4b95a/artifacts","end_time":1743508087,"experiment_id":"1bf6b0a4-b874-47b8-a79f-292c615471ec","lifecycle_stage":"active","run_id":"4f7ccc8a-f09a-4a51-a9ee-5a8da1f4b95a","run_name":"mighty_carpet_y037hw3z","run_uuid":"4f7ccc8a-f09a-4a51-a9ee-5a8da1f4b95a","start_time":1743508074,"status":"FINISHED","user_id":"561e81b0-4da1-42c1-b290-381c5782272c"},"data":{"metrics":{"train_accuracy":0.997229916897507,"test_accuracy":1},"params":{"n_estimators":"100"},"tags":{"mlflow.user":"dcaf7b03-32e1-45bc-b03b-2da2786f6cfd","synapseml.notebook.artifactId":"541c9fd0-f54a-44d9-bdb9-a8db2d979286","synapseml.user.name":"danny","synapseml.user.id":"7c38aabf-71be-44a2-8bd1-240d7015d15e","synapseml.livy.id":"e50020a4-5e38-4ad5-9b81-a3040d5ab3df","mlflow.rootRunId":"4f7ccc8a-f09a-4a51-a9ee-5a8da1f4b95a","mlflow.runName":"mighty_carpet_y037hw3z","synapseml.experimentName":"model_deployment","synapseml.experiment.artifactId":"05fdd04f-1a5d-4785-be80-12ef22e29bba"}},"inputs":{"dataset_inputs":[]}}},"metadata":{}}],"execution_count":12,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"25725e07-fa66-49ef-b30c-1ad0fc305722"},{"cell_type":"code","source":["import mlflow\n","import pandas as pd\n","import numpy as np\n","import json\n","from notebookutils import mssparkutils\n","\n","def load_model_artifacts():\n","    \"\"\"\n","    Load model and preprocessing pipeline from MLflow\n","    \"\"\"\n","    try:\n","        # Load the entire run artifacts\n","        client = mlflow.tracking.MlflowClient()\n","        latest_version = client.get_latest_versions(\"BiospecimenClassifier\")[0]\n","        run_id = latest_version.run_id\n","        \n","        # Load model and preprocessor separately\n","        model_uri = f\"runs:/{run_id}/model\"\n","        preprocessor_uri = f\"runs:/{run_id}/preprocessor\"\n","        \n","        model = mlflow.sklearn.load_model(model_uri)\n","        preprocessor = mlflow.sklearn.load_model(preprocessor_uri)\n","        \n","        return model, preprocessor, latest_version.version\n","    \n","    except Exception as e:\n","        print(f\"Error loading model artifacts: {str(e)}\")\n","        raise\n","\n","# Load model components\n","model, preprocessor, model_version = load_model_artifacts()\n","\n","def validate_input(data):\n","    \"\"\"Validate input data structure and values\"\"\"\n","    required_columns = [\n","        'Aliquot Quantity', \n","        'Aliquot Volume',\n","        'Concentration',\n","        'Days To Collection',\n","        'Days To Sample Procurement',\n","        'Current Weight',\n","        'Initial Weight'\n","    ]\n","    \n","    # Check all required columns are present\n","    missing_cols = [col for col in required_columns if col not in data]\n","    if missing_cols:\n","        raise ValueError(f\"Missing required columns: {missing_cols}\")\n","    \n","    # Convert to DataFrame for processing\n","    input_df = pd.DataFrame([data])\n","    \n","    # Check for non-numeric values\n","    for col in required_columns:\n","        if not pd.api.types.is_numeric_dtype(input_df[col]):\n","            try:\n","                input_df[col] = pd.to_numeric(input_df[col])\n","            except:\n","                raise ValueError(f\"Column {col} contains non-numeric value: {input_df[col].values[0]}\")\n","    \n","    return input_df[required_columns]\n","\n","def score(data):\n","    \"\"\"\n","    Score new data using the deployed model\n","    Args:\n","        data: Dictionary with feature values\n","    Returns:\n","        Dictionary with predictions and metadata\n","    \"\"\"\n","    try:\n","        # Validate and prepare input\n","        input_data = validate_input(data)\n","        \n","        # Preprocess (handles NaN if any remain)\n","        processed_data = preprocessor.transform(input_data)\n","        \n","        # Verify no NaN values\n","        if np.isnan(processed_data).any():\n","            raise ValueError(\"NaN values present after preprocessing\")\n","        \n","        # Get predictions\n","        prediction = int(model.predict(processed_data)[0])\n","        probabilities = model.predict_proba(processed_data)[0].tolist()\n","        \n","        return {\n","            \"prediction\": prediction,\n","            \"probabilities\": probabilities,\n","            \"status\": \"success\",\n","            \"model_version\": model_version\n","        }\n","        \n","    except Exception as e:\n","        return {\n","            \"error\": str(e),\n","            \"status\": \"error\",\n","            \"input_received\": data\n","        }\n","\n","# Example test\n","if __name__ == \"__main__\":\n","    test_data = {\n","        \"Aliquot Quantity\": 5.2,\n","        \"Aliquot Volume\": 1.0,\n","        \"Concentration\": 50.0,\n","        \"Days To Collection\": 10,\n","        \"Days To Sample Procurement\": 12,\n","        \"Current Weight\": 0.5,\n","        \"Initial Weight\": 0.6\n","    }\n","    \n","    result = score(test_data)\n","    print(\"Test scoring result:\")\n","    print(json.dumps(result, indent=2))\n","    "],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":16,"statement_ids":[16],"state":"finished","livy_statement_state":"available","session_id":"e50020a4-5e38-4ad5-9b81-a3040d5ab3df","normalized_state":"finished","queued_time":"2025-04-01T11:48:46.3928457Z","session_start_time":null,"execution_start_time":"2025-04-01T11:48:46.3943776Z","execution_finish_time":"2025-04-01T11:48:49.0170382Z","parent_msg_id":"f220882e-e408-4be1-9b86-e576f49c9351"},"text/plain":"StatementMeta(, e50020a4-5e38-4ad5-9b81-a3040d5ab3df, 16, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stderr","text":["/tmp/ipykernel_6012/159969211.py:14: FutureWarning: ``mlflow.tracking.client.MlflowClient.get_latest_versions`` is deprecated since 2.9.0. Model registry stages will be removed in a future major release. To learn more about the deprecation of model registry stages, see our migration guide here: https://mlflow.org/docs/2.12.2/model-registry.html#migrating-from-stages\n  latest_version = client.get_latest_versions(\"BiospecimenClassifier\")[0]\n"]},{"output_type":"display_data","data":{"text/plain":"Downloading artifacts:   0%|          | 0/9 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"65cf402a9e374808a15884343d8496b9"}},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"Downloading artifacts:   0%|          | 0/9 [00:00<?, ?it/s]","application/vnd.jupyter.widget-view+json":{"version_major":2,"version_minor":0,"model_id":"12e47caad77147be841ee49eac18f0e6"}},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Test scoring result:\n{\n  \"prediction\": 1,\n  \"probabilities\": [\n    0.0,\n    1.0\n  ],\n  \"status\": \"success\",\n  \"model_version\": \"2\"\n}\n"]},{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":17,"statement_ids":[17],"state":"finished","livy_statement_state":"available","session_id":"e50020a4-5e38-4ad5-9b81-a3040d5ab3df","normalized_state":"finished","queued_time":"2025-04-01T11:48:51.0462336Z","session_start_time":null,"execution_start_time":"2025-04-01T11:48:51.047614Z","execution_finish_time":"2025-04-01T11:48:51.3668893Z","parent_msg_id":"4b240cca-914b-437c-9505-57476da08759"},"text/plain":"StatementMeta(, e50020a4-5e38-4ad5-9b81-a3040d5ab3df, 17, Finished, Available, Finished)"},"metadata":{}}],"execution_count":13,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"4f04db78-7834-45b8-9b00-db371ff2e1fd"}],"metadata":{"kernel_info":{"name":"synapse_pyspark"},"kernelspec":{"name":"synapse_pyspark","language":"Python","display_name":"Synapse PySpark"},"language_info":{"name":"python"},"microsoft":{"language":"python","language_group":"synapse_pyspark","ms_spell_check":{"ms_spell_check_language":"en"}},"widgets":{"application/vnd.jupyter.widget-state+json":{"version_major":2,"version_minor":0,"state":{"667d426548d34986af007b5aecfd4617":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"18180fd849a64045baf4d0a689e02073":{"model_name":"HTMLStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":"","font_size":null,"text_color":null}},"2846c3ddfb274223b784e94deda55801":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"7ac65861fd8d4147b9075f8c7d701287":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"65c75526d0b34a949fdd16a7d2b786cc":{"model_name":"HTMLStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":"","font_size":null,"text_color":null}},"c576ab227e674478893824085df73fbc":{"model_name":"ProgressStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":""}},"6a8769511a3b47a6b47032bc64b5ba5a":{"model_name":"HTMLModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":" 9/9 [00:00&lt;00:00, 22.76it/s]","layout":"IPY_MODEL_2846c3ddfb274223b784e94deda55801","style":"IPY_MODEL_081c003870584b3c9cf0b27f4143435e"}},"efc7f2647a72486891b6fe26fc4b9bcb":{"model_name":"HTMLModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":"Downloading artifacts: 100%","layout":"IPY_MODEL_caffed907567450193252a922d529cde","style":"IPY_MODEL_aee981ac0d744191a8b587fe6f1c77e4"}},"610615ce8b224fa98c3f5006606e0ff9":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"499c44658e664bfaa8db65c013970799":{"model_name":"ProgressStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":""}},"325a61cfb6974777904a5a1cd736094d":{"model_name":"FloatProgressModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":9,"max":9,"bar_style":"success","style":"IPY_MODEL_c576ab227e674478893824085df73fbc","layout":"IPY_MODEL_667d426548d34986af007b5aecfd4617"}},"06fd0ac661214a8d93cabc415ad627ea":{"model_name":"HTMLModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":" 9/9 [00:00&lt;00:00, 11.64it/s]","layout":"IPY_MODEL_610615ce8b224fa98c3f5006606e0ff9","style":"IPY_MODEL_65c75526d0b34a949fdd16a7d2b786cc"}},"ccf26434afa44af98563bf310fba83ac":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"0d5898265127416a9b9b788794ff2014":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"aee981ac0d744191a8b587fe6f1c77e4":{"model_name":"HTMLStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":"","font_size":null,"text_color":null}},"cf88ac05097c4fdf9fe1d65cd0f32a98":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"caffed907567450193252a922d529cde":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"081c003870584b3c9cf0b27f4143435e":{"model_name":"HTMLStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":"","font_size":null,"text_color":null}},"db83b088a54e45458d6e8a0619fee27e":{"model_name":"HTMLModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":"Downloading artifacts: 100%","layout":"IPY_MODEL_cf88ac05097c4fdf9fe1d65cd0f32a98","style":"IPY_MODEL_18180fd849a64045baf4d0a689e02073"}},"65cf402a9e374808a15884343d8496b9":{"model_name":"HBoxModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"children":["IPY_MODEL_db83b088a54e45458d6e8a0619fee27e","IPY_MODEL_325a61cfb6974777904a5a1cd736094d","IPY_MODEL_06fd0ac661214a8d93cabc415ad627ea"],"layout":"IPY_MODEL_ccf26434afa44af98563bf310fba83ac"}},"12e47caad77147be841ee49eac18f0e6":{"model_name":"HBoxModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"children":["IPY_MODEL_efc7f2647a72486891b6fe26fc4b9bcb","IPY_MODEL_8f6e1166e13e42c69484caee5ccbc2df","IPY_MODEL_6a8769511a3b47a6b47032bc64b5ba5a"],"layout":"IPY_MODEL_0d5898265127416a9b9b788794ff2014"}},"8f6e1166e13e42c69484caee5ccbc2df":{"model_name":"FloatProgressModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":9,"max":9,"bar_style":"success","style":"IPY_MODEL_499c44658e664bfaa8db65c013970799","layout":"IPY_MODEL_7ac65861fd8d4147b9075f8c7d701287"}}}}},"nteract":{"version":"nteract-front-end@1.0.0"},"spark_compute":{"compute_id":"/trident/default","session_options":{"conf":{"spark.synapse.nbs.session.timeout":"1200000"}}},"dependencies":{"lakehouse":{"known_lakehouses":[{"id":"53477481-ba13-4a4f-a8ea-d1f736d0f87e"}],"default_lakehouse":"53477481-ba13-4a4f-a8ea-d1f736d0f87e","default_lakehouse_name":"GenomeLH","default_lakehouse_workspace_id":"cde60769-1208-4712-9d88-602cb5dae476"}}},"nbformat":4,"nbformat_minor":5}