# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     name: python3
# ---

# + [markdown] id="u6kTqqtESNnc"
# # **Kegiatan Modul 3**
#
# **Poin penilaian :**
#
# * Tingkat kesesuaian code
# * Tingkat kesesuaian output
# * Kesesuaian step preprocessing dan pemodelan
# * Kesesuaian jawaban dengan konten materi modul
# * Pemahaman materi tentang Dropout dan BatchNormalization
# * Dapat menerapkan semua konten materi dalam modul-modul sebelumnya
# * Kerapian kode program
# * Tidak ada error
# * Nilai Maksimal 100 poin

# + [markdown] id="-muSoJjnFt8y"
# ## **Introduction**
#
# Dataset yang akan anda gunakan dalam kegiatan ini adalah dataset [Rock Paper Scissors](https://www.kaggle.com/drgfreeman/rockpaperscissors).  Demi mempermudah anda dalam mengerjakan modul ini maka akan sangat disarankan untuk menggunakan [google colab](https://colab.research.google.com/). Anda dapat menggunakan google colab untuk mendownload langsung dataset dari kaggle dan menyimpannya dalam google drive anda. Untuk kenyamanan dan ruang kerja yang besar akan lebih baik anda menggunakan email kampus untuk menyimpan dataset yang anda gunakan. Perhatikan langkah berikut untuk melakukan setting environment anda.

# + [markdown] id="fLoYIWSbKgko"
# ## **Get Your Dataset**
#
# * Mount drive terlebih dahulu
#
# * Untuk dapat mengakses dataset ini anda diharuskan memiliki akun kaggle. Jika belum memilikinya buat satu akun pribadi.
#
# * Download kaggle API.json kemudian upload dalam google drive anda.
#
# * Ubah lokasi direktori kerja anda ke direktori dimana anda menyimpan kaggle.json
#
# * Buka laman dataset kemudian Copy API Command.
#
# * Jalankan perintah untuk mendownload dataset dari kaggle menggunakan google colab.
#
# * Untuk selanjutnya pahami code dibawah dengan baik.
#
# * Gunakan tutorial berikut untuk lebih jelasnya : [Fetch Kaggle Dataset into Google Colab](https://medium.com/analytics-vidhya/how-to-fetch-kaggle-datasets-into-google-colab-ea682569851a)
#

# + id="_iP7_H-5ubtG" outputId="2ce8946d-f36f-44a0-e671-f2b84dce72e5" colab={"base_uri": "https://localhost:8080/"}
from google.colab import drive
drive.mount('/content/drive')

# + id="fWkAcnefSPKI"
# Define kaggle json path
# Sesuaikan dengan path anda
import os
os.environ['KAGGLE_CONFIG_DIR'] = "/content/drive/My Drive/modul3"

# + id="IPUJ-XM5S4Th" outputId="f6f9d956-d948-4613-ec83-a47ab4bf997a" colab={"base_uri": "https://localhost:8080/"}
# Ubah lokasi direktori kerja
# Sesuaikan dengan path anda
# %cd /content/drive/My Drive/modul3

# + [markdown] id="g8tGIV-bTmOE"
# Cek apakah api sudah terbaca oleh sistem

# + id="69Bbmd-TCGhh" outputId="49507b7b-9c1a-47b8-f40a-910621a0b5ae" colab={"base_uri": "https://localhost:8080/"}
# Cek apakah api sudah terbaca oleh sistem
# !ls  

# + [markdown] id="7wGGZC8vTX0A"
# * Paste API Command dari kaggle dataset yang telah anda copy sebelumnya dan tambahkan tanda seru didepannya.
# * Pastikan anda menggunakan akun google kampus untuk mendapatkan storage penyimpanan unlimited.
# * Lebih disarankan untuk menggunakan google colab karena proses download data lebih cepat dan stabil daripada download manual dan menggunakan jupyter notebook.

# + id="emSTR53KTGW9" outputId="c0ab10c2-d2c8-4701-8a30-cf47d98a32e6" colab={"base_uri": "https://localhost:8080/"}
# !kaggle datasets download -d drgfreeman/rockpaperscissors

# + id="JcpagHVWbdDY" outputId="d7defaae-9812-4921-9e88-fbb3bd157a8a" colab={"base_uri": "https://localhost:8080/"}
# Cek isi direktori kerja dan memastikan dataset telah berhasil didownload.
# !ls

