{"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":"code","source":"!pip install -U seaborn","metadata":{"execution":{"iopub.status.busy":"2022-04-16T04:39:20.588861Z","iopub.execute_input":"2022-04-16T04:39:20.589244Z","iopub.status.idle":"2022-04-16T04:39:29.635727Z","shell.execute_reply.started":"2022-04-16T04:39:20.589175Z","shell.execute_reply":"2022-04-16T04:39:29.634799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Global variables","metadata":{}},{"cell_type":"code","source":"SECONDS = None\nFPS = None","metadata":{"execution":{"iopub.status.busy":"2022-04-16T04:39:29.637562Z","iopub.execute_input":"2022-04-16T04:39:29.63792Z","iopub.status.idle":"2022-04-16T04:39:29.64307Z","shell.execute_reply.started":"2022-04-16T04:39:29.637875Z","shell.execute_reply":"2022-04-16T04:39:29.641695Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Librarys","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\nfrom tensorflow import keras\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.layers import Dense, GRU, Flatten, TimeDistributed, Flatten, BatchNormalization, Activation, Dropout, LSTM,Conv3D, MaxPooling3D, Conv2D, MaxPooling2D\n# from tensorflow.keras.layers.convolutional import \nfrom tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau\nfrom tensorflow.keras import optimizers\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport cv2\n\nimport os\nfrom tqdm.notebook import tqdm\n\nfrom sklearn.model_selection import train_test_split\n\nnp.random.seed(30)\ntf.random.set_seed(30)","metadata":{"execution":{"iopub.status.busy":"2022-04-16T04:39:29.644218Z","iopub.execute_input":"2022-04-16T04:39:29.644454Z","iopub.status.idle":"2022-04-16T04:39:36.783803Z","shell.execute_reply.started":"2022-04-16T04:39:29.644419Z","shell.execute_reply":"2022-04-16T04:39:36.782624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(cv2.__version__)","metadata":{"execution":{"iopub.status.busy":"2022-04-16T04:39:36.785667Z","iopub.execute_input":"2022-04-16T04:39:36.786051Z","iopub.status.idle":"2022-04-16T04:39:36.800969Z","shell.execute_reply.started":"2022-04-16T04:39:36.785989Z","shell.execute_reply":"2022-04-16T04:39:36.79995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# View Dataset\n---","metadata":{}},{"cell_type":"markdown","source":"**Metadata with video label**","metadata":{}},{"cell_type":"code","source":"train_metadata = pd.read_json(\"../input/deepfake-detection-challenge/train_sample_videos/metadata.json\")\ntrain_metadata = train_metadata.T\ntrain_metadata.reset_index(inplace=True)\ntrain_metadata.rename({\"index\":\"name\"},axis=1,inplace=True)\ntrain_metadata.head()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-04-16T04:39:36.803381Z","iopub.execute_input":"2022-04-16T04:39:36.804034Z","iopub.status.idle":"2022-04-16T04:39:37.188426Z","shell.execute_reply.started":"2022-04-16T04:39:36.803967Z","shell.execute_reply":"2022-04-16T04:39:37.187581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Fake/Real videos count","metadata":{}},{"cell_type":"code","source":"# Escolhendo tema grafico\nsns.set_style(\"dark\")\n\n# Configurando tamanho grafico\nfig, ax = plt.subplots(figsize=(10,8))\nbar = sns.countplot(data=train_metadata,x=\"label\",ax=ax)\nax.set_title(\"Real and Fake Videos Split\")\n\n# Adicionando legendas nas barras\nfor p in bar.patches:\n    _x = p.get_x() + p.get_width() / 2\n    _y = p.get_y() + p.get_height() + 4\n    value = f\"{p.get_height()}\"\n    ax.text(_x, _y, value, ha=\"center\")\n\nplt.savefig(\"labels_dist.png\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-16T05:10:00.659547Z","iopub.execute_input":"2022-04-16T05:10:00.659896Z","iopub.status.idle":"2022-04-16T05:10:00.889088Z","shell.execute_reply.started":"2022-04-16T05:10:00.659843Z","shell.execute_reply":"2022-04-16T05:10:00.88811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Video FPS","metadata":{}},{"cell_type":"code","source":"def get_fps_all(train_metadata:pd.DataFrame)->list:\n    fps = []\n    for video_name in tqdm(train_metadata.name,total=train_metadata.shape[0]):\n        path_video = f\"../input/deepfake-detection-challenge/train_sample_videos/{video_name}\"\n        video = cv2.VideoCapture(path_video)\n        fps.append(video.get(cv2.CAP_PROP_FPS))\n        video.release()\n    return fps\n\ntrain_metadata[\"fps\"] = get_fps_all(train_metadata)\nFPS = int(train_metadata[\"fps\"].min())","metadata":{"execution":{"iopub.status.busy":"2022-04-16T04:50:59.983485Z","iopub.execute_input":"2022-04-16T04:50:59.983841Z","iopub.status.idle":"2022-04-16T04:51:15.836533Z","shell.execute_reply.started":"2022-04-16T04:50:59.983764Z","shell.execute_reply":"2022-04-16T04:51:15.835566Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Plot Graph**","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(figsize=(10,8))\ndata = train_metadata[\"fps\"].value_counts()\nsns.barplot(ax=ax,x=data.index,y=list(data))\nax.set_title(\"Frame rate per second\")\nplt.savefig(\"fps_dist.png\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-16T05:56:12.503487Z","iopub.execute_input":"2022-04-16T05:56:12.504406Z","iopub.status.idle":"2022-04-16T05:56:12.927699Z","shell.execute_reply.started":"2022-04-16T05:56:12.504327Z","shell.execute_reply":"2022-04-16T05:56:12.926472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Video Time","metadata":{}},{"cell_type":"code","source":"def getDuration(train_metadata:pd.DataFrame)->list:\n    duration = []\n    for video_name,fps in tqdm(zip(train_metadata.name,train_metadata[\"fps\"]),total=train_metadata.shape[0]):\n        path_video = f\"../input/deepfake-detection-challenge/train_sample_videos/{video_name}\"\n        \n        vidcapture = cv2.VideoCapture(path_video)\n        totalNoFrames = vidcapture.get(cv2.CAP_PROP_FRAME_COUNT);\n        durationInSeconds = round(float(totalNoFrames) / float(fps),4)\n        duration.append(durationInSeconds)\n        vidcapture.release()\n    \n    return duration\n\ntrain_metadata[\"duration\"] = getDuration(train_metadata)\nSECONDS = int(train_metadata[\"duration\"].min())","metadata":{"execution":{"iopub.status.busy":"2022-04-16T04:51:16.137093Z","iopub.execute_input":"2022-04-16T04:51:16.137434Z","iopub.status.idle":"2022-04-16T04:51:24.3923Z","shell.execute_reply.started":"2022-04-16T04:51:16.137375Z","shell.execute_reply":"2022-04-16T04:51:24.391372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Plot Graph**","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(figsize=(10,8))\nsns.histplot(ax=ax,data=train_metadata,x=\"duration\")\nax.set_title(\"Seconds per video\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-16T06:13:19.642685Z","iopub.execute_input":"2022-04-16T06:13:19.643075Z","iopub.status.idle":"2022-04-16T06:13:20.130683Z","shell.execute_reply.started":"2022-04-16T06:13:19.643025Z","shell.execute_reply":"2022-04-16T06:13:20.129467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Width and Height","metadata":{}},{"cell_type":"code","source":"def get_width_height(train_metadata:pd.DataFrame)->tuple:\n    height = []\n    width = []\n\n    for video_name,fps in tqdm(zip(train_metadata.name,train_metadata[\"fps\"]),total=train_metadata.shape[0]):\n        path_video = f\"../input/deepfake-detection-challenge/train_sample_videos/{video_name}\"\n\n        vidcapture = cv2.VideoCapture(path_video)\n        height.append(vidcapture.get(cv2.CAP_PROP_FRAME_HEIGHT))\n        width.append(vidcapture.get(cv2.CAP_PROP_FRAME_WIDTH))\n        vidcapture.release()\n\n    return (width, height)\n\nwidth, height = get_width_height(train_metadata)\ntrain_metadata[\"width\"] = width\ntrain_metadata[\"height\"] = height","metadata":{"execution":{"iopub.status.busy":"2022-04-16T04:51:24.773665Z","iopub.execute_input":"2022-04-16T04:51:24.773978Z","iopub.status.idle":"2022-04-16T04:51:33.613999Z","shell.execute_reply.started":"2022-04-16T04:51:24.773919Z","shell.execute_reply":"2022-04-16T04:51:33.613024Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Plot Graph**","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(1,2,figsize=(10,5))\ndata = train_metadata[\"width\"].value_counts()\nbar = sns.barplot(ax=ax[0],x=data.index,y=list(data))\nfor i,pat in enumerate(bar.patches):\n    ax[0].annotate(f\"{int(pat.get_height())}\",\n                (i,pat.get_height()))\n\nax[0].set_title(\"Width\")\n\ndata = train_metadata[\"height\"].value_counts()\nbar = sns.barplot(ax=ax[1],x=data.index,y=list(data))\nfor i,pat in enumerate(bar.patches):\n    ax[1].annotate(f\"{int(pat.get_height())}\",\n                (i,pat.get_height()))\n    \nax[1].set_title(\"Lenght\")\n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-16T04:51:33.615555Z","iopub.execute_input":"2022-04-16T04:51:33.615833Z","iopub.status.idle":"2022-04-16T04:51:34.003461Z","shell.execute_reply.started":"2022-04-16T04:51:33.615772Z","shell.execute_reply":"2022-04-16T04:51:34.002281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train Variables","metadata":{}},{"cell_type":"code","source":"FRAMES = SECONDS * FPS\nprint(f\"Frames Totais: {FRAMES}\")\n\nIMG_SIZE = 224\nBATCH_SIZE = 10\nEPOCHS = 10","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.618305Z","iopub.execute_input":"2022-04-12T00:51:41.619298Z","iopub.status.idle":"2022-04-12T00:51:41.628164Z","shell.execute_reply.started":"2022-04-12T00:51:41.6192Z","shell.execute_reply":"2022-04-12T00:51:41.626867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Normalize Videos","metadata":{}},{"cell_type":"code","source":"def pre_process_video(path_video:str,img_index:int,resize:tuple)->list:\n    frames = []\n    vidcapture = cv2.VideoCapture(path_video)\n    index = 0\n    j = 0\n    while(vidcapture.isOpened()):\n        rent, frame = vidcapture.read()\n        if(not rent):\n            break\n        else:\n            if(len(img_index) - 1 < j):\n                break\n            else:\n                if(index == img_index[j]):\n                    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n                    frame = cv2.resize(frame,resize)\n                    frames.append(frame)\n                    j += 1\n\n                index += 1\n\n    frames = np.array(frames)\n    frames = (frames / 255)\n    frames = frames.reshape(frames.shape[0],frames.shape[1],frames.shape[2],1)\n    return frames","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.630341Z","iopub.execute_input":"2022-04-12T00:51:41.631175Z","iopub.status.idle":"2022-04-12T00:51:41.649601Z","shell.execute_reply.started":"2022-04-12T00:51:41.63107Z","shell.execute_reply":"2022-04-12T00:51:41.648327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Getting Image Tensor","metadata":{}},{"cell_type":"code","source":"def getImgTensor(n_frames:int)->list:\n    img_idx = np.round(np.linspace(0, FRAMES, n_frames)).astype(int)\n    return [img_idx, IMG_SIZE, IMG_SIZE, 1]","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.651921Z","iopub.execute_input":"2022-04-12T00:51:41.652724Z","iopub.status.idle":"2022-04-12T00:51:41.662985Z","shell.execute_reply.started":"2022-04-12T00:51:41.65265Z","shell.execute_reply":"2022-04-12T00:51:41.661761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_tensor = getImgTensor(50)\nprint ('# img_tensor =', img_tensor)","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.66524Z","iopub.execute_input":"2022-04-12T00:51:41.666029Z","iopub.status.idle":"2022-04-12T00:51:41.679134Z","shell.execute_reply.started":"2022-04-12T00:51:41.665955Z","shell.execute_reply":"2022-04-12T00:51:41.67798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Generate Data","metadata":{}},{"cell_type":"code","source":"def getBatchData(train_metadata,batch,batch_size,img_tensor)->tuple:\n    [len_frames,width,length] = [len(img_tensor[0]),img_tensor[1], img_tensor[2]] # dimensions\n    img_idx = img_tensor[0] # array index of frames\n    \n    batch_data = np.zeros((batch_size,len_frames,width,length,1)) # batch data that will pass forward\n    batch_labels = np.zeros((batch_size,2)) # batch labels that will pass forward\n    \n    #############################################################\n    # Here is how the batch data is split by callback\n    if(((batch+1)*batch_size) <= train_metadata.shape[0]):\n        train_metadata_ = train_metadata.iloc[\n            batch*batch_size:(batch+1)*batch_size,\n            :\n        ]\n    else:\n        train_metadata_ = train_metadata.iloc[\n            batch*batch_size:,\n            :\n        ]\n    \n    #############################################################\n    video_posi = 0\n    name_list = train_metadata_['name'].to_list()\n    label_list = train_metadata_[\"label\"].to_list()\n    \n    for name,label in zip(name_list,label_list):\n        path_ = f\"../input/deepfake-detection-challenge/train_sample_videos/{name}\"\n        batch_data[video_posi] = pre_process_video(path_,\n                                          img_idx,\n                                          (width,length))\n        \n        if(label_list == \"FAKE\"):\n            batch_labels[video_posi][0] = 1\n        else:\n            batch_labels[video_posi][1] = 1\n            \n        video_posi += 1\n            \n    return batch_data, batch_labels","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.681303Z","iopub.execute_input":"2022-04-12T00:51:41.681866Z","iopub.status.idle":"2022-04-12T00:51:41.69565Z","shell.execute_reply.started":"2022-04-12T00:51:41.681681Z","shell.execute_reply":"2022-04-12T00:51:41.694534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def generator(train_metadata, batch_size, img_tensor):\n    while True:\n        if(len(train_metadata[\"name\"])%batch_size == 0):\n            num_batches = int(len(train_metadata[\"name\"])/batch_size)\n        else:\n            num_batches = int(len(train_metadata[\"name\"])/batch_size) + 1\n        \n        for batch in range(num_batches):\n            yield getBatchData(train_metadata,batch,batch_size,img_tensor)","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.697424Z","iopub.execute_input":"2022-04-12T00:51:41.697837Z","iopub.status.idle":"2022-04-12T00:51:41.716305Z","shell.execute_reply.started":"2022-04-12T00:51:41.697764Z","shell.execute_reply":"2022-04-12T00:51:41.714965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train Model","metadata":{}},{"cell_type":"code","source":"def plotModelHistory(h):\n    fig, ax = plt.subplots(1, 2, figsize=(15,4))\n    ax[0].plot(h.history['loss'])   \n    ax[0].plot(h.history['val_loss'])\n    ax[0].legend(['loss','val_loss'])\n    ax[0].set_title(\"Train loss vs Validation loss\")\n\n    ax[1].plot(h.history['categorical_accuracy'])   \n    ax[1].plot(h.history['val_categorical_accuracy'])\n    ax[1].legend(['categorical_accuracy','val_categorical_accuracy'])\n    ax[1].set_title(\"Train accuracy vs Validation accuracy\")\n    plt.show()\n\n    print(\"Max. Training Accuracy\", max(h.history['categorical_accuracy']))\n    print(\"Max. Validaiton Accuracy\", max(h.history['val_categorical_accuracy']))","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.718282Z","iopub.execute_input":"2022-04-12T00:51:41.718583Z","iopub.status.idle":"2022-04-12T00:51:41.73096Z","shell.execute_reply.started":"2022-04-12T00:51:41.718531Z","shell.execute_reply":"2022-04-12T00:51:41.729686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def make3dFilter(x):\n    return tuple([x]*3)\n\ndef make2dFilter(x):\n    return tuple([x]*2)","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.732569Z","iopub.execute_input":"2022-04-12T00:51:41.732992Z","iopub.status.idle":"2022-04-12T00:51:41.750458Z","shell.execute_reply.started":"2022-04-12T00:51:41.732935Z","shell.execute_reply":"2022-04-12T00:51:41.74923Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#write your model here\ndef defineModel(img_tensor):\n    inputShape = (len(img_tensor[0]), img_tensor[1], img_tensor[2], img_tensor[3])\n    print(inputShape)\n    model = Sequential([\n        Conv3D(16, make3dFilter(5), activation='relu', input_shape=inputShape),\n        MaxPooling3D(make3dFilter(2), padding='same'),\n        BatchNormalization(),\n\n        Conv3D(32, make3dFilter(3), activation='relu'),\n        MaxPooling3D(pool_size=(1,2,2), padding='same'),\n        BatchNormalization(),\n\n        Conv3D(64, make3dFilter(3), activation='relu'),\n        MaxPooling3D(pool_size=(1,2,2), padding='same'),\n        BatchNormalization(),\n\n        Flatten(),\n        Dense(128, activation='relu'),\n        BatchNormalization(),\n        Dropout(0.25),\n\n        Dense(64, activation='relu'),\n        BatchNormalization(),\n        Dropout(0.25),\n\n        Dense(2, activation='softmax')\n    ])\n    model.compile(optimizer=optimizers.Adam(), loss='categorical_crossentropy', metrics=['categorical_accuracy'])\n    return model\n\nmodel = defineModel(img_tensor)\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:41.752111Z","iopub.execute_input":"2022-04-12T00:51:41.75243Z","iopub.status.idle":"2022-04-12T00:51:42.868324Z","shell.execute_reply.started":"2022-04-12T00:51:41.752378Z","shell.execute_reply":"2022-04-12T00:51:42.867414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train, test = train_test_split(train_metadata,test_size=0.33,random_state=42,stratify=train_metadata[\"label\"])\n\ntrain_generator = generator(train, BATCH_SIZE, img_tensor)\nval_generator = generator(test, BATCH_SIZE, img_tensor)\n\nif (train.shape[0]%BATCH_SIZE) == 0:\n    steps_per_epoch = int(train.shape[0]/BATCH_SIZE)\nelse:\n    steps_per_epoch = (train.shape[0]//BATCH_SIZE) + 1\n\nif (test.shape[0]%BATCH_SIZE) == 0:\n    validation_steps = int(test.shape[0]/BATCH_SIZE)\nelse:\n    validation_steps = (test.shape[0]//BATCH_SIZE) + 1","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:42.872329Z","iopub.execute_input":"2022-04-12T00:51:42.872665Z","iopub.status.idle":"2022-04-12T00:51:42.886895Z","shell.execute_reply.started":"2022-04-12T00:51:42.872621Z","shell.execute_reply":"2022-04-12T00:51:42.885858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Checkpoints","metadata":{}},{"cell_type":"code","source":"import datetime\n\ncurr_dt_time = datetime.datetime.now()\n\nmodel_name = 'model_init' + '_' + str(curr_dt_time).replace(' ','').replace(':','_') + '/'\n    \nif not os.path.exists(model_name):\n    os.mkdir(model_name)\n\nfilepath = model_name + 'model-{epoch:05d}-{loss:.5f}-{categorical_accuracy:.5f}-{val_loss:.5f}-{val_categorical_accuracy:.5f}.h5'\n\ncheckpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=False, save_weights_only=False, mode='auto', period=1)\n\nLR = ReduceLROnPlateau(monitor='val_loss', factor=0.2, verbose=1, patience=4)\n\n# callbacks_list = [checkpoint, LR]\ncallbacks_list = [LR]","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:42.888025Z","iopub.execute_input":"2022-04-12T00:51:42.888368Z","iopub.status.idle":"2022-04-12T00:51:42.907207Z","shell.execute_reply.started":"2022-04-12T00:51:42.88831Z","shell.execute_reply":"2022-04-12T00:51:42.906009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Fit Model**","metadata":{}},{"cell_type":"code","source":"model.fit_generator(train_generator, steps_per_epoch=steps_per_epoch, epochs=EPOCHS, verbose=1, \n            callbacks=callbacks_list, validation_data=val_generator, \n            validation_steps=validation_steps, class_weight=None, workers=1, initial_epoch=0)","metadata":{"execution":{"iopub.status.busy":"2022-04-12T00:51:42.908437Z","iopub.execute_input":"2022-04-12T00:51:42.908831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plotModelHistory(model.history)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}