Kecerdasan buatan

Pola Desain dalam Python untuk Insinyur AI dan LLM: Panduan Praktis

mm
Design Patterns in Python for AI and LLM Engineers: A Practical Guide

Sebagai insinyur AI, membuat kode yang bersih, efisien, dan mudah dipelihara sangat penting, terutama ketika membangun sistem yang kompleks.

Pola desain adalah solusi yang dapat digunakan kembali untuk masalah umum dalam desain perangkat lunak. Untuk insinyur AI dan LLM, pola desain membantu membangun sistem yang kuat, scalable, dan mudah dipelihara yang dapat menangani alur kerja yang kompleks dengan efisien. Artikel ini akan membahas pola desain dalam Python, dengan fokus pada relevansinya dalam sistem AI dan LLM. Saya akan menjelaskan setiap pola dengan contoh kasus praktis dan kode Python.

Mari kita jelajahi beberapa pola desain kunci yang sangat berguna dalam konteks AI dan pembelajaran mesin, bersama dengan contoh Python.

Mengapa Pola Desain Penting untuk Insinyur AI

Sistem AI sering melibatkan:

  1. Pembuatan objek yang kompleks (misalnya, memuat model, pipeline praproses data).
  2. Mengelola interaksi antara komponen (misalnya, inferensi model, pembaruan waktu nyata).
  3. Mengatasi skalabilitas, keterjagaan, dan fleksibilitas untuk kebutuhan yang berubah.

Pola desain menangani tantangan ini, memberikan struktur yang jelas dan mengurangi perbaikan ad-hoc. Mereka dibagi menjadi tiga kategori utama:

  • Pola Kreatif: Fokus pada pembuatan objek. (Singleton, Factory, Builder)
  • Pola Struktural: Mengatur hubungan antara objek. (Adapter, Dekorator)
  • Pola Perilaku: Mengelola komunikasi antara objek. (Strategi, Pengamat)

1. Pola Singleton

Pola Singleton memastikan sebuah kelas hanya memiliki satu instance dan menyediakan akses global ke instance tersebut. Ini sangat berharga dalam alur kerja AI di mana sumber daya bersama—seperti pengaturan konfigurasi, sistem logging, atau instance model—harus dikelola secara konsisten tanpa redundansi.

Kapan Menggunakan

  • Mengelola konfigurasi global (misalnya, hiperparameter model).
  • Berbagi sumber daya di seluruh thread atau proses (misalnya, memori GPU).
  • Mengensure akses konsisten ke satu mesin inferensi atau koneksi database.

Implementasi

Berikut adalah cara mengimplementasikan pola Singleton dalam Python untuk mengelola konfigurasi model AI:

class KonfigurasiModel:
"""
Kelas Singleton untuk mengelola konfigurasi model global.
"""
_instance = None # Variabel kelas untuk menyimpan instance Singleton

<p>def __new__(cls, *args, **kwargs):
if not cls._instance:
# Buat instance baru jika belum ada
cls._instance = super().__new__(cls)
cls._instance.pengaturan = {} # Inisialisasi kamus konfigurasi
return cls._instance</p>

<p>def set(self, kunci, nilai):
&quot;&quot;&quot;
Setel pasangan kunci-nilai konfigurasi.
&quot;&quot;&quot;
self.pengaturan[kunci] = nilai</p>

<p>def get(self, kunci):
&quot;&quot;&quot;
Dapatkan nilai konfigurasi berdasarkan kunci.
&quot;&quot;&quot;
return self.pengaturan.get(kunci)</p>

<p># Contoh Penggunaan
konfigurasi1 = KonfigurasiModel()
konfigurasi1.set(&quot;nama_model&quot;, &quot;GPT-4&quot;)
konfigurasi1.set(&quot;ukuran_batch&quot;, 32)</p>

<p># Mengakses instance yang sama
konfigurasi2 = KonfigurasiModel()
print(konfigurasi2.get(&quot;nama_model&quot;)) # Keluaran: GPT-4
print(konfigurasi2.get(&quot;ukuran_batch&quot;)) # Keluaran: 32
print(konfigurasi1 is konfigurasi2) # Keluaran: True (keduanya adalah instance yang sama)</p>