# + id="3HDyNsR3bam4"
# Ekstrak file dataset dan hapus file zip dataset agar tidak memakan banyak tempat.
# !unzip \*.zip &> /dev/null && rm *.zip

# + id="Vgw_k1zihmkK" outputId="0bdfee0e-1b64-4264-e020-2a6db5dc95f8" colab={"base_uri": "https://localhost:8080/"}
# Cek isi direktori kerja untuk memastikan dataset telah berhasil diekstrak.
# !ls

# + [markdown] id="AHa7xcuP5vsU"
# ## **Prepare Your Data**

# + [markdown] id="dPVmxstVUvyL"
# ### **Soal 1** 
# poin 5
#
# ---
# Terlihat disana bahwa ada file dan folder baru yaitu : `paper, rock, scissors, README_rpc-cv-images.txt`. Untuk tujuan mempermudah aksesabilitas dataset maka akan lebih baik semua folder dataset yang merepresentasikan kelasnya tersebut disimpan dalam satu folder bernama `dataset`. Tugas anda adalah membuat folder baru dan memindahkan semua folder tersebut folder `dataset`.
#
# Selanjutnya, anda akan ditugaskan untuk melakukan splitting dataset menjadi 3 bagian yaitu `train, test, val` oleh sebab itu anda perlu tempat khusus untuk menyimpan ketiga folder tersebut agar penyimpanan anda lebih rapi. Buatlah sebuah folder baru bernama `rockpaperscissors` dan masukkan folder `dataset` kedalamnya. Nanti kita juga akan menyimpan folder `train, test, val` kedalam folder `rockpaperscissors`.
#
# *Ingat google colab juga menerima command berbasis linux.*

# + id="d0m6kXUQR1US"
# mkdir dataset

# + id="rXprYKJ00J5y"
# mv "/content/drive/My Drive/modul3/paper/" "/content/drive/My Drive/modul3/dataset/"

# + id="GeU4rL-x5G6O"
# mv "/content/drive/My Drive/modul3/rock/" "/content/drive/My Drive/modul3/dataset/"

# + id="n4AlxxOw5Juc"
# mv "/content/drive/My Drive/modul3/scissors/" "/content/drive/My Drive/modul3/dataset/"

# + id="6Re0vwqYUPGD"
# mkdir rockpaperscissors

# + id="btUF38On5brX"
# mv "/content/drive/My Drive/modul3/dataset/" "/content/drive/My Drive/modul3/rockpaperscissors/"

# + [markdown] id="FownsNlA1ws5"
# Bila anda melakukannya dengan benar, maka ketika anda menjalankan perintah dibawah anda akan menemui output sbb :
#
# **Output perintah `!ls`**
# ```
#  bbc_document_classification	  kaggle.json
#  big_mart_sales_forcasting	  model.png
#  Bird_Type			  monkey_labels.txt
#  BRAIN_TUMOR			  Monkey_Species
#  cats_and_dogs_filtered		  PetImages
#  dataset			  README_rpc-cv-images.txt
#  Diabetics_Retinopathy		  Rice_Disease
#  DS_CHEAT_SHEET			  rockpaperscissors
#  imdb_indonesian_movies_2.csv	  rps-cv-images
# 'Kaggle Download Dataset.ipynb'
# ```
#
# **Output perintah `!ls rockpaperscissors`**
# ```
#  dataset
# ```
# **Output perintah `!ls rockpaperscissors`**
# ```
#  paper  rock  scissors
# ```
#
#

# + id="cZuq9u-j59_4" outputId="a1174f35-07ae-4024-d8de-a17ba3e00249" colab={"base_uri": "https://localhost:8080/"}
# !ls

# + id="hBQZazI16Kij" outputId="34848c81-d2c9-4bdc-d416-07d2ebc3c3aa" colab={"base_uri": "https://localhost:8080/"}
# !ls rockpaperscissors

# + id="Mq3lR3oh6QhZ" outputId="0353cb8b-3639-4451-c9d8-437ba517f142" colab={"base_uri": "https://localhost:8080/"}
# !ls rockpaperscissors/dataset

