Tutorial

Rekomendasi film Indonesia dengan kecerdasan artifisial

14 Mins read

Menonton film mungkin menjadi suatu hobi bagi kebanyakan dari kita. Terlepas dari selera genrenya yang berbeda-beda, tetap saja aktivitas ini membawa kegembiraan tersendiri bagi penggemarnya. Agar menonton film semakin menyenangkan, penonton acap kali mencari rekomendasi film yang sesuai seleranya dari berbagai sumber. Kemudian jika suatu film yang ditonton dinilai bagus, penonton akan mencari-cari dan bertanya-tanya adakah film lain yang serupa, baik dalam hal ide cerita, alur, pemeran, maupun latar belakangnya. Nah, bagaimanakah suatu teknologi dapat membantu para penggemar film untuk menemukan rekomendasi tayangan yang sesuai?

Kabar baiknya adalah teknologi artificial intelligence (AI) dapat diterapkan untuk menyelesaikan persoalan sederhana tersebut menggunakan pendekatan sistem rekomendasi. Faktanya, pendekatan inilah yang diaplikasikan oleh berbagai perusahaan di industri film, seperti YouTube, Netflix, dan Hulu dalam merekomendasikan suatu tayangan kepada user / pelanggannya.

Dalam artikel kali ini saya mencoba untuk membuat tutorial model sederahna dari jaringan saraf tiruan (JST) (dalam artikel ini kata tiruan/buatan (artificial) selanjutnya akan disebut sebagai artifisial karena mengacu pada istilah yang digunakan dalam peluncuran strategi nasional kecerdasan artifisial) sebagai salah satu contoh penerapan kecerdasan artifisial dalam menentukan rekomendasi film. Dalam kasus kali ini, saya menggunakan film Indonesia sebagai objeknya. Mari simak penjelasan selengkapnya.

Dalam menentukan rekomendasi (film) dengan menggunakan kecerdasan artifisial, terdapat dua pendekatan yang dapat diterapkan. Keduanya ialah collaborative filtering dan content-based filtering. Collaborative filtering adalah sistem rekomendasi yang bekerja dengan cara mengeksplorasi kebiasaan pelanggan (user behavior). Sistem ini akan melihat bagaimana setiap pelanggan bereaksi terhadap suatu produk (dapat berupa rating atau pun resensi dari produk tersebut). Dengan preferensi tersebut, pelanggan lain yang memiliki preferensi yang sama akan dipandu menuju produk serupa. Sementara itu, content-based filtering melakukan perekomendasian dengan cara melihat profil atau atribut dari suatu produk. Selanjutnya, melalui data tersebut dicari kesamaan karakteristiknya pada produk lain. Oleh karena itu, ketika pelanggan menyukai suatu produk, ia akan mendapat rekomendasi produk lain yang mempunyai kemiripan fitur. Sebagai catatan, kedua pendekatan collaborative filtering dan content-based filtering ini disarankan untuk diterapkan secara bersamaan supaya sistem rekomendasi menjadi lebih akurat. Sumber bacaan lebih lanjut silakan pelajari di tautan ini.

Pada artikel kali ini, pembahasan saya fokuskan pada sistem rekomendasi content-based filtering. Sistem rekomendasi ini saya gunakan untuk menemukan rekomendasi film Indonesia dengan mengacu pada suatu film Indonesia lain yang memiliki atribut/karakteristik tertentu.Metode yang digunakan ialah pemrosesan bahasa alami / natural language processing (NLP) dan juga model autoencoders (AEs) untuk mendapatkan representasi tersembunyi (latent representation). Selanjutnya kita akan hitung kesamaan dari fitur-fitur yang ada dari film Indonesia tersebut untuk mendapatkan rekomendasi sebuah film Indonesia yang lain.

Seperti pada tutorial sebelum-sebelumnya, kali ini pun saya menerapkan model kecerdasan artifisial dengan menggunakan bahasa pemrograman Python dan librari PyTorch untuk pemodelan model deep learning. Sebagai panduan dalam tutorial ini, kode lengkap dari penerapan rekomendasi film Indonesia dapat diakses dan diunduh pada tautan ini.

Import librari yang diperlukan

# Import librari yang dibutuhkan
import pandas as pd
pd.set_option('display.max_colwidth', -1)
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
import torch.optim as optim
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# Import librari sastrawi untuk pemrosesan NLP Bahasa Indonesia
!pip install sastrawi
!pip install swifter
from Sastrawi.StopWordRemover.StopWordRemoverFactory import StopWordRemoverFactory
from Sastrawi.Stemmer.StemmerFactory import StemmerFactory
import swifter

