<jupyter_start><jupyter_text>Klasifikasi Gambar Gunting, Batu, Kertas dengan TensorflowDalam notebook ini kita akan mengklasifikasi gambar dengan computer vision pada API keras dengan Tensorflow versi 2.x. Gambar akan didownload menggunakan link yang disediakan kemudian akan dibagi menjadi set train dan set validation pada folder yang berbeda. Kemudian menggunakan ImageGenerator, akan diterapkan Augmentasi gambar dan terakhir hasil model dapat diuji coba dengan mengupload gambar pada notebook ini. Terdapat 726 gambar batu, 750 gambar gunting, dan 710 gambar kertas.Created by <NAME>  Persiapan Data dan Folder<jupyter_code># Import Library yang akan digunakan
import os
import zipfile
import shutil
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from google.colab import files
from keras.preprocessing import image

# Cek versi dari tensorflow
print(tf.__version__)
# Download file zip berisikan gambar
!wget --no-check-certificate \
  https://dicodingacademy.blob.core.windows.net/picodiploma/ml_pemula_academy/rockpaperscissors.zip \
  -O /tmp/rockpaperscissors.zip
# Ekstrak file Zip
local_zip = '/tmp/rockpaperscissors.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp')
zip_ref.close()
os.listdir('/tmp/rockpaperscissors')<jupyter_output><empty_output><jupyter_text>Setelah file diekstrak, terdapat 4 folder(paper, rock, scissors, dan rps-cv-images) dan file README. rps-cv-images memiliki folder yang sama dengan 3 folder lainnya. Kita akan membagi jumlah file menjadi 80% untuk train folder dan 20% untuk validation folder.<jupyter_code># Membuat Folder Training dan Validation
os.mkdir(os.path.join('/tmp/rockpaperscissors/', 'train/'))
os.mkdir(os.path.join('/tmp/rockpaperscissors/', 'validation/'))
os.mkdir(os.path.join('/tmp/rockpaperscissors/validation/', 'rock/'))
os.mkdir(os.path.join('/tmp/rockpaperscissors/validation/', 'paper/'))
os.mkdir(os.path.join('/tmp/rockpaperscissors/validation/', 'scissors/'))
# Memindahkan file gambar ke dua folder (gambar masih terduplikat)
folder_list = ['paper', 'scissors', 'rock']
for folder in folder_list:
  shutil.move('/tmp/rockpaperscissors/' + folder, '/tmp/rockpaperscissors/train')<jupyter_output><empty_output><jupyter_text>Kita akan memindahkan 20% data dari folder train ke validation folder.<jupyter_code>for folder in folder_list:
  fraction = int(len(os.listdir('/tmp/rockpaperscissors/train/' + folder + '/'))*0.2) #jumlah 20% data yang akan dipindahkan
  folder_dir = os.listdir('/tmp/rockpaperscissors/train/' + folder + '/')
  chosen_file = folder_dir[:fraction] #memilih 20% pada urutan awal
  for file in chosen_file:
    shutil.move('/tmp/rockpaperscissors/train/' + folder + '/' + file, '/tmp/rockpaperscissors/validation/'+ folder + '/' + file)<jupyter_output><empty_output><jupyter_text>shutil.move memiliki kegunaan seperti cut sehingga kita tidak perlu khawatir ada file yang terduplikat antara folder train dan validation.<jupyter_code># Jumlah file gambar di folder train setelah dipindahkan
print('Pada folder train:')
print('Gambar gunting: ' + str(len(os.listdir('/tmp/rockpaperscissors/train/scissors/'))))
print('Gambar batu: ' + str(len(os.listdir('/tmp/rockpaperscissors/train/rock/'))))
print('Gambar kertas: ' + str(len(os.listdir('/tmp/rockpaperscissors/train/paper/'))))
# Jumlah file gambar di folder validation setelah menerima gambar yang dipindahkan
print('Pada folder validation:')
print('Gambar gunting: ' + str(len(os.listdir('/tmp/rockpaperscissors/validation/scissors/'))))
print('Gambar batu: ' + str(len(os.listdir('/tmp/rockpaperscissors/validation/rock/'))))
print('Gambar kertas: ' + str(len(os.listdir('/tmp/rockpaperscissors/validation/paper/'))))<jupyter_output>Pada folder validation:
Gambar gunting: 150
Gambar batu: 145
Gambar kertas: 142<jupyter_text>Gambar telah terpisahkan pada folder yang sesuai dan siap dilakukan augmentasi gambar.  Augmentasi dari Generator Gambar<jupyter_code>folder_train = '/tmp/rockpaperscissors/train/'
train_datagen = ImageDataGenerator(
      rescale=1./255,
      rotation_range=40,
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True,
      fill_mode='nearest')