Penjelasan

  1. Metode __new__: Metode ini memastikan hanya satu instance dari kelas yang dibuat. Jika instance sudah ada, maka instance yang ada itu yang dikembalikan.
  2. Keadaan Bersama: Baik konfigurasi1 dan konfigurasi2 mengacu pada instance yang sama, membuat semua konfigurasi dapat diakses secara global dan konsisten.
  3. Kasus Penggunaan AI: Gunakan pola ini untuk mengelola pengaturan global seperti jalur dataset, konfigurasi logging, atau variabel lingkungan.

2. Pola Factory

Pola Factory menyediakan cara untuk mendelegasikan pembuatan objek ke subkelas atau metode factory khusus. Dalam sistem AI, pola ini ideal untuk membuat jenis model, loader data, atau pipeline dinamis berdasarkan konteks.

Kapan Menggunakan

  • Membuat model dinamis berdasarkan input pengguna atau kebutuhan tugas.
  • Mengelola logika pembuatan objek yang kompleks (misalnya, pipeline praproses data multi-langkah).
  • Melepaskan instansiasi objek dari sisa sistem untuk meningkatkan fleksibilitas.

Implementasi

Mari kita bangun sebuah Factory untuk membuat model untuk tugas AI yang berbeda, seperti klasifikasi teks, ringkasan, dan terjemahan:

class ModelDasar:
&quot;&quot;&quot;
Kelas dasar abstrak untuk model AI.
&quot;&quot;&quot;
def prediksi(self, data):
raise NotImplementedError(&quot;Subkelas harus mengimplementasikan metode `prediksi`&quot;)

<p>class ModelKlasifikasiTekst(ModelDasar):
def prediksi(self, data):
return f&quot;Mengklasifikasikan teks: {data}&quot;</p>

<p>class ModelRingkasan(ModelDasar):
def prediksi(self, data):
return f&quot;Meringkas teks: {data}&quot;</p>

<p>class ModelTerjemahan(ModelDasar):
def prediksi(self, data):
return f&quot;Menerjemahkan teks: {data}&quot;</p>

<p>class FactoryModel:
&quot;&quot;&quot;
Kelas Factory untuk membuat model AI dinamis.
&quot;&quot;&quot;
@staticmethod
def buat_model(jenis_tugas):
&quot;&quot;&quot;
Metode factory untuk membuat model berdasarkan jenis tugas.
&quot;&quot;&quot;
pemetaan_tugas = {
&quot;klasifikasi&quot;: ModelKlasifikasiTekst,
&quot;ringkasan&quot;: ModelRingkasan,
&quot;terjemahan&quot;: ModelTerjemahan,
}
kelas_model = pemetaan_tugas.get(jenis_tugas)
if not kelas_model:
raise ValueError(f&quot;Jenis tugas tidak dikenal: {jenis_tugas}&quot;)
return kelas_model()</p>

<p># Contoh Penggunaan
tugas = &quot;klasifikasi&quot;
model = FactoryModel.buat_model(tugas)
print(model.prediksi(&quot;AI akan mengubah dunia!&quot;))
# Keluaran: Mengklasifikasikan teks: AI akan mengubah dunia!</p>

Penjelasan

  1. Kelas Dasar Abstrak: Kelas ModelDasar mendefinisikan antarmuka (prediksi) yang harus diimplementasikan oleh semua subkelas, memastikan konsistensi.
  2. Logika Factory: Kelas FactoryModel secara dinamis memilih kelas yang tepat berdasarkan jenis tugas dan membuat instance.
  3. Ekstensibilitas: Menambahkan jenis model baru sangat mudah—hanya implementasikan subkelas baru dan perbarui pemetaan_tugas factory.

Kasus Penggunaan AI

Bayangkan Anda merancang sistem yang memilih model LLM yang berbeda (misalnya, BERT, GPT, atau T5) berdasarkan tugas. Pola Factory membuatnya mudah untuk memperluas sistem saat model baru tersedia tanpa memodifikasi kode yang ada.

3. Pola Builder