# + id="F-JngY7b0lmJ"
base_dir="/content/drive/My Drive/modul3/rockpaperscissors"
data_dir="/content/drive/My Drive/modul3/rockpaperscissors/dataset"

# + [markdown] id="6Y-OMhb1crH6"
# ### **Soal 2**  *Opsional*
#
# poin 15
#
# ---
# Sebelum dataset siap untuk dilakukan proses training anda perlu melakukan splitting dataset menjadi 3 bagian yaitu `train, test, val`. Data `train dan val` akan digunakan ketika anda melakukan training model. Dan data `test` akan anda gunakan ketika anda melakukan prediksi unseen data menggunakan model yang telah anda latih.
#
# * nilai full hanya untuk praktikan yang mampu menerapkan 2 baris code untuk splitting dataset

# + id="ICEtTq1U-cE0" outputId="e8ef1790-63d8-48a0-d19a-b6a891f5c50c" colab={"base_uri": "https://localhost:8080/"}
pip install split-folders

# + id="E9_rvimipTEP" outputId="1d1255fe-a01f-429d-879e-647b34214b7c" colab={"base_uri": "https://localhost:8080/"}
import splitfolders
splitfolders.ratio(data_dir, output=base_dir, seed=1337, ratio=(.7, .15, .15), group_prefix=None) # default values

# + [markdown] id="x_bZuRvRsd3I"
# Splitting dataset berhasil apabila dijalankan perintah `ls rockpaperscissors` maka akan menampilkan output seperti dibawah ini:
#
# ```
# # dataset/  test/  train/  val/
# ```
#
#

# + id="XBlRnCI_AZY4" outputId="ca527708-9bfc-47d6-8c1a-346246857ca7" colab={"base_uri": "https://localhost:8080/"}
# ls rockpaperscissors

# + [markdown] id="bGJNvpjE06bH"
# ## **Data Preprocessing**
#
# Kita anggap dataset yang kita miliki merupakan dataset yang telah bersih dan siap digunakan untuk proses training model. Namun agar data yang kita miliki dapat diproses oleh model maka kita perlu melakukan sedikit pengolahan data. Kita perlu melakukan load dataset yang tersimpan dalam folder-folder kelas menggunakan generator dan melakukan sedikit proses augmentasi sederhana. 
#
#
# **NOTE :** Penjelasan augmentasi secara detail akan dibahas pada modul selanjutnya. Disini kita akan mengunakan augmentasi sederhana saja seperti resize, flip dan rotation.

# + [markdown] id="LE3_N5ZA3CkM"
# ### **Soal 3**
# poin 20
#
# ---
#
# Lakukan proses agumentasi sederhana dan setting dataset menggunakan generator dengan ketentuan **WAJIB** menyertakan proses berikut :
#
# * Resize
# * Rescaling
# * Color Mode
# * Shuffle
# * Class Mode
#
# Terapkan semua proses diatas pada data `train, test dan validation`.
#

# + id="mThUU7Ai6ytp"
# Definisikan path untuk data train test dan validation
# sesuaikan dengan path anda

train_path = os.path.join(base_dir,'train')
test_path  = os.path.join(base_dir,'test')
val_path   = os.path.join(base_dir,'val')

# + id="0r61d25Zoh_Z" outputId="b946a9c9-8618-4318-e03e-5eae674546b3" colab={"base_uri": "https://localhost:8080/"}
from keras.preprocessing.image import ImageDataGenerator
from sklearn.utils import shuffle
Batch_size=32
augmen_gen = ImageDataGenerator(rescale=1. / 255,
                            rotation_range=40,
                            width_shift_range=0.2,
                            height_shift_range=0.2,
                            zoom_range=0.2,
                            horizontal_flip=True,
                            fill_mode='nearest')

train_gen = augmen_gen.flow_from_directory(
    train_path,
    class_mode = 'categorical',
    shuffle=True,
    target_size = (224,224),
    batch_size=Batch_size,
    color_mode ='rgb'
)

val_gen = augmen_gen.flow_from_directory(
    val_path,
    class_mode = 'categorical',
    shuffle=True,
    target_size = (224,224),
    batch_size=Batch_size,
    color_mode ='rgb'
)

test_gen = augmen_gen.flow_from_directory(
    test_path,
    class_mode = 'categorical',
    shuffle=False,
    target_size = (224,224),
    batch_size=Batch_size,
    color_mode ='rgb',
)