Beberapa librari yang diperlukan pada tutorial kali ini yakni sebagai berikut:

  • Pandas untuk memuat dataset dan penggunaan DataFrame untuk memudahkan penyimpanan data;
  • NumPy untuk memudahkan pembuatan array dan indexing array;
  • Scikit-klearn untuk membantu mengekstrak fitur dan menghitung kesamaan dari suatu vektor;
  • Sastrawi dan Swifter untuk memudahkan prapemrosesan teks; dan
  • PyTorch untuk membuat model jaringan saraf tiruan / deep learning.
# Periksa versi dari PyTorch dan juga periksa apakah kita dapat memanfaatkan GPU 
print("Torch's version: " + torch.__version__)
print(torch.cuda.is_available())

Untuk melihat versi dari PyTorch yang telah ter-install, kita dapat menjalankan baris di atas. Selain itu, periksa juga apakah environment kita sudah mendukung penggunaan GPU atau tidak. Sebagai informasi, layanan Google Colaboratory memungkinkan kita untuk menggunakan PyTorch dengan dukungan GPU.

Memuat dan Eksplorasi Dataset Film Indonesia

Dataset yang akan digunakan dalam tutorial ini ialah sinopsis film Indonesia dari IMDB dari Kaggle yang disediakan dalam tautan ini. Dataset ini terdiri dari 1.005 sampel dengan 3 atribut utama, yakni judul film, genre, dan sinopsis singkat. Dari ketiga atribut utama tersebut, kita hanya akan menggunakan dua atribut, yaitu judul dan sinopsis, untuk mendapatkan rekomendasi film.

# Memuat data dari IMDB Film Indonesia yang saya simpan di google drive 
# Tautan untuk mendapatkan data: https://www.kaggle.com/antoniuscs/imdb-synopsis-indonesian-movies oleh Mas Antonius Christiyanto
data = pd.read_csv('/content/drive/My Drive/Konsep.AI/NLP/data/datasets_88471_203593_imdb_indonesian_movies_2.csv')

# Mengecek dimensi dari data yang sudah kita muat
data.shape 

# Lihat beberapa data film yang tersedia
data.head(5)

Dataset film Indonesia dapat kita muat secara mudah dengan menggunakan metode pd.read_csv() dengan lokasi dari file *.csv sebagai masukannya. Dengan memanggil metode tersebut, tipe data yang kita muat akan dikonversi secara otomatis menjadi DataFrame. Kita dapat cek dimensi dari data yang sudah kita muat dengan menggunakan kode sederahana data.shape. Selain itu, kita dapat pula melihat beberapa data yang tersedia dengan kode data.head(5), dan 5 sebagai masukan atas jumlah data yang ingin ditampilkan. Dari kode di atas, kita dapat melihat lima sampel film dengan kolom judul_film, ringkasan_sinopsis dan genre.

Sampel data untuk dijadikan sebagai data pelatihan model kecerdasan artifisial untuk rekomendasi film Indonesia.
Sampel data untuk dijadikan sebagai data pelatihan model kecerdasan artifisial untuk rekomendasi film Indonesia.

Lebih lanjut, dengan menggunakan fitur DataFrame dari Pandas, kita dapat dengan mudah menghitung jumlah sampel berdasarkan genre dengan kode .groupby(.).count().

# Periksa distribusi genre film yang tersedia
data.groupby('genre').count()

Dari tabel tersebut di atas, kita dapat memperoleh gambaran persebaran sampel yang tersedia berdasarkan lima genre yang tersedia. Dari angka tersebut, kita dapat mengambil kesimpulan bahwa distribusi sampel dapat dikatakan rata dari masing-masing genre. Dengan DataFrame, kita juga dapat dengan mudah mencari film berdasarkan genre tertentu, yaitu cukup menggunakan indexing dengan menyebutkan nama kolom dan kondisi tertentu sebagai berikut.

# Cek data dengan genre Romantis
data[data['genre'] == 'Romantis'].head(10)

Prapemrosesan untuk Natural Language Processing (NLP)

Untuk memproses suatu teks, terdapat beberapa langkah yang harus dipenuhi sebagai langkah-langkah prapemrosesan untuk mendapatkan teks yang ‘bersih’. Beberapa langkah prapemrosesan tersebut ialah sebagai berikut:

1. Menggabungkan fitur judul_film dan ringkasan_sinopsis

