{"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":"## Import Libraries","metadata":{"id":"6Lm8oDa4q6H4"}},{"cell_type":"code","source":"from google.colab import drive\ndrive.mount('/content/drive')","metadata":{"id":"kysSsaYf4fVv","outputId":"929ba288-454c-499e-f735-6f42193dad56"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n#visualization\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n#data wrangling\nimport pandas as pd\nimport numpy as np\n\n#keras layers & model\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Conv2D, Flatten, Dropout, Activation\nfrom keras.layers import MaxPooling2D, BatchNormalization\n\n#One Hot Encoding\nfrom keras.utils import to_categorical\n\nfrom tensorflow.keras import regularizers\nfrom tensorflow.keras.optimizers import SGD, Adam\nfrom tensorflow.python.client import device_lib\n\nfrom tensorflow.keras.metrics import Accuracy\nfrom sklearn.metrics import (confusion_matrix, \n                             classification_report, \n                             accuracy_score, \n                             f1_score, \n                             roc_auc_score)\n\nfrom sklearn.model_selection import train_test_split\nimport random\nimport os\nfrom random import randint\nimport random as rdn\n#from keras.preprocessing.image import ImageDataGenerator, load_img\n\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.utils import load_img\n\nfrom tensorflow.keras.preprocessing.image import array_to_img, load_img\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator,img_to_array\n\n\n\n#from keras.applications import resnet50\n#from keras.applications.resnet50 import preprocess_input\nfrom keras import optimizers\nfrom keras import regularizers\nfrom keras.callbacks import EarlyStopping,LearningRateScheduler,ReduceLROnPlateau\nfrom keras.callbacks import ModelCheckpoint\n","metadata":{"id":"16TG-sF3qyEM"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir -p ~/.kaggle\n!cp kaggle.json ~/.kaggle/","metadata":{"id":"MWw1sde-6Pi3"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!kaggle competitions download -c dogs-vs-cats","metadata":{"id":"uWvbpJbT6Eho","outputId":"3eb695ab-d00e-4c39-fc55-9001bb2700eb"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import zipfile\n\nzip_files = ['test1', 'train']\n\nzf = zipfile.ZipFile(\"/content/dogs-vs-cats.zip\",\"r\")\nzf.extractall()\nzf.close()\n","metadata":{"id":"_aeuTx0b6_Bb"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nzf = zipfile.ZipFile(\"test1.zip\")\nzf.extractall('/content')\nzf.close()\n","metadata":{"id":"05u3jrRf9HTC"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nzf = zipfile.ZipFile(\"/content/train.zip\",\"r\")\nzf.extractall('/content')\nzf.close()\n","metadata":{"id":"YyaXSWlK9Rmn"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filenames = os.listdir(\"/content/train\")\nlabels = []\nfor filename in filenames:\n    label = filename.split('.')[0]\n    if label == 'dog':\n        labels.append(1)\n    else:\n        labels.append(0)\n\ndf = pd.DataFrame({\n    'filename': filenames,\n    'category': labels\n})","metadata":{"id":"fVvYwhKR9djB"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preprocessing","metadata":{"id":"uXN5IYEPJgny"}},{"cell_type":"code","source":"df.head(3)","metadata":{"id":"Vz3V27jI6-z3","outputId":"6d321bb1-d45f-4151-8aa2-28b8cd45c74e"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.isnull().sum()","metadata":{"id":"qD3A-_W86-wp","outputId":"78a0a46a-b37d-4670-bdf7-a3bd05993b35"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.countplot(df['category'])","metadata":{"id":"dMy31O3dsBov","outputId":"8e72844e-88e6-46d2-ff88-c0b6b0770d67"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['category'].value_counts(dropna= False)","metadata":{"id":"HDNBpbQTZGPT","outputId":"a16532e0-f9f6-42fe-bfca-81755d585657"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.info()","metadata":{"id":"KUNuWSLFujLM","outputId":"0b53e26c-c3dd-44bd-c086-90ab89a56f73"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ntest_img = random.choice(filenames)\n\nimage = load_img(\"/content/train/\"+test_img)\n\n\nplt.imshow(image)\n\n#matplotlib.pyplot.imshow(image)","metadata":{"id":"LNjINAseQvdJ","outputId":"5e24fbf3-0a44-4ef4-f2f6-c48ed4dc5c02"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_path = 'train/'\n\nn_pictures = 6 # number of pictures to be shown\ncolumns = int(n_pictures / 2)\nrows = 2\nplt.figure(figsize=(40, 12))\nfor i in range(n_pictures):\n    num = i + 1\n    ax = plt.subplot(rows, columns, i + 1)\n    if i < columns:\n        image_name = 'cat.' + str(rdn.randint(1, 1000)) + '.jpg'\n    else: \n        image_name = 'dog.' + str(rdn.randint(1, 1000)) + '.jpg'\n    plt.xlabel(image_name)    \n    plt.imshow(load_img(train_path + image_name)) ","metadata":{"id":"kGOguufGYV5g","outputId":"29405223-72b2-458e-fada-83f441b3751c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df, validate_df = train_test_split(df, test_size=0.20, random_state=42)\n\ntrain_df = train_df.reset_index(drop=True)\ntotal_train = train_df.shape[0]\n\nvalidate_df = validate_df.reset_index(drop=True)\ntotal_validate = validate_df.shape[0]\n#train_df.head()\n\nprint(len(train_df), len(validate_df))","metadata":{"id":"fx2xRs09G-Zx","outputId":"45351606-4281-4558-aae9-e4b4131bb171"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['category'].value_counts().plot.bar()","metadata":{"id":"uGSTAdMnPsRO","outputId":"b80eed9e-53fd-41ad-ca39-dc7cde4726cd"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"validate_df['category'].value_counts().plot.bar()","metadata":{"id":"l4w6L8U8PsKu","outputId":"9b84c2da-85e4-4c84-edba-3c78dc54ad36"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# set the dimensions to which we will convert the images\nimg_width, img_height = 128, 128\ntarget_size = (img_width, img_height)\nbatch_size = 15\n#rescale=1.0/255\n","metadata":{"id":"yX9iWSODY3gI"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## configure the train data generator\n","metadata":{"id":"kyYSghVpunNF"}},{"cell_type":"code","source":"# FAST_RUN = False\n# IMAGE_WIDTH=128\n# IMAGE_HEIGHT=128\n# IMAGE_SIZE=(IMAGE_WIDTH, IMAGE_HEIGHT)\n# IMAGE_CHANNELS=3\n\n# batch_size=15","metadata":{"id":"t4xdF6NnNB6E"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" train_datagen = ImageDataGenerator(\n    rotation_range=15,\n    rescale=1./255,\n    shear_range=0.1,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    width_shift_range=0.1,\n    brightness_range=[0.2,1.2],\n    height_shift_range=0.1\n)\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    train_df, \n    train_path,\n    shear_range=0.2, #\n    zoom_range=0.2, #\n    horizontal_flip=True, #\n    \n    shuffle=True, # shuffle the image data\n    x_col='filename', y_col='category',\n    classes=['dog', 'cat'],\n    target_size=target_size,\n    batch_size=batch_size,\n    color_mode=\"rgb\",\n    class_mode='raw')\n\n","metadata":{"id":"dJZPzGnALpRM","outputId":"a6126b76-25e8-4b7d-d324-86b84c4df218"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"validation_datagen = ImageDataGenerator(rescale=1./255)\n\n\nvalidation_generator = validation_datagen.flow_from_dataframe(\n    validate_df, \n    train_path,\n    shear_range=0.2, #\n    zoom_range=0.2, #\n    horizontal_flip=True, # \n    shuffle=True, # shuffle the image data\n    x_col='filename', y_col='category',\n    classes=['dog', 'cat'],\n    target_size=target_size,\n    batch_size=batch_size,\n    color_mode=\"rgb\",\n    class_mode='raw'\n)","metadata":{"id":"4vb0iiJsLpLc","outputId":"b0cd4f6a-9812-475e-c061-638bafc48f91"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"example_df = train_df.sample(n=1).reset_index(drop=True)\nexample_generator = train_datagen.flow_from_dataframe(\n    example_df, \n    \"train/\", \n    x_col='filename',\n    y_col='category',\n    target_size=target_size,\n    class_mode='raw'\n)","metadata":{"id":"IMBcJuZ3bZz7","outputId":"8ae35de1-de79-4dd2-aa65-f16f3d5de73a"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(12, 12))\nfor i in range(0, 15):\n    plt.subplot(5, 3, i+1)\n    for X_batch, Y_batch in example_generator:\n        image = X_batch[0]\n        plt.imshow(image)\n        break\nplt.tight_layout()\nplt.show()","metadata":{"id":"UEdxagF8bluT","outputId":"f7315481-30b0-4a99-fc38-2c38c35dc36d"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Model","metadata":{"id":"FdCXpx0XVcxi"}},{"cell_type":"code","source":"input_shape = (img_width, img_height, 3)\nprint(input_shape)\n\nmodel = Sequential()\nmodel.add(Conv2D(32, (3, 3), strides=(1, 1), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=input_shape))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Dropout(0.20))\n\nmodel.add(Conv2D(64, (3, 3), strides=(1, 1), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Dropout(0.20))\n\nmodel.add(Conv2D(64, (3, 3), strides=(1, 1), activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Dropout(0.20))\n\nmodel.add(Conv2D(128, (3, 3),  strides=(1, 1),activation='relu', kernel_initializer='he_uniform', padding='same'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Dropout(0.20))\n\nmodel.add(Flatten())\nmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\nmodel.add(BatchNormalization())\nmodel.add(Dropout(0.5))\n\n\nmodel.add(Dense(2, activation='sigmoid')) # 2 because we have cat and dog classes\n\n\n","metadata":{"id":"pMfp8lRUVX-B","outputId":"727e151a-1477-4b81-eccc-ca2f2e05b7c6"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# compile the model and print its architecture\nopt = SGD(lr=0.001, momentum=0.9)\nhistory = model.compile(optimizer=opt, loss='sparse_categorical_crossentropy', metrics=['accuracy'])\n","metadata":{"id":"GqwXOOV4ujCJ","outputId":"835dca39-d9fb-4414-dfa7-6235acbd6fcd"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"id":"aHjHKZGFui-M","outputId":"434509e4-900c-47e6-95b3-4e9f69350ef7"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Callbacks","metadata":{"id":"Gw4NbiToauqR"}},{"cell_type":"code","source":"from keras.callbacks import EarlyStopping, ReduceLROnPlateau","metadata":{"id":"_nFm0UOsui8J"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Early Stop**\n\nTo prevent over fitting we will stop the learning after 10 epochs and val_loss value not decreased","metadata":{"id":"cQHKsRdIa6A0"}},{"cell_type":"code","source":"earlystop = EarlyStopping(patience=10, monitor='val_accuracy')","metadata":{"id":"UN85VPHUa2o7"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filepath = 'weights-loss-{epoch:02d}-{val_loss:.2f}.hdf5'\n\ncheckpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, \n                save_best_only=False, save_freq= \"epoch\",  \n                save_weights_only=False, mode='auto')\n\n\n","metadata":{"id":"UEB8V_yat-II"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Learning Rate Reduction\n\nWe will reduce the learning rate when then accuracy not increase for 2 steps","metadata":{"id":"ibFzgk58bDdY"}},{"cell_type":"code","source":"learning_rate_reduction = ReduceLROnPlateau(monitor='val_accuracy', \n                                            patience=2, \n                                            verbose=1, \n                                            factor=0.5, \n                                            min_lr=0.00001)","metadata":{"id":"-78vl3mCui4Q"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callbacks = [earlystop, learning_rate_reduction,checkpoint]","metadata":{"id":"tZhJFN5pui2o"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Fit Model","metadata":{"id":"H1D2vL9tfmSH"}},{"cell_type":"code","source":"model.load_weights('weights-loss-10-0.35.hdf5')","metadata":{"id":"ckmibmNlBHvj"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs=3 if FAST_RUN else 10\nhistory = model.fit_generator(\n    generator = train_generator, \n    epochs = epochs,\n    validation_data = validation_generator,\n    validation_steps = total_validate // batch_size,\n    steps_per_epoch = total_train // batch_size,\n    callbacks = callbacks\n)","metadata":{"id":"QDgVBn1CV3hu","outputId":"955c5958-f0cd-4680-8b2a-041f99eef5ce"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss, accuracy = model.evaluate_generator(validation_generator, total_validate//batch_size, workers=12)\nprint(\"Test: accuracy = %f  ;  loss = %f \" % (accuracy, loss))","metadata":{"id":"7XE-RFnGrPQW","outputId":"8c31fba2-95b7-4ed6-b000-e2b8c9845ac0"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Save Model","metadata":{"id":"pJAz_FxCf6FD"}},{"cell_type":"code","source":"#Safe the weights\nmodel.save_weights('cats-and-dogs-weights-v1.h5')","metadata":{"id":"Yq_lvLpChJ38"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# load Model\n#model.load_weights('cats-and-dogs-weights-v1.h5')","metadata":{"id":"KYJSr3TsHxTd"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#loss, accuracy = model.evaluate_generator(validation_generator, total_validate//batch_size, workers=12)\nprint(\"Test: accuracy = %f  ;  loss = %f \" % (accuracy, loss))","metadata":{"id":"5W8_nScbHyrm","outputId":"1a70bec8-eab0-4a1d-f956-bb6dd0a51503"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Visualise Training","metadata":{"id":"PTFfbaQrgDov"}},{"cell_type":"code","source":"plt.plot(history.history['accuracy'])\nplt.plot(history.history['val_accuracy'])\nplt.legend(['accuracy','val_accuracy'], loc=\"upper left\")\nplt.title('Model accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('Epoch')\nplt.show()\n","metadata":{"id":"kjEKkioiUUb6","outputId":"989397be-2354-4656-e53b-fc08d0a73c98"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.legend(['loss','val_loss'])\nplt.title('Model Loss')\nplt.ylabel('Loss')\nplt.xlabel('Epoch')\nplt.show()","metadata":{"id":"aPc45omRUUVr","outputId":"99aaa8a1-3b38-4bd0-a56f-75966e5dbf71"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Accuracy\n","metadata":{"id":"_kNpRpMQh04h"}},{"cell_type":"code","source":"y_val = validate_df['category']\n\ny_pred = model.predict_generator(validation_generator)","metadata":{"id":"yXornNU7rp03","outputId":"4cbf62ae-9643-4ae7-8f29-785b96b12e49"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_val","metadata":{"id":"904cAXlrr0RC","outputId":"f3a4650d-1c89-477b-ef4d-6a556e6f1d4c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred","metadata":{"id":"bDRSQ0dUr8iE","outputId":"69e80caa-014b-4238-aff2-a909dbf4277b"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"threshold = 0.5\ny_final = np.where(y_pred > threshold, 1,0)","metadata":{"id":"H1zO6cxjrpt1"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_final.size","metadata":{"id":"jxsX_mV-tLEN","outputId":"d8762d9d-3b20-409c-985b-5292ea86529f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rounded_y_final = np.argmax(y_final, axis=1)","metadata":{"id":"IxAJrBJKrfwO"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import seaborn as sns\nfrom sklearn.metrics import confusion_matrix","metadata":{"id":"78ea_UHDrpev"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# compute the confusion matrix\nconfusion_mtx = confusion_matrix(y_val, rounded_y_final) \n# plot the confusion matrix\nf,ax = plt.subplots(figsize=(8, 8))\nsns.heatmap(confusion_mtx, annot=True, linewidths=0.01,cmap=\"Blues\",linecolor=\"gray\", fmt= '.1f',ax=ax)\nplt.xlabel(\"Predicted Label\")\nplt.ylabel(\"True Label\")\nplt.title(\"Confusion Matrix\")\nplt.show()","metadata":{"id":"D_2QhBThs-Yp","outputId":"b42e45e3-b9e4-481f-c39d-d0c1112c9920"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import classification_report\n\n# Generate a classification report\nreport = classification_report(y_val, rounded_y_final, target_names=['0','1'])\n\nprint(report)","metadata":{"id":"_yMZEwiFs-Uq","outputId":"b9e34cf3-aaf1-4c77-e888-e9ffa2b9cdcf"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Testing Data","metadata":{"id":"VueQFrxGgLe0"}},{"cell_type":"code","source":"filenames = os.listdir(\"/content/test1\")\n\ntest_df = pd.DataFrame({\n    'filename': filenames\n})\nnb_samples = test_df.shape[0]","metadata":{"id":"_sZ4cm4K8HQu"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Test Generator","metadata":{"id":"XFPsBBZBgQ3a"}},{"cell_type":"code","source":"test_path = \"/content/test1\"","metadata":{"id":"WFaAQhag8VR2"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_datagen = ImageDataGenerator(rescale=1./255)\n\ntest_generator = test_datagen.flow_from_dataframe(\n    test_df, \n    test_path, \n    shuffle= False, # shuffle the image data\n    x_col='filename', \n    y_col= None,\n    #classes=['dog', 'cat'],\n    target_size=target_size,\n    batch_size=batch_size,\n    #color_mode=\"rgb\",\n    class_mode= None\n)\n","metadata":{"id":"f2XruZMyb_SC","outputId":"969e4c61-402b-45d0-d5e2-8234a2d3b61c"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##PREDICT","metadata":{"id":"0O2ZTadng-mg"}},{"cell_type":"code","source":"predict = model.predict_generator(test_generator, steps=np.ceil(nb_samples/batch_size))","metadata":{"id":"Q1uLnehzpQLX","outputId":"b78f37e4-b54f-4efd-939a-9d5a2642ec11"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['predicted'] = np.argmax(predict, axis=-1)","metadata":{"id":"Fkaehtke4vw0"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df.head()","metadata":{"id":"7hnULoZh4voT","outputId":"73cfec78-ab4e-4b95-8ca5-f2531fca8d90"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['predicted'].value_counts().plot.bar()","metadata":{"id":"WyCBjxzc5EW6","outputId":"63d19956-3cbd-47f0-f149-c4342ec501ed"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['predicted'] = test_df['predicted'].replace({ 1: 'dog', 0: 'cat'})","metadata":{"id":"8DS0aU8b_Q0V"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df.head()","metadata":{"id":"mMofCOAi_Zjy","outputId":"ae3007f3-c646-456e-8368-fd09417fefc3"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_test = test_df.head(18)\nsample_test.head()\nplt.figure(figsize=(12, 24))\nfor index, row in sample_test.iterrows():\n    filename = row['filename']\n    predicted = row['predicted']\n    img = load_img(\"/content/test1/\"+filename, target_size= target_size)\n    plt.subplot(6, 3, index+1)\n    plt.imshow(img)\n    plt.xlabel(f'{filename}, predicted: {predicted}')\nplt.tight_layout()\nplt.show()","metadata":{"id":"1Pe3Of4T5ePi","outputId":"064632db-d795-4891-a6ec-d837812b2c7a"},"execution_count":null,"outputs":[]}]}