{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## constant variables ##","metadata":{}},{"cell_type":"code","source":"ROOT_DIR = '../input/cassava-leaf-disease-classification/'\nTRAIN_DIR = ROOT_DIR + '/train_images/'\nTEST_DIR = ROOT_DIR + '/test_images/'\nIMG_SIZE = 300# IMG_SIZE is determined by EfficientNet model choice. I selected EfficientNetB3 model. therefore input = (300,300,3)\nBATCH_SIZE = 32\nNUM_CLASSES = 5\nEPOCHS = 50\nSEED = 42 \n#why 42 always ? https://medium.com/geekculture/the-story-behind-random-seed-42-in-machine-learning-b838c4ac290a\nTEST_SIZE = 0.2\nVALIDATION_SIZE = 0.1\nLEARNING_RATE =  1e-4\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-10-14T05:56:44.194938Z","iopub.execute_input":"2021-10-14T05:56:44.195479Z","iopub.status.idle":"2021-10-14T05:56:44.335720Z","shell.execute_reply.started":"2021-10-14T05:56:44.195378Z","shell.execute_reply":"2021-10-14T05:56:44.334890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Downloading efficientnet weights ##\nin this notebook I will use efficientnet for transfer learning. therfore we need latest EfficientNet weights. \n\nhttps://keras.io/examples/vision/image_classification_efficientnet_fine_tuning/","metadata":{}},{"cell_type":"code","source":"!wget https://storage.googleapis.com/cloud-tpu-checkpoints/efficientnet/noisystudent/noisy_student_efficientnet-b3.tar.gz","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:56:44.337567Z","iopub.execute_input":"2021-10-14T05:56:44.338007Z","iopub.status.idle":"2021-10-14T05:56:49.358776Z","shell.execute_reply.started":"2021-10-14T05:56:44.337971Z","shell.execute_reply":"2021-10-14T05:56:49.357996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!tar -xf /kaggle/working/noisy_student_efficientnet-b3.tar.gz","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:56:49.359955Z","iopub.execute_input":"2021-10-14T05:56:49.360184Z","iopub.status.idle":"2021-10-14T05:56:51.030042Z","shell.execute_reply.started":"2021-10-14T05:56:49.360148Z","shell.execute_reply":"2021-10-14T05:56:51.029141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!wget https://raw.githubusercontent.com/9vimu9/efficientnet_weight_update_util/main/efficientnet_weight_update_util.py","metadata":{"execution":{"iopub.status.busy":"2021-10-14T06:03:55.104675Z","iopub.execute_input":"2021-10-14T06:03:55.105056Z","iopub.status.idle":"2021-10-14T06:03:56.476061Z","shell.execute_reply.started":"2021-10-14T06:03:55.105020Z","shell.execute_reply":"2021-10-14T06:03:56.475198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!python ./efficientnet_weight_update_util.py --model b3 --notop --ckpt ./noisy_student_efficientnet-b3/model.ckpt --o ./efficientnetb3_notop.h5","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:56:53.240599Z","iopub.execute_input":"2021-10-14T05:56:53.240842Z","iopub.status.idle":"2021-10-14T05:57:05.323397Z","shell.execute_reply.started":"2021-10-14T05:56:53.240816Z","shell.execute_reply":"2021-10-14T05:57:05.322611Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Importing packages ## ","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt #draw graphs\nimport numpy as np\nimport pandas as pd #create dataframes using csv files\nimport os\nfrom sklearn.model_selection import train_test_split # to create train, test, validation datasets\nimport tensorflow as tf\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.losses import SparseCategoricalCrossentropy\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator #for data preprocessing, image augmentation\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\nfrom tensorflow.keras.applications import EfficientNetB3 #transfer learning model\nfrom tensorflow.keras.utils import plot_model # to draw summary of the model","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:05.326460Z","iopub.execute_input":"2021-10-14T05:57:05.326697Z","iopub.status.idle":"2021-10-14T05:57:07.392927Z","shell.execute_reply.started":"2021-10-14T05:57:05.326670Z","shell.execute_reply":"2021-10-14T05:57:07.392214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Seeding ##\nWe utilize random seed values when constructing training, validation, and test dataset. The aim is to make sure we receive the same training and validation dataset while we utilize various hyperparameters or methods in order to analyze the performance of different models","metadata":{}},{"cell_type":"code","source":"tf.random.set_seed(SEED) #tensorflow\nos.environ['PYTHONHASHSEED'] = str(SEED) #python\nnp.random.seed(SEED) #numpy\n","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:07.394301Z","iopub.execute_input":"2021-10-14T05:57:07.394536Z","iopub.status.idle":"2021-10-14T05:57:07.399411Z","shell.execute_reply.started":"2021-10-14T05:57:07.394505Z","shell.execute_reply":"2021-10-14T05:57:07.398660Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## preparing training, validation and test datasets ##\nlabels of the dataset are included in the train.csv.we can use read_csv function in pandas to read the file. it will return a DataFrame. it is very big advantage. because in Tensorflow, we can directly feed DataFrame object to train our model","metadata":{}},{"cell_type":"code","source":"all_data_frame = pd.read_csv(ROOT_DIR + 'train.csv')","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:07.400819Z","iopub.execute_input":"2021-10-14T05:57:07.401072Z","iopub.status.idle":"2021-10-14T05:57:07.436465Z","shell.execute_reply.started":"2021-10-14T05:57:07.401040Z","shell.execute_reply":"2021-10-14T05:57:07.435859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# read first 10 records\nall_data_frame.sample(10)","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:07.437590Z","iopub.execute_input":"2021-10-14T05:57:07.437906Z","iopub.status.idle":"2021-10-14T05:57:07.461723Z","shell.execute_reply.started":"2021-10-14T05:57:07.437871Z","shell.execute_reply":"2021-10-14T05:57:07.460920Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"change the data type of the column \"label\" to string","metadata":{}},{"cell_type":"code","source":"all_data_frame = all_data_frame.astype({\"label\": str})","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:07.464796Z","iopub.execute_input":"2021-10-14T05:57:07.464984Z","iopub.status.idle":"2021-10-14T05:57:07.496807Z","shell.execute_reply.started":"2021-10-14T05:57:07.464961Z","shell.execute_reply":"2021-10-14T05:57:07.496187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"creating test dataset","metadata":{}},{"cell_type":"code","source":"other_data_frame, test_data_frame = train_test_split(\n                        all_data_frame, \n                        test_size = TEST_SIZE, \n                        random_state = SEED)\nprint(\"test data size : \"+str(test_data_frame.shape[0]))","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:07.497945Z","iopub.execute_input":"2021-10-14T05:57:07.498196Z","iopub.status.idle":"2021-10-14T05:57:07.506179Z","shell.execute_reply.started":"2021-10-14T05:57:07.498164Z","shell.execute_reply":"2021-10-14T05:57:07.505470Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"creating training and validation dataset using remaining dataset","metadata":{}},{"cell_type":"code","source":"train_data_frame, validation_data_frame = train_test_split(\n                    other_data_frame, \n                    test_size = VALIDATION_SIZE, \n                    random_state = SEED)\n\nprint(\"train data size : \"+str(train_data_frame.shape[0]))\nprint(\"validation data size : \"+str(validation_data_frame.shape[0]))","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:07.507337Z","iopub.execute_input":"2021-10-14T05:57:07.507762Z","iopub.status.idle":"2021-10-14T05:57:07.516849Z","shell.execute_reply.started":"2021-10-14T05:57:07.507726Z","shell.execute_reply":"2021-10-14T05:57:07.516039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## data preprocessing ##\nI used ImageDataGenerator object to increase training dataset by doing image augmentation. this is very useful method when the dataset is small","metadata":{}},{"cell_type":"code","source":"train_image_data_generator = ImageDataGenerator(\n                    rotation_range = 270, \n                    zoom_range = [0.05,1.0],\n                    shear_range = 0.3, \n                    brightness_range = [0.5,1.5],\n                    horizontal_flip = True,\n                    vertical_flip = True,\n                    width_shift_range = 0.4, \n                    height_shift_range = 0.4, \n                    fill_mode = 'nearest'\n)","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:07.518132Z","iopub.execute_input":"2021-10-14T05:57:07.518875Z","iopub.status.idle":"2021-10-14T05:57:07.524890Z","shell.execute_reply.started":"2021-10-14T05:57:07.518839Z","shell.execute_reply":"2021-10-14T05:57:07.523843Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"now we created a image generator for training dataset.next, we can select data source for the image generator.in earlier steps, I converted dataset to dataframe. therfore we can use ImageDataGenerator's built in function, flow_from_dataframe.","metadata":{}},{"cell_type":"code","source":"\ntrain_data_frame_iterator = train_image_data_generator.flow_from_dataframe(\n                    train_data_frame,\n                    directory = TRAIN_DIR,\n                    x_col = \"image_id\",\n                    y_col = \"label\",\n                    target_size = (IMG_SIZE,IMG_SIZE),\n                    class_mode = \"sparse\",\n                    batch_size = BATCH_SIZE,\n                    shuffle = True,\n                    seed = SEED,\n                    interpolation = \"nearest\"\n)","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:07.526169Z","iopub.execute_input":"2021-10-14T05:57:07.526577Z","iopub.status.idle":"2021-10-14T05:57:41.844491Z","shell.execute_reply.started":"2021-10-14T05:57:07.526542Z","shell.execute_reply":"2021-10-14T05:57:41.843781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"creating DataFrame object for validation","metadata":{}},{"cell_type":"code","source":"\nvalidation_data_frame_iterator =  ImageDataGenerator().flow_from_dataframe(\n                    validation_data_frame,\n                    directory = TRAIN_DIR,\n                    x_col = \"image_id\",\n                    y_col = \"label\",\n                    target_size = (IMG_SIZE,IMG_SIZE),\n                    class_mode = \"sparse\",\n                    batch_size = BATCH_SIZE,\n                    shuffle = True,\n                    seed = SEED,\n                    interpolation = \"nearest\"\n)","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:41.845685Z","iopub.execute_input":"2021-10-14T05:57:41.845937Z","iopub.status.idle":"2021-10-14T05:57:45.440014Z","shell.execute_reply.started":"2021-10-14T05:57:41.845901Z","shell.execute_reply":"2021-10-14T05:57:45.439270Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"creating DataFrame object for testing","metadata":{}},{"cell_type":"code","source":"test_data_frame_iterator =  ImageDataGenerator().flow_from_dataframe(\n                    test_data_frame,\n                    directory = TRAIN_DIR,\n                    x_col = \"image_id\",\n                    y_col = \"label\",\n                    target_size = (IMG_SIZE,IMG_SIZE),\n                    class_mode = \"sparse\",\n                    batch_size = BATCH_SIZE,\n                    shuffle = False,\n                    seed = SEED,\n                    interpolation = \"nearest\"\n)","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:45.441346Z","iopub.execute_input":"2021-10-14T05:57:45.441799Z","iopub.status.idle":"2021-10-14T05:57:54.385204Z","shell.execute_reply.started":"2021-10-14T05:57:45.441758Z","shell.execute_reply":"2021-10-14T05:57:54.384360Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model creation and training ## ","metadata":{}},{"cell_type":"code","source":"def create_model_unfreezed():\n    #create sequential Model object\n    model = models.Sequential()\n    \n    #create pretrained EfficientNetB3 model and loading weights from downloaded file in previous steps\n    pre_trained_model = EfficientNetB3(input_shape = (IMG_SIZE, IMG_SIZE, 3), include_top = False, weights = \"./efficientnetb3_notop.h5\",drop_connect_rate=0.2)\n    #make every layer in the pre trained model trainable. that means during the training, weights and biases of the pretrained model can be changed. \n    pre_trained_model.trainable = True\n    #but according to  this documentation BathcNormalization layers need to be kept frozen\n    #https://keras.io/examples/vision/image_classification_efficientnet_fine_tuning/\n    for layer in pre_trained_model.layers:\n        if isinstance(layer, layers.BatchNormalization):\n            layer.trainable = False\n            \n    model.add(pre_trained_model)\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dense(256, activation = 'relu'))\n    model.add(layers.Dropout(0.7)) # to prevent overfitting\n    model.add(layers.Dense(NUM_CLASSES, activation = 'softmax'))\n    plot_model(model, show_shapes = True)\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:54.386714Z","iopub.execute_input":"2021-10-14T05:57:54.386976Z","iopub.status.idle":"2021-10-14T05:57:54.394449Z","shell.execute_reply.started":"2021-10-14T05:57:54.386943Z","shell.execute_reply":"2021-10-14T05:57:54.393478Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = create_model_unfreezed()\n","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:54.396095Z","iopub.execute_input":"2021-10-14T05:57:54.396452Z","iopub.status.idle":"2021-10-14T05:57:55.620967Z","shell.execute_reply.started":"2021-10-14T05:57:54.396342Z","shell.execute_reply":"2021-10-14T05:57:55.619095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(\n        loss = SparseCategoricalCrossentropy(name='sparse_categorical_crossentropy'),\n        optimizer = Adam(learning_rate = LEARNING_RATE),\n        metrics = ['accuracy']\n)","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.621750Z","iopub.status.idle":"2021-10-14T05:57:55.622053Z","shell.execute_reply.started":"2021-10-14T05:57:55.621894Z","shell.execute_reply":"2021-10-14T05:57:55.621913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Creating callbacks ##","metadata":{}},{"cell_type":"code","source":"# Stop training when a monitored metric has stopped improving. usefull to prevent overfitting\nearly_stopping = EarlyStopping(monitor = 'val_loss',\n                               patience = 4,\n                               mode = 'min',\n                               restore_best_weights = True)\n\n# To save the Keras model in h5 format for future use.\nmodel_checkpoint = ModelCheckpoint('model.h5', \n                             monitor = 'val_accuracy',\n                             mode = 'max', \n                             save_best_only = True)\n\n# When a measure no longer improves, slow down its learning rate.\nreduce_learning_rate = ReduceLROnPlateau(monitor = 'val_loss',\n                              factor = 0.3,\n                              patience = 3,\n                              mode = 'min')","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.623361Z","iopub.status.idle":"2021-10-14T05:57:55.623764Z","shell.execute_reply.started":"2021-10-14T05:57:55.623528Z","shell.execute_reply":"2021-10-14T05:57:55.623546Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Calculating step size ##","metadata":{}},{"cell_type":"code","source":"TRAIN_STEPS_PER_EPOCH = train_data_frame_iterator.n//train_data_frame_iterator.batch_size\nVALIDATION_STEPS_PER_EPOCH = validation_data_frame_iterator.n//validation_data_frame_iterator.batch_size\nTEST_STEPS_PER_EPOCH = test_data_frame_iterator.n//test_data_frame_iterator.batch_size","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.624888Z","iopub.status.idle":"2021-10-14T05:57:55.625525Z","shell.execute_reply.started":"2021-10-14T05:57:55.625245Z","shell.execute_reply":"2021-10-14T05:57:55.625275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" train_data_frame_iterator.n","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.626701Z","iopub.status.idle":"2021-10-14T05:57:55.627411Z","shell.execute_reply.started":"2021-10-14T05:57:55.627156Z","shell.execute_reply":"2021-10-14T05:57:55.627181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data_frame_iterator.batch_size","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.628799Z","iopub.status.idle":"2021-10-14T05:57:55.629269Z","shell.execute_reply.started":"2021-10-14T05:57:55.629022Z","shell.execute_reply":"2021-10-14T05:57:55.629045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.630760Z","iopub.status.idle":"2021-10-14T05:57:55.631369Z","shell.execute_reply.started":"2021-10-14T05:57:55.631088Z","shell.execute_reply":"2021-10-14T05:57:55.631112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_model(model, show_shapes = True)","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.633006Z","iopub.status.idle":"2021-10-14T05:57:55.633423Z","shell.execute_reply.started":"2021-10-14T05:57:55.633198Z","shell.execute_reply":"2021-10-14T05:57:55.633218Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(train_data_frame_iterator,\n                    validation_data = validation_data_frame_iterator,\n                    epochs = EPOCHS,\n                    steps_per_epoch = TRAIN_STEPS_PER_EPOCH,\n                    validation_steps = VALIDATION_STEPS_PER_EPOCH,\n                    callbacks = [reduce_learning_rate,model_checkpoint,early_stopping]\n                   )","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.634678Z","iopub.status.idle":"2021-10-14T05:57:55.635127Z","shell.execute_reply.started":"2021-10-14T05:57:55.634877Z","shell.execute_reply":"2021-10-14T05:57:55.634899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## measuring validation accuracy ##","metadata":{}},{"cell_type":"code","source":"validation_loss, validation_accuracy = model.evaluate(validation_data_frame_iterator, steps = VALIDATION_STEPS_PER_EPOCH)\nprint(\"validation accuracy: {:5.2f}%\".format(100 * validation_accuracy))","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.636125Z","iopub.status.idle":"2021-10-14T05:57:55.636531Z","shell.execute_reply.started":"2021-10-14T05:57:55.636311Z","shell.execute_reply":"2021-10-14T05:57:55.636331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## measrung test accuracy ##","metadata":{}},{"cell_type":"code","source":"test_loss, test_accuracy = model.evaluate(test_data_frame_iterator, steps = TEST_STEPS_PER_EPOCH)\nprint(\"test accuracy: {:5.2f}%\".format(100 * test_accuracy))","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.638541Z","iopub.status.idle":"2021-10-14T05:57:55.639011Z","shell.execute_reply.started":"2021-10-14T05:57:55.638786Z","shell.execute_reply":"2021-10-14T05:57:55.638808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## train accuracy vs validation accuracy ##","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(15, 5))\nplt.plot(history.history['accuracy'], 'b*-', label=\"train accuracy\")\nplt.plot(history.history['val_accuracy'], 'r*-', label=\"validation accuracy\")\nplt.grid()\nplt.title(\"train accuracy vs validation accuracy\")\nplt.ylabel(\"Accuracy\")\nplt.xlabel(\"Epochs\")\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.640081Z","iopub.status.idle":"2021-10-14T05:57:55.640910Z","shell.execute_reply.started":"2021-10-14T05:57:55.640651Z","shell.execute_reply":"2021-10-14T05:57:55.640676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## train loss vs validation loss ##","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(15, 5))\nplt.plot(history.history['loss'], 'b*-', label=\"train loss\")\nplt.plot(history.history['val_loss'], 'r*-', label=\"validation loss\")\nplt.grid()\nplt.title(\"train loss vs validation loss\")\nplt.ylabel(\"Loss\")\nplt.xlabel(\"Epochs\")\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-10-14T05:57:55.642189Z","iopub.status.idle":"2021-10-14T05:57:55.642642Z","shell.execute_reply.started":"2021-10-14T05:57:55.642404Z","shell.execute_reply":"2021-10-14T05:57:55.642425Z"},"trusted":true},"execution_count":null,"outputs":[]}]}