# 1. Tambahkan judul_film ke dalam ringkasan_sinopsis_bersih
data['ringkasan_sinopsis_bersih'] = data['judul_film'] + " " + data['ringkasan_sinopsis_bersih']
data.head(5)

Sebagai data masukan, kita akan menggabungkan fitur dari judul_film dan ringkasan_sinopsis menjadi kolom baru pada DataFrame dengan nama ringkasan_sinopsis_bersih.

2. Menghapus karakter selain alfabet / simbol

# 2. Menghapus karakter-karakter selain alfabet dan simpan ke dalam kolom terpisah pada DataFrame
data['ringkasan_sinopsis_bersih'] = data['ringkasan_sinopsis'].str.replace("[^a-zA-Z#]", " ")
data.head(5)

Kode di atas befungsi untuk menghapus simbol-simbol yang tidak kita inginkan untuk dijadikan sebagai data masukan dengan menggunakan fungsi regular expression. Tanda baca, seperti koma, titik, dll, akan terhapus secara otomatis. Selain itu, untuk keperluan saat ini, angka juga akan kita hapus karena cenderung kurang memiliki arti atau hanya akan berkontribusi sebagai noise pada pemodelan teks.

3. Mengubah huruf besar menjadi huruf kecil (case folding)

# 3. Mengubah semua huruf ke dalam huruf kecil (Case folding)
data['ringkasan_sinopsis_bersih'] = data['ringkasan_sinopsis_bersih'].apply(lambda kalimat: kalimat.lower())
data.head(5)

Untuk mendapatkan fitur yang sama — terlepas dari penampilkan teks — kita akan mengubah penulisan kapitalisasi semua teks menjadi huruf kecil dengan fungsi case folding .lower().

4. Menghapus stopword & stemming

# 4. Stopword removal dan Stemming (CATATAN: Proses ini memakan banyak waktu sebanding dengan jumlah data yang kita punyai)
# Instansiasi 
swfactory = StopWordRemoverFactory()
stfactory = StemmerFactory()

# Tampilkan stopword
print(swfactory.get_stop_words()[:10])

# Buat stopword remover dan stemmer
swremover = swfactory.create_stop_word_remover()
stemmer = stfactory.create_stemmer()

# Stopword removal
data['ringkasan_sinopsis_bersih'] = data['ringkasan_sinopsis_bersih'].apply(lambda kalimat: swremover.remove(kalimat))
# Stemming
data['ringkasan_sinopsis_bersih'] = data['ringkasan_sinopsis_bersih'].swifter.apply(lambda kalimat: stemmer.stem(kalimat))
data.head(5)

Tahapan berikutnya ialah penghapusan stopword (kata umum) yang sering digunakan pada suatu kalimat, tetapi tidak mempunyai makna tertentu, misalnya ['yang', 'untuk', 'pada', ... ]. Selain itu, kita juga akan melakukan stemming yang berarti pengembalian semua kata yang mengandung imbuhan ke dalam bentuk kata dasarnya, seperti "melihat" menjadi "lihat", "mengerjakan" serta "pekerjaan" menjadi "kerja", dsb. Untuk kedua proses ini, kita gunakan librari Sastrawi yang sering digunakan untuk memproses teks bahasa Indonesia. Selain itu, Swifter kita gunakan untuk mempercepat pemrosesan jalannya proses stemming tersebut.

Ekstraksi Fitur Term Frequency-Inverse Document Frequency (TF-IDF)

# Vektorisasi dokumen dengan TF-IDF
vektorisasi = TfidfVectorizer(max_features=1024, ngram_range=(1,3), max_df=0.7, smooth_idf=True, use_idf=True, sublinear_tf=True)

# Hitung fitur
X = vektorisasi.fit_transform(data['ringkasan_sinopsis_bersih']).toarray()

Dari teks yang sudah bersih tersebut, kita akan melakukan ekstraksi fitur dari judul film dan ringkasan sinopsis. Dalam hal ini, term frequency-inverse document frequency (TF-IDF) akan kita gunakan sebagai fitur dari teks yang kita punya. Ringkasnya, TF-IDF merupakan teknik ekstraksi fitur yang melakukan perhitungan terhadap seberapa pentingnya suatu kata dalam sebuah dokumen dengan cara melihat berapa banyaknya kata tersebut muncul dan juga berapa banyakny dokumen yang memuat kata tersebut dalam suatu koleksi dokumen. Fungsi TF-IDF sudah disediakan olek Scikit-learn dengan nama kelas TfidfVectorizer(). Selanjutnya, kita dapat menentukan beberapa konfigurasi penting berikut:

  • max_features: jumlah fitur yang ingin kita gunakan dengan melihat skor frekuensi kata yang muncul paling banyak;
  • ngram_range: batas bawah dan atas untuk n-gram yang akan diekstraksi dari suatu teks;
  • max_df: pengabaian istilah yang memiliki frekuensi dokumen lebih tinggi dari ambang batas ini.