# + [markdown] id="kqIE1t7R0zrA"
# ## **Definisikan Model CNN**
#
# Sangat disarankan menggunakan GPU sebagai akselerator untuk mempercepat proses training. Oleh sebab itu akan sangat lebih baik bila menggunakan google colab dimana anda dapat meminjam GPU dari google secara gratis.

# + [markdown] id="DmMY0uROUFqP"
# ### **Soal 4**
# poin 60
#
# ---
#
# Definisikan model CNN anda sebaik mungkin, model dan evaluasi yang anda bangun **WAJIB** memenuhi kriteria berikut:
#
# * Menerapkan proses Convolution 
# * Menerapkan proses Pooling
# * Menerapkan Dropout
# * Menerpakan BatchNormalization
# * Evaluasi model menggunakan grafik loss dan accuracy
# * Evaluasi menggunakan classification report
# * Evaluasi menggunakan confusion matrix
#
# Bila anda telah melaksanakan semua item-item wajib diatas maka anda bisa mendapatkan penilaian yang sesuai dengan kriteria penilaian sbb: ***Bila tidak menerapkan salah satu dari item wajib maka penilaian di soal ini dianggap gugur***
#
# * Akurasi < 50% Nilai Max 20
# * Akurasi < 80% Nilai Max 30
# * Akurasi >= 80% Nilai Max 40
#
# Opsional untuk mendapatkan nilai tambah :
# * Menggunakan Callbacks  **Poin tambahan 5 poin**
# * Menggunakan Learning Rate  **Poin tambahan 5 poin**
# * Lakukan prediksi dengan data test, pastikan model anda dapat memprediksi unseen data dengan kelas yang benar ***dengan ketentuan dapat menampilkan gambar dan label prediksi dan probability score dari gambar yang diprediksikan***. **Poin tambahan 15 poin**
# * **Nilai tambahan 15 poin** apabila lama proses training model tidak lebih dari 15 menit dengan akurasi >90%

# + id="PWp_YTCzIp5R"
# IMPORT SEMUA PAKET YANG ANDA PERLUKAN UNTUK MENDEFINISIKAN MODEL DISINI
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import InputLayer, Dense, Conv2D, MaxPool2D, Flatten, BatchNormalization, Dropout
from tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
from tensorflow.keras.optimizers import Adam
import time

# + id="Mjl4kwq1XKJE"
# DEFINISIKAN MODEL ANDA DISINI
# Feature Extraction Layer
model = Sequential()

model.add(InputLayer(input_shape=[224,224,3]))
model.add(Conv2D(filters=32, kernel_size=3, strides=1, padding='same', activation='relu'))
model.add(MaxPool2D(pool_size=2, padding='same'))
model.add(Conv2D(filters=64, kernel_size=3, strides=1, padding='same', activation='relu'))
model.add(MaxPool2D(pool_size=2, padding='same'))
model.add(Conv2D(filters=128, kernel_size=3, strides=1, padding='same', activation='relu'))
model.add(MaxPool2D(pool_size=2, padding='same'))
model.add(Dropout(0.25))
model.add(BatchNormalization())
model.add(Flatten())

# Fully Connected Layer
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(3, activation='softmax'))

# + id="dTQC-d65tO0e" outputId="f1a21043-274c-4e8e-9846-e5b73cd66c8d" colab={"base_uri": "https://localhost:8080/"}
# TULIS CODE UNTUK MENAMPILKAN SUMMARY DARI ARSITEKTUR MODEL ANDA DISINI
# Print model summary
print(model.summary())

# + id="lk-8KBYctRLn"
# TULIS CODE CALLBACKS ANDA DISINI
best_model_path = 'best_model.h5'
checkpoint_callback = ModelCheckpoint(best_model_path,
                                     monitor='val_accuracy',
                                     save_best_only=True,
                                     verbose=1)
reduce_callback = ReduceLROnPlateau(monitor='val_accuracy', patience=3, factor=0.5, min_lr=0.000003, verbose=1)
callbacks_list = [checkpoint_callback, reduce_callback]

# early_stop = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=5)

# + id="8tPPBmcDtYwi"
# TULIS CODE UNTUK DEFINISI LEARNING RATE DISINI 
learning_rate=0.00001