Pola Builder memisahkan konstruksi objek kompleks dari representasinya. Pola ini berguna ketika objek melibatkan beberapa langkah untuk diinisialisasi atau dikonfigurasi.

Kapan Menggunakan

  • Membangun pipeline multi-langkah (misalnya, praproses data).
  • Mengelola konfigurasi untuk eksperimen atau pelatihan model.
  • Membuat objek yang memerlukan banyak parameter, memastikan keterbacaan dan keterjagaan.

Implementasi

Berikut adalah cara menggunakan pola Builder untuk membuat pipeline praproses data:

class PipelineData:
&quot;&quot;&quot;
Kelas Builder untuk membangun pipeline praproses data.
&quot;&quot;&quot;
def __init__(self):
self.langkah = []

<p>def tambah_langkah(self, fungsi_langkah):
&quot;&quot;&quot;
Tambahkan langkah praproses ke pipeline.
&quot;&quot;&quot;
self.langkah.append(fungsi_langkah)
return self # Kembalikan self untuk memungkinkan chaining metode</p>

<p>def jalankan(self, data):
&quot;&quot;&quot;
Jalankan semua langkah dalam pipeline.
&quot;&quot;&quot;
for langkah in self.langkah:
data = langkah(data)
return data</p>

<p># Contoh Penggunaan
pipeline = PipelineData()
pipeline.tambah_langkah(lambda x: x.strip()) # Langkah 1: Hilangkan spasi
pipeline.tambah_langkah(lambda x: x.lower()) # Langkah 2: Konversi ke lowercase
pipeline.tambah_langkah(lambda x: x.replace(&quot;.&quot;, &quot;&quot;)) # Langkah 3: Hilangkan titik</p>

<p>data_olahan = pipeline.jalankan(&quot; Halo Dunia. &quot;)
print(data_olahan) # Keluaran: halo dunia</p>

Penjelasan

  1. Metode Berantai: Metode tambah_langkah memungkinkan chaining untuk sintaks yang intuitif dan ringkas saat mendefinisikan pipeline.
  2. Eksekusi Langkah demi Langkah: Pipeline mengolah data dengan menjalankannya melalui setiap langkah secara berurutan.
  3. Kasus Penggunaan AI: Gunakan pola Builder untuk membuat pipeline praproses data yang kompleks atau pengaturan pelatihan model.

4. Pola Strategi

Pola Strategi mendefinisikan keluarga algoritma yang dapat dipertukarkan, mengenkapsulasi setiap algoritma dan memungkinkan perilaku berubah secara dinamis saat runtime. Pola ini sangat berguna dalam sistem AI di mana proses yang sama (misalnya, inferensi atau pengolahan data) mungkin memerlukan pendekatan yang berbeda tergantung pada konteks.

Kapan Menggunakan

  • Beralih antara strategi inferensi yang berbeda (misalnya, pengolahan batch vs. streaming).
  • Menggunakan teknik pengolahan data yang berbeda secara dinamis.
  • Memilih strategi manajemen sumber daya berdasarkan infrastruktur yang tersedia.

Implementasi

Mari kita gunakan pola Strategi untuk mengimplementasikan dua strategi inferensi yang berbeda untuk model AI: inferensi batch dan inferensi streaming.


<p>class StrategiInferensi:
&quot;&quot;&quot;
Kelas dasar abstrak untuk strategi inferensi.
&quot;&quot;&quot;
def inferensi(self, model, data):
raise NotImplementedError(&quot;Subkelas harus mengimplementasikan metode `inferensi`&quot;)</p>

<p>class InferensiBatch(StrategiInferensi):
&quot;&quot;&quot;
Strategi untuk inferensi batch.
&quot;&quot;&quot;
def inferensi(self, model, data):
print(&quot;Melakukan inferensi batch...&quot;)
return [model.prediksi(item) for item in data]</p>

<p>class InferensiStreaming(StrategiInferensi):
&quot;&quot;&quot;
Strategi untuk inferensi streaming.
&quot;&quot;&quot;
def inferensi(self, model, data):
print(&quot;Melakukan inferensi streaming...&quot;)
hasil = []
for item in data:
hasil.append(model.prediksi(item))
return hasil</p>