Selebihnya silakan mengacu pada dokumentasi Scikit-klearn untuk TF-IDF.

Rekomendasi Film Indonesia dengan Cosine Similarity

Untuk melihat kemiripan suatu fitur yang sudah kita representasikan ke dalam suatu vektor, kita dapat meggunakan metode cosine similarity. Metode ini menghitung kemiripan dengan perkalian skalar / titik (dot product) dibagi dengan besaran vektor-vektor tersebut. Suatu vektor akan dianggap sama apabila skor untuk cosine similarity ini bernilai 1.

sim(A,B)=\cos(\theta)=\frac{A.B}{||A||||B||}

# Pendefinisian fungsi untuk mengecek kemiripan film dengan melakukan perhitungan cosine_similarity
def periksa_film_mirip(data, index, jumlah_film=10):
  sim = np.array([cosine_similarity(data[index].reshape(1, -1), data[i].reshape(1, -1))[0][0] for i in range(data.shape[0])])
  sim_idx = np.argsort(sim)[::-1][:jumlah_film]
  return sim_idx

Pada baris kode diatas, kita membuat fungsi periksa_film_mirip() dengan masukan data, index dari film yang dicari dan berapa jumlah_film (dengan skor kesamaan teratas) yang ingin ditampilkan. Keluaran dari fungsi terebut adalah indeks dari film yang dianggap mirip berdasarkan perhitungan skor cosine_similarity() tersebut.

# Ketika cinta bertasbih
sim_idx = periksa_film_mirip(X, 921)
data.loc[sim_idx][['judul_film', 'genre', 'ringkasan_sinopsis']]

Sebagai contoh, dengan fitur TF-IDF tersebut kita bisa menghitung langsung kesamaannya dengan memanggil fungsi periksa_film_mirip() dengan X dan 921 sebagai indeks untuk film “Ketika Cinta Bertasbih” (salah satu film favorit saya). Keluaran dari fungsi tersebut ialah sebagai sepuluh film berikut “Ketika Cinta Bertasbih”, “Ketika Cinta Bertasbih 2”, “Habibie & Ainun”, “Rudy Habibie”, “Titian Serambut Dibelah Tudjuh”, “Sang Pencerah”, “Perempuan Berkalung Sorban”, “Rokkap”, “Para Pencari Tuhan”, “Secerah Senyum”. Hasilnya tersebut saya rasa sudah cukup mewakili karena sebagian besar film tersebut bergenre sama dengan “Ketika Cinta Bertasbih”, yaitu sama-sama bergenre romantis. Ketika melihat lebih dalam ringkasan sinopsis dari film-film tersebut, terdapat kata-kata yang sering muncul, seperti “hidup”, “cinta”, “juang”, “islam”, dan “jodoh”.

Ekstraksi Representasi Tersembunyi dengan Autoencoders (AEs)

Pada tahapan kedua ini, kita akan mencoba untuk melakukan penyempurnaan dari model yang telah dibahas sebelumnya dengan menggunakan autoencoders sebagai model jaringan saraf tiruan. Model ini kita gunakan untuk melakukan ekstraksi fitur yang tersembunyi dari fitur yang telah kita ekstraksi sebelumnya dengan menggunakan TF-IDF di atas.

Persiapan data dengan mini-batch

# Pendifinisian fungsi untuk membuat objek dari DataLoader
def buat_loader(data, label, batch_size=8, shuffle=True):

  # Buat list yang berisi data & label, kita konversi juga dari numpy array ke dalam tensor di pytorch
  records = [{'data': torch.from_numpy(data[i]), 'label': torch.from_numpy(np.array(label[i]))} for i in range(data.shape[0])]

  # Kembalikan objek dari DataLoader dengan konfigurasi batch_size yang telah disiapkan
  return DataLoader(records, batch_size=batch_size, num_workers=1, shuffle=shuffle)
# Panggil fungsi buat_loader untuk memudahkan pelatihan  
data_train = buat_loader(X, y)