# + id="2NHvlRG7tpgb"
# TULIS CODE UNTUK TRAINING DISINI
model.compile(loss='categorical_crossentropy',
             optimizer=Adam(lr=learning_rate),
             metrics='accuracy')


# + id="OIHye4dUNq5J" outputId="80e36b0f-eaea-4df9-9ac1-43c77f90184b" colab={"base_uri": "https://localhost:8080/"}
# TULIS CODE UNTUK MENCETAK LAMA TRAINING TIME DISINI
start = time.time()
H = model.fit_generator(train_gen, epochs=25,validation_data=val_gen, validation_steps = 4, verbose=1, callbacks=[callbacks_list])

End = time.time()
print ("training time: ", End-start,"s")  # the time would be round to 3 decimal in seconds

# + [markdown] id="qk59kdzr5AMT"
# # **Evaluate**

# + id="4K8XoKgx5do6"
# IMPORT SEMUA PAKET YANG ANDA PERLUKAN UNTUK MENGEVALUASI MODEL DISINI
# %matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from keras.models import load_model
from sklearn.metrics import classification_report, confusion_matrix

# + id="GVaP9dbG4wc9" outputId="e3722da2-eafa-4535-a35d-9822031d5304" colab={"base_uri": "https://localhost:8080/"}
# TULIS CODE UNTUK EVALUASI MODEL DISINI

model.load_weights(best_model_path)

ypred = model.predict(test_gen)
predictions = np.argmax(ypred, axis = 1)
# labels = (pred > 0.5).astype(np.int)
print(classification_report(test_gen.classes,predictions))

# + id="XjOQkFIUR1oZ" outputId="f19d10b8-ccc0-4290-a82e-cac23137687b" colab={"base_uri": "https://localhost:8080/", "height": 382}
import itertools
def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')

    print(cm)

    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, format(cm[i, j], fmt),
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

cnf_matrix=confusion_matrix(test_gen.classes,predictions)
plot_confusion_matrix(cnf_matrix, classes=test_gen.class_indices)

# + id="d5ZkO3yN2c08" outputId="0cbfd10d-1dca-4035-9676-c2ced8f913d8" colab={"base_uri": "https://localhost:8080/", "height": 581}
# TULIS CODE UNTUK PLOT EVALUASI MODEL DISINI
plt.style.use("ggplot")

plt.plot(np.arange(0, 25), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, 25), H.history["val_loss"], label="val_loss")
plt.title("Loss Plot")
plt.xlabel("Epoch #")
plt.ylabel("Loss")
plt.show()

plt.plot(np.arange(0, 25), H.history["accuracy"], label="train_acc")
plt.plot(np.arange(0, 25), H.history["val_accuracy"], label="val_acc")
plt.title("Accuracy Plot")
plt.xlabel("Epoch #")
plt.ylabel("Accuracy")
plt.legend()
plt.show()

# + id="9FZBVsIH46Bb" outputId="ca7dfcae-f2d2-4be6-9ec2-b14317676794" colab={"base_uri": "https://localhost:8080/", "height": 299}
# TULIS CODE UNTUK PREDIKSI DATA TEST DISINI

import PIL

def predictModel(image_path):
    # Load and resize the image using PIL.
    img = PIL.Image.open(image_path)
    img_resized = img.resize((224, 224), PIL.Image.LANCZOS)

    # Plot the image.
    plt.imshow(img_resized)

    # Convert the PIL image to a numpy-array with the proper shape.
    img_array = np.expand_dims(np.array(img_resized), axis=0)

    pred_coba = model.predict_classes(img_array)
    ahoy = model.predict(img_array)
    
    labels = np.argmax(ahoy, axis=1)

    plt.title(f"Pred : {ahoy}\nLabels : {labels}")

predictModel("/content/drive/My Drive/modul3/rockpaperscissors/test/rock/3wrX8EawcOolzrAY.png")

# num_pred=10
# for i in range (num_pred):
#   a=np.random(os.walk(test_path))
#   predictModel(a)

# + id="c8DQT_zyX8uf" outputId="80779525-d2d8-4083-ffb5-e7a275fbbd9b" colab={"base_uri": "https://localhost:8080/", "height": 265}
import random
img = random.choice(test_path)
plt.plot(img)
plt.show()

StarcoderdataJupyterScriptsDedupFiltered