<p>class KonteksInferensi:
&quot;&quot;&quot;
Kelas konteks untuk beralih antara strategi inferensi secara dinamis.
&quot;&quot;&quot;
def __init__(self, strategi: StrategiInferensi):
self.strategi = strategi</p>

<p>def set_strategi(self, strategi: StrategiInferensi):
&quot;&quot;&quot;
Ubah strategi inferensi secara dinamis.
&quot;&quot;&quot;
self.strategi = strategi</p>

<p>def inferensi(self, model, data):
&quot;&quot;&quot;
Delegasikan inferensi ke strategi yang dipilih.
&quot;&quot;&quot;
return self.strategi.inferensi(model, data)</p>

<p># Kelas Model Mock
class ModelMock:
def prediksi(self, input_data):
return f&quot;Diprediksi: {input_data}&quot;</p>

<p># Contoh Penggunaan
model = ModelMock()
data = [&quot;sampel1&quot;, &quot;sampel2&quot;, &quot;sampel3&quot;]</p>

<p>konteks = KonteksInferensi(InferensiBatch())
print(konteks.inferensi(model, data))
# Keluaran:
# Melakukan inferensi batch...
# [&#039;Diprediksi: sampel1&#039;, &#039;Diprediksi: sampel2&#039;, &#039;Diprediksi: sampel3&#039;]</p>

<p># Beralih ke inferensi streaming
konteks.set_strategi(InferensiStreaming())
print(konteks.inferensi(model, data))
# Keluaran:
# Melakukan inferensi streaming...
# [&#039;Diprediksi: sampel1&#039;, &#039;Diprediksi: sampel2&#039;, &#039;Diprediksi: sampel3&#039;]</p>

Penjelasan

  1. Kelas Strategi Abstrak: Kelas StrategiInferensi mendefinisikan antarmuka yang harus diikuti oleh semua strategi.
  2. Strategi Konkret: Setiap strategi (misalnya, InferensiBatch, InferensiStreaming) mengimplementasikan logika khusus untuk pendekatan tersebut.
  3. Peralihan Dinamis: Kelas KonteksInferensi memungkinkan peralihan strategi pada runtime, menawarkan fleksibilitas untuk kasus penggunaan yang berbeda.

Kapan Menggunakan

  • Beralih antara inferensi batch untuk pengolahan offline dan inferensi streaming untuk aplikasi waktu nyata.
  • Menyesuaikan teknik pengolahan data atau praproses dinamis berdasarkan tugas atau format input.

5. Pola Pengamat

Pola Pengamat membangun hubungan satu-ke-banyak antara objek. Ketika satu objek (subyek) berubah keadaan, semua objek yang bergantung (pengamat) diberitahu secara otomatis. Pola ini sangat berguna dalam sistem AI untuk pemantauan waktu nyata, penanganan peristiwa, atau sinkronisasi data.

Kapan Menggunakan

  • Memantau metrik seperti akurasi atau kerugian selama pelatihan model.
  • Pembaruan waktu nyata untuk dashboard atau log.
  • Mengelola ketergantungan antara komponen dalam alur kerja yang kompleks.

Implementasi

Mari kita gunakan pola Pengamat untuk memantau kinerja model AI secara waktu nyata.

class Subyek:
&quot;&quot;&quot;
Kelas dasar untuk subyek yang diawasi.
&quot;&quot;&quot;
def __init__(self):
self._pengamat = []

<p>def tambah_pengamat(self, pengamat):
&quot;&quot;&quot;
Tambahkan pengamat ke subyek.
&quot;&quot;&quot;
self._pengamat.append(pengamat)</p>

<p>def hapus_pengamat(self, pengamat):
&quot;&quot;&quot;
Hapus pengamat dari subyek.
&quot;&quot;&quot;
self._pengamat.remove(pengamat)</p>

<p>def beritahu(self, data):
&quot;&quot;&quot;
Beritahu semua pengamat tentang perubahan keadaan.
&quot;&quot;&quot;
for pengamat in self._pengamat:
pengamat.perbarui(data)</p>