Pertama, kita akan menggunakan metode pelatihan stochastic gradient descent dengan menggunakan mini-batch. Untuk mempermudah, kita siapkan dengan menggunakan DataLoader yang sudah disiapkan oleh PyTorch. Dari data yang kita punyai tersebut, kita konversi terlebih dahulu menjadi suatu PyTorch’s tensor dengan memanggil fungsi torch.from_numpy(data[i]). Semua data kita simpan dalam peubah records untuk kemudian kita jadikan sebagai masukan untuk kelas DataLoader dengan parameter lain seperti batch_size, num_workers dan shuffle.

Model Autoencoders

Model autoencoders yang akan kita gunakan terdiri dari dua jaringan, yaitu encoder dan decoder. Encoder bertugas untuk melakukan kompresi dari data masukan untuk mendapatkan representasi tersembunyi untuk kemudian direkonstruksi oleh decoder. Untuk keperluan kita, data masukan berupa fitur TF-IDF dan model tersebut harus melakukan rekonstruksi TF-IDF. Sebagai gambaran, model tersebut dapat diilustrasikan sebagai berikut.

Autoencoders sebagai model kecerdasan artifisial untuk mendapatkan ekstraksi fitur untuk rekomendasi film Indonesia.
Autoencoders untuk mendapatkan ekstraksi fitur untuk rekomendasi film Indonesia.
# Definisikan class untuk Autoencoder
class Autoencoder(nn.Module):
  # Konstruktor
  def __init__(self, embed_dim):
    super(Autoencoder, self).__init__()
    self.encoder = nn.Sequential(
        nn.Linear(embed_dim, 512),
        nn.BatchNorm1d(512),
        nn.Tanh(),
        nn.Dropout(0.3),
        nn.Linear(512, 256),
        nn.BatchNorm1d(256),
        nn.Tanh(),
        nn.Dropout(0.3),
        nn.Linear(256, 64),
        nn.BatchNorm1d(64),
        nn.Tanh(),
        nn.Dropout(0.3),
    )
    self.decoder = nn.Sequential(
        nn.Linear(64, 256),
        nn.BatchNorm1d(256),
        nn.Tanh(),
        nn.Dropout(0.3),
        nn.Linear(256, 512),
        nn.BatchNorm1d(512),
        nn.Tanh(),
        nn.Dropout(0.3),
        nn.Linear(512, embed_dim)
    )
    self.reset_parameters()

  # Inisiasi parameters
  def reset_parameters(self):
    for weight in self.parameters():
        if len(weight.size()) == 1:
          continue
        nn.init.xavier_normal_(weight)
 
  # Operasi encode
  def encode(self, x):
    return self.encoder(x)

  # Operasi decode
  def decode(self, z):
    return self.decoder(z)
  
  # Operasi Autoencoder
  def forward(self, x):
    # Encode
    z = self.encode(x)
    # Decode
    x_hat = self.decode(z)
    return x_hat

Untuk itu, dengan menggunakan PyTorch, kita buat terlebih dahulu kelas Autoencoder yang memiliki masing-masing tiga lapisan untuk encoder dan decoder. Untuk memudahkan pendeklarasian lapisan tersebut, kita dapat menggunakan nn.Sequential()dan mendaftarkan semua operasi yang kita inginkan sebagai masukan. Seperti yang terlihat pada baris kode di bawah ini, saya menggunakan nn.Linear() sebagai operasi transformasi linear, nn.BatchNorm1d() dan nn.Dropout() sebagai teknik regularisasi untuk membantu proses pelatihan berjalan dengan baik, dan nn.Tanh() sebagai fungsi aktivasi non-linearitas. Sebagai tambahan, saya membuat fungsi reset_parameters() untuk melakuan inisialisasi pada bobot dengan menggunakan metode Xavier.

Pelatihan model Autoencoders

# Konfigurasi pemelajaran
# embed_dim = 1024
embed_dim = X.shape[1]
learning_rate = 0.00001
weight_decay = 0.00001
epochs = 2000

# Inisialisasi 
losses = []
lowest_loss = 99999
criterion_loss = nn.MSELoss()
model = Autoencoder(embed_dim).cuda()
best_model = None
optimizer = optim.Adam(model.parameters(), lr=learning_rate, weight_decay=weight_decay)

# Pengecekan model
print(model)

Setelah persiapan data dan pembuatan model tersebut selesai, kita tinggal melakukan parameter untuk pelatihan, seperti menentukan dimensi masukan embed_dim, laju pelatihan learning_rate, nilai regularisasi menggunakan L2 weight_decay, dan menentukan jumlah epochs. Selain itu, sebagai pengukuran keberhasilan rekonstruksi, kita tentukan mean-squared loss dengan fungsi nn.MSELoss()sebagai fungsi kerugian (loss function). Tak lupa pula kita gunakan optimizer sebagai teknik optimisasi untuk pelatihan / pencarian bobot yang optimal. Kali ini kita gunakan optimisasi Adam dengan memanggil optim.Adam(). Kita dapat melihat atau memeriksa terlebih dahulu model yang telah kita buat teresebut di atas dengan menggunakan fungsi print(model).