folder_validation = '/tmp/rockpaperscissors/validation/'
validation_datagen = ImageDataGenerator(
      rescale = 1./255,
      rotation_range=40,
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True,
      fill_mode='nearest')

train_generator = train_datagen.flow_from_directory(
        folder_train, 
        target_size=(150, 150),  
        batch_size=20,
        class_mode='categorical')

validation_generator = train_datagen.flow_from_directory(
        folder_validation, 
        target_size=(150, 150),  
        batch_size=20,
        class_mode='categorical')<jupyter_output>Found 1751 images belonging to 3 classes.
Found 437 images belonging to 3 classes.<jupyter_text>kita menggunakan class_mode categorical karena terdapat 3 jenis label.  Model Sequential<jupyter_code>model = tf.keras.models.Sequential([

tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(3, activation='softmax') # menggunakan 3 neuron di akhir dengan fungsi aktivasi softmax sebagai probabilitas
])
model.summary()

model.compile(optimizer=RMSprop(lr=0.001), loss='categorical_crossentropy', metrics=['acc'])<jupyter_output>Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 148, 148, 16)      448       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 74, 74, 16)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 72, 72, 32)        4640      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 36, 36, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 34, 34, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 17, 17, 64)        0         
________________________________________________________[...]<jupyter_text>Kita menggunakan optimizer berupa RMSprop dan loss categorical_crossentropy. Proses Training<jupyter_code>model.fit(
      train_generator,
      steps_per_epoch=20, 
      epochs=25,
      validation_data=validation_generator, 
      validation_steps=5,  
      verbose=1)<jupyter_output>Epoch 1/25
20/20 [==============================] - 12s 614ms/step - loss: 1.4496 - acc: 0.3575 - val_loss: 1.1081 - val_acc: 0.2800
Epoch 2/25
20/20 [==============================] - 12s 606ms/step - loss: 1.1109 - acc: 0.3775 - val_loss: 1.0922 - val_acc: 0.3100
Epoch 3/25
20/20 [==============================] - 12s 614ms/step - loss: 1.1537 - acc: 0.3625 - val_loss: 1.0889 - val_acc: 0.3600
Epoch 4/25
20/20 [==============================] - 12s 623ms/step - loss: 1.0641 - acc: 0.4450 - val_loss: 1.0726 - val_acc: 0.4330
Epoch 5/25
20/20 [==============================] - 12s 595ms/step - loss: 1.0321 - acc: 0.5499 - val_loss: 0.8510 - val_acc: 0.6900
Epoch 6/25
20/20 [==============================] - 12s 604ms/step - loss: 0.9585 - acc: 0.5775 - val_loss: 0.8107 - val_acc: 0.7500
Epoch 7/25
20/20 [==============================] - 12s 604ms/step - loss: 0.7617 - acc: 0.6850 - val_loss: 0.5760 - val_acc: 0.7500
Epoch 8/25
20/20 [==============================] - 12s 619ms/step - [...]<jupyter_text>Setiap kali proses training dilakukan akan menghasilkan nilai akurasi yang sedikit berbeda, didapatkan berkisar diantara 90%.<jupyter_code>%matplotlib inline
 
uploaded = files.upload()
 
for fn in uploaded.keys():
 
  # predicting images
  path = fn
  img = image.load_img(path, target_size=(150,150))
  imgplot = plt.imshow(img)
  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)
 
  images = np.vstack([x])
  classes = model.predict(images, batch_size=10)
  classes = classes.tolist()
  
if classes[0][0] == 1:
  print('kertas')
elif classes[0][2] == 1:
  print('gunting')
else:
  print('batu')
# !rm -rf '/tmp/rockpaperscissors'
#uncomment sebelum restart runtime<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14637391882900866, 'fraction_numerical': 0.051452650255045466, 'mean_word_length': 4.871744791666667, 'pattern_counts': {'":': 0, '<': 30, '<?xml version=': 0, '>': 30, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '227653', 'license': 'BSD-4-Clause-UC', 'n_tokens_mistral': 3468, 'n_tokens_neox': 3040, 'n_words': 668, 'path': 'rockpaperscissors.ipynb', 'repo_name': 'reyhanalemmario/ML_project', 'size': '9028'}