<p>class PemantauModel(Subyek):
&quot;&quot;&quot;
Subyek yang memantau metrik kinerja model.
&quot;&quot;&quot;
def perbarui_metrik(self, nama_metrik, nilai):
&quot;&quot;&quot;
Simulasikan pembaruan metrik kinerja dan beritahu pengamat.
&quot;&quot;&quot;
print(f&quot;Diperbarui {nama_metrik}: {nilai}&quot;)
self.beritahu({nama_metrik: nilai})</p>

<p>class Pengamat:
&quot;&quot;&quot;
Kelas dasar untuk pengamat.
&quot;&quot;&quot;
def perbarui(self, data):
raise NotImplementedError(&quot;Subkelas harus mengimplementasikan metode `perbarui`&quot;)</p>

<p>class PengamatLog(Pengamat):
&quot;&quot;&quot;
Pengamat untuk mencatat metrik.
&quot;&quot;&quot;
def perbarui(self, data):
print(f&quot;Mencatat metrik: {data}&quot;)</p>

<p>class PengamatPeringatan(Pengamat):
&quot;&quot;&quot;
Pengamat untuk mengangkat peringatan jika ambang batas dilanggar.
&quot;&quot;&quot;
def __init__(self, ambang_batas):
self.ambang_batas = ambang_batas</p>

<p>def perbarui(self, data):
for metrik, nilai in data.items():
if nilai &amp;gt; self.ambang_batas:
print(f&quot;PERINGATAN: {metrik} melebihi ambang batas dengan nilai {nilai}&quot;)</p>

<p># Contoh Penggunaan
pemantau = PemantauModel()
pencatat = PengamatLog()
peringatan = PengamatPeringatan(ambang_batas=90)</p>

<p>pemantau.tambah_pengamat(pencatat)
pemantau.tambah_pengamat(peringatan)</p>

<p># Simulasikan pembaruan metrik
pemantau.perbarui_metrik(&quot;akurasi&quot;, 85) # Mencatat metrik
pemantau.perbarui_metrik(&quot;akurasi&quot;, 95) # Mencatat dan memicu peringatan</p>

Penjelasan
  1. Subyek: Mengelola daftar pengamat dan memberitahu mereka ketika keadaannya berubah. Dalam contoh ini, kelas PemantauModel melacak metrik.
  2. Pengamat: Melakukan tindakan spesifik ketika diberitahu. Misalnya, PengamatLog mencatat metrik, sedangkan PengamatPeringatan memicu peringatan jika ambang batas dilanggar.
  3. Desain Terpisah: Pengamat dan subyek terhubung longgar, membuat sistem modular dan dapat diperluas.

Bagaimana Pola Desain Berbeda untuk Insinyur AI vs. Insinyur Tradisional

Pola desain, meskipun secara umum dapat diterapkan, mengambil karakteristik unik ketika diimplementasikan dalam rekayasa AI dibandingkan dengan rekayasa perangkat lunak tradisional. Perbedaan ini terletak pada tantangan, tujuan, dan alur kerja yang melekat dalam sistem AI, yang sering kali memerlukan pola untuk disesuaikan atau diperluas di luar penggunaan konvensional.

1. Pembuatan Objek: Statis vs. Dinamis

  • Rekayasa Tradisional: Pola pembuatan objek seperti Factory atau Singleton sering digunakan untuk mengelola konfigurasi, koneksi database, atau keadaan sesi pengguna. Ini umumnya statis dan didefinisikan dengan baik selama desain sistem.
  • Rekayasa AI: Pembuatan objek sering melibatkan alur kerja dinamis, seperti:
    • Membuat model secara dinamis berdasarkan input pengguna atau kebutuhan sistem.
    • Memuat konfigurasi model yang berbeda untuk tugas seperti terjemahan, ringkasan, atau klasifikasi.
    • Menginstansiasi pipeline pengolahan data yang berbeda tergantung pada karakteristik dataset (misalnya, data tabular vs. teks tidak terstruktur).

Contoh: Dalam AI, pola Factory mungkin secara dinamis menghasilkan model pembelajaran dalam yang berbeda berdasarkan jenis tugas dan keterbatasan perangkat keras, sedangkan dalam sistem tradisional, itu mungkin hanya menghasilkan komponen antarmuka pengguna.

2. Keterbatasan Kinerja

  • Rekayasa Tradisional: Pola desain biasanya dioptimalkan untuk latensi dan throughput dalam aplikasi seperti server web, kueri database, atau rendering antarmuka pengguna.
  • Rekayasa AI: Keterbatasan kinerja dalam AI meluas ke latensi inferensi model, utilisasi GPU/TPU, dan optimasi memori. Pola harus menampung:
    • Penyimpanan hasil antara untuk mengurangi perhitungan berulang (Pola Dekorator atau Proksi).
    • Switching algoritma dinamis (Pola Strategi) untuk menyeimbangkan latensi dan akurasi berdasarkan beban sistem atau keterbatasan waktu nyata.

3. Sifat Data-Centric

  • Rekayasa Tradisional: Pola sering beroperasi pada struktur input-output yang tetap (misalnya, form, respons API REST).
  • Rekayasa AI: Pola harus menangani variabilitas data baik dalam struktur maupun skala, termasuk:
    • Streaming data untuk sistem waktu nyata.
    • Data multimodal (misalnya, teks, gambar, video) yang memerlukan pipeline dengan langkah pengolahan yang fleksibel.
    • Dataset skala besar yang memerlukan pipeline praproses dan augmentasi data yang efisien, sering menggunakan pola seperti Builder atau Pipeline.

4. Eksperimen vs. Stabilitas

  • Rekayasa Tradisional: Fokus pada membangun sistem yang stabil dan dapat diprediksi di mana pola memastikan kinerja yang konsisten dan keandalan.
  • Rekayasa AI: Alur kerja AI sering eksperimental dan melibatkan:
    • Mengulang berbagai arsitektur model atau teknik praproses data.
    • Mengupdate komponen sistem secara dinamis (misalnya, pelatihan ulang model, mengganti algoritma).
    • Mengembangkan alur kerja yang ada tanpa memutus pipeline produksi, sering menggunakan pola yang dapat diperluas seperti Dekorator atau Factory.

Contoh: Sebuah Factory dalam AI mungkin tidak hanya menginstansiasi model tetapi juga melampirkan bobot yang telah dimuat sebelumnya, mengatur pengoptimasi, dan menghubungkan callback pelatihan—semua secara dinamis.

Praktik Terbaik untuk Menggunakan Pola Desain dalam Proyek AI

  1. Jangan Terlalu Direkayasa: Gunakan pola hanya ketika mereka secara jelas memecahkan masalah atau meningkatkan organisasi kode.
  2. Pertimbangkan Skala: Pilih pola yang akan berkembang dengan sistem AI Anda.
  3. Dokumentasi: Dokumentasikan mengapa Anda memilih pola tertentu dan bagaimana mereka harus digunakan.
  4. Pengujian: Pola desain harus membuat kode Anda lebih mudah diuji, bukan lebih sulit.
  5. Kinerja: Pertimbangkan implikasi kinerja dari pola, terutama dalam pipeline inferensi.

Kesimpulan

Pola desain adalah alat kuat untuk insinyur AI, membantu menciptakan sistem yang dapat dipelihara dan scalable. Kunci adalah memilih pola yang tepat untuk kebutuhan spesifik Anda dan mengimplementasikannya dengan cara yang meningkatkan kode Anda.

Ingat bahwa pola adalah pedoman, bukan aturan. Merasa bebas untuk menyesuaikannya dengan kebutuhan spesifik Anda sambil menjaga prinsip inti tetap utuh.

Saya telah menghabiskan lima tahun terakhir dengan membenamkan diri dalam dunia Machine Learning dan Deep Learning yang menarik. Minat dan keahlian saya telah membawa saya untuk berkontribusi pada lebih dari 50 proyek rekayasa perangkat lunak yang beragam, dengan fokus khusus pada AI/ML. Rasa ingin tahu saya yang terus-menerus juga telah menarik saya ke arah Natural Language Processing, sebuah bidang yang saya ingin jelajahi lebih lanjut.