# Set mode menjadi pelatihan
model.train()

# Perulangan untuk pelatihan
for epoch in range(epochs):  
  # Rekam total loss
  tot_loss = 0.

  # Ambil data training
  for batch in data_train:

    # Hapus gradien
    optimizer.zero_grad()
    
    # Dapatkan data untuk batch kali ini
    batch_x = batch['data'].float().cuda()
    batch_y = batch['label'].float().cuda()

    # Panggil model
    batch_x_hat = model(batch_x)

    # Hitung loss
    loss = criterion_loss(batch_x, batch_x_hat)

    # Backpropagation dan update bobot
    loss.backward()
    optimizer.step()

    # Rekam loss
    tot_loss += loss.item()
  
  # Rekam rata-rata dari losses
  losses.append(tot_loss / len(data_train))

  # Tampilkan epoch losses
  print('Epoch %d, Loss: %.5f' % (epoch, tot_loss))

  # Periksa apakah epoch ini yang terbaik?
  if tot_loss < lowest_loss:
    lowest_loss = tot_loss
    best_model = model
    print('Epoch %d Terbaik! Loss: %.5f' % (epoch, tot_loss))

Setelah itu, kita dapat menjalankan pelatihan dengan melakukan perulangan sebanyak epochs kali. Jangan lupa untuk melakukan set model.train() untuk memberi tahu model kita bahwa kita sedang melakukan proses pelatihan. Karena kita menggunakan metode pencarian gradien berdasarkan galat antara rekonstruksi dan data asli pada tiap batch, maka sebelum melakukan perhitungan tesebut kita panggil terlebih dahulu optimizer.zero_grad()untuk menghapus perhitungan dan penyimpanan gradien pada batch sebelumnya. Setelah itu, kita dapatkan data batch saat ini, dan panggil model dengan fungsi model(batch_x) kemudian kita simpan hasil rekonstruksi fitur tersebut ke dalam peubahbatch_x_hat. Perhitungan galat dapat dilakukan secara mudah dengan menggunakan fungsi criterion_loss(batch_x, batch_x_hat) dan menyimpannya dalam peubah loss.

Tahap selanjutnya ialah penggunaan metode propagansi mundur (backpropagation) untuk mendapatkan gradien dengan memanggil fungsi loss.backward(). Proses perhitungan gradien secara otomatis akan ditangani oleh PyTorch. Setelah itu, bobot yang baru dapat dihitung dan diperbarui berdasarkan gradien tersebut dengan memanggil fungsi optimizer.step(). Sampai tahap ini, sebenarnya proses perhitungan untuk batch tersebut sudah selesai. Namun, untuk kepentingan pencatatan, kita akan catat rata-rata dari galat untuk setiap epoch dan menyimpannya sebagai list pada peubah losses. Tak lupa juga kita simpan model terbaik sebagai best_model, apabila hasil pelatihan mendapatkan nilai galat terendah dari nilai sebelumnya.

Dengan melakukan pencatatan yang demikian, kita dapat dengan mudah membuat ilustrasi kurva pelatihan perubahan galat untuk tiap epoch, seperti gambar di bawah ini. Dari tren pada kurva tersebut, terlihat bahwa rata-rata galat menurun seiring dengan berjalannya epoch. Hal ini menandakan pelatihan berjalan baik.

Kurva pelatihan model kecerdasan artifisial Autoencoder
Kurva pelatihan model kecerdasan artifisial Autoencoder

Evaluasi Model untuk Rekomendasi Film Indonesia

# Ambil model terbaik dan set mode menjadi evaluasi
best_model.eval()

# Lakukan operasi encode dengan menggunakan model terbaik yang sudah dilatih
X_encoded = best_model.encode(torch.from_numpy(X).float().cuda()).to('cpu').detach().numpy()

Untuk melakukan evaluasi, kita gunakan best_model.eval() untuk mengubahnya menjadi mode evaluasi. Setelah itu, untuk setiap fitur yang kita punyai pada peubah X kita ekstrak fitur tersembunyinya dengan memanggil fungsi best_model.encode()dan kita simpan pada peubah X_encoded.

# Ketika cinta bertasbih
sim_idx = periksa_film_mirip(X_encoded, 921, 15)
data.loc[sim_idx][['judul_film', 'genre', 'ringkasan_sinopsis']]

Setelah itu, kita tinggal melakukan evaluasi dengan menghitung kesamaan fitur tersebut dengan memanggil fungsi periksa_film_mirip() untuk mendapatkan rekomendasi film Indonesia. Hal ini sama seperti yang sebelumnya sudah kita lakukan dengan menggunakan fitur TF-IDF. Dengan menjalankan baris kode di atas, dari masukan film “Ketika Cinta Bertasbih” kita mendapatkan rekomendasi film: “Ketika Cinta Bertasbih”, “Ketika Cinta Bertasbih 2”, “Sang Pencerah”, “Cakra”, “Sepuluh”, “LOVE and FAITH”, “Habibie & Ainun”, “Rudy Habibie”, “Membunuh : Murder”, “King”, “Air Mata Terakhir Bunda”, “Quickie Express”, “Secerah Senyum”, “Dream Obama”, “Para Pencari Tuhan”. Secara umum, beberapa kata yang didapatkan dari judul-judul film yang direkomendasikan mempunyai kesamaan kata dasar seperti “hidup”, “ibu”, “juang”, “cinta”, “kerja”, “usaha”, “didik”, dll. Judul yang direkomendasikan sedikit berbeda dari sebelumnya, dengan beberapa kejanggalan, misalnya munculnya judul “Cakra”, “Membunuh: Murder”, “Quickie Express”,. Ketiganya merupakan genre laga dan komedi dan ini berbeda dari genre “Ketika Cinta Bertasbih”, yang bergenre romantis. Ketika hal ini ditelisik lebih jauh, ditemukan bahwa ringkasan sinopsis ketiga tersebut sangatlah pendek, yaitu hanya 1-2 kalimat. Terlalu pendeknya sinopsis ini beresiko memunculkan kesalahan yang lebih tinggi saat dijadikan sebagai data pelatihan. Dengan demikian, ini dapat menjadi catatan bahwa ringkasan sinopsis yang pendek disarankan untuk dihapus sebagai data pelatihan karena akan berdampak bias pada pelatihan model.

# Catatan Akhir Sekolah
sim_idx = periksa_film_mirip(X_encoded, 47, 15)
data.loc[sim_idx][['judul_film', 'genre', 'ringkasan_sinopsis']]

Sebagai contoh tambahan, saya coba juga untuk mendapatkan rekomendasi film yang memiliki kesamaan karakteristik dengan film “Catatan Akhir Sekolah”. Hasilnya rekomendasi film yang muncul sebagai berikut “Catatan Akhir Sekolah”, “Rini Tomboy”, “Pengantin Sunat”, “Barbi3”, “Something in Between”, “Basahhh…”, “Planet Mars”, “Semua Sudah Dimaafkan Sebab Kita Pernah Bahagia”, “Lupus”, “Oh Baby”, “Sarang Kuntilanak”, “My Generation”, “Total Chaos”, “Marmut Merah Jambu”, “Cita-Citaku Setinggi Tanah”. Secara umum, dari film-film memiliki karakteristik karena mengandung kata-kata seperti “sekolah”, “SMA”, “siswa”, “remaja”, “masa”, “dokumenter”, dan “hidup”.

# Air terjun pengantin	
sim_idx = periksa_film_mirip(X_encoded, 213, 15)
data.loc[sim_idx][['judul_film', 'genre', 'ringkasan_sinopsis']]

Selain dari genre-genre film yang sudah dibahas, rekomendasi film Indonesia dari genre horor pun bisa didapatkan dengan masukan “Air Terjun Pengantin” sebagai contoh dan dengan hasil rekomendasi film sebagai berikut “Air Terjun Pengantin”, “Ada Apa dengan Pocong?”, “Siti”, “Jakarta Undercover”, “Garis Bawah”, “Terowongan Casablanca”, “Air Terjun Pengantin Phuket”, “Tusuk Jelangkung”, “Badai di Ujung Negeri”, “Raiders of the Doomed Kingdom”, “Lawang Sewu”, “Kawin Kontrak lagi”, “Beranak dalam Kubur”, “Tengkorak Hidoep”, “Alas Pati”. Sebagian besar judul yang direkomendasikan memang berasal dari genre horor dengan beberapa pengecualian. Kata-kata yang terdapat pada sinopsis tersebut misalnya “pengantin”, “meninggal”, “kecelakaan”, “jatuh”, “dukun”, “bunuh”, “malam”, “mayat”, dll.

# Jendral Soedirman	
sim_idx = periksa_film_mirip(X_encoded, 800, 15)
data.loc[sim_idx][['judul_film', 'genre', 'ringkasan_sinopsis']]

Sebagai sampel terakhir, karena saat ini kita berada di bulan Agustus– bulan kemerdekaan Republik Indonesia tercinta ini — tentu sangat relavan dan merupakan momen yang tepat untuk menonton film dengan tema perjuangan. Saya mencoba menjalankan evaluasi untuk film “Jendral Soedirman”, dengan hasil rekomendasi film: “Jendral Soedirman”, “Soegija”, “Naga Bonar”, “Banda the Dark Forgotten Trail”, “Jaka Sembung”, “Dead Mine”, “Kafedo”, “Darah Garuda – Merah Putih II”, “Hearts of Fredom”, “Guru Bangsa Tjokroaminoto”, “DPO (Detachement Police Operation)”, “Pulang”, “Pasukan Garuda: I Leave My Heart In Lebanon”, “Maju Terus!”, “Bulan Terbit di atas Mesir”. Sesuai dengan harapan, kata yang sering muncul dari ringkasan sinopsis film-film tersebut ialah “Indonesia”, “Belanda”, “perang”, “tentara”, “gerilya”, “merdeka”, “pimpin”, “rakyat”, “juang”, “pulau”, dll.

Pengembangan sistem rekomendasi lanjutan dan produk lainnya

Saat ini, fitur masukan yang berupa sinopsis dari film yang kita punyai sebagai referensi sangat bergantung pada bagus-tidaknya sinopsis tersebut disusun sehingga mampu menjelaskan isi film tersebut secara ringkas. Jika hanya sekadar mencoba mengembangkan sistem rekomendasi seperti ini untuk kepentingan pribadi, saya rasa ini sudah cukup. Tetapi jika ini diterapkan pada layanan untuk perusahaan besar, tentu saja kesalahan dalam merekemondasikan suatu produk akan beresiko terhadap potensi hilangnya calon pangguna atau pelanggan yang tepat. Untuk mendapatkan hasil yang optimal tentu content-based filtering saja tidak cukup. Dengan menggabungkan dua pendekatan content-based filtering dan collaborative-filtering, diharapkan kita mendapatkan model yang lebih akurat.

Ide pengembangan lainnya ialah seorang pengguna dapat dengan bebas memasukkan kata-kata kunci yang mereka inginkan sebagai deskripsi dari film yang ingin mereka tonton. Dengan proses yang sama, model kecerdasan artifisal dapat dengan mudah mendapatkan rekomendasi film yang penonton inginkan.

Selain untuk memfilter rekomendasi film, sistem rekomendasi seperti ini dapat dengan mudah juga diterapkan pada kasus-kasus lain yang serupa. Misalnya, sistem rekomendasi buku, handphone, laptop, dan lain sebagainya. Tentu dengan syarat dataset dari kategori pencarian tersebut tersedia dengan jumlah sampel yang relatif banyak untuk melatih modal yang kita punyai dan membuat model yang akurat dalam merekomendasikan suatu produk kepada pelanggan.

Referensi & sumber bacaan selanjutnya

https://codeburst.io/explanation-of-recommender-systems-in-information-retrieval-13077e1d916c

https://towardsdatascience.com/creating-a-hybrid-content-collaborative-movie-recommender-using-deep-learning-cc8b431618af

https://towardsdatascience.com/how-to-build-from-scratch-a-content-based-movie-recommender-with-natural-language-processing-25ad400eb243


Jika ada pertanyaan, koreksi, ataupun ingin sekadar berdiskusi lebih lanjut, silakan gunakan kolom komentar untuk berkomunikasi dengan penulis.

Ikuti juga kami di media sosial lain:


About author
Mahasiswa program doktoral di Korea University, Korea Selatan dengan jurusan Brain & Cognitive Engineering | Anggota dari Machine Intelligence Lab @ Korea University | Perintis dari Konsep.AI
Articles
Related posts
Tutorial

Tutorial pemelajaran mesin: metode pengklasteran K-means

10 Mins read
Pada artikel kali ini, saya akan membahas metode pengklasteran data dengan menggunakan salah satu metode pemelajaran mesin (machine learning) yaitu K-means. Metode…
Daftarkan email kamu untuk mendapatkan ulasan terkini seputar teknologi kecerdasan buatan!

 

Leave a Reply

Your email address will not be published. Required fields are marked *