Pengenalan MLlib

Konsep pipeline ML terdistribusi.

Daftar isi

MLlib adalah pustaka pembelajaran mesin Spark, dan cara terbaik mengenalnya adalah melalui satu abstraksi kuncinya, yaitu pipeline. Pipeline menyusun tahap persiapan data dan model menjadi satu objek yang di-fit dan di-transform sebagaimana DataFrame, sehingga pekerjaan pembelajaran mesin menikmati hal yang sama dengan pekerjaan data lain di Spark, yaitu eksekusi terdistribusi dan schema yang tercatat. Topik ini merakit pipeline kecil dari ujung ke ujung dan menempatkan MLlib dalam peta kerja pembelajaran mesin modern.

Tiga jenis tahap dan pola pipeline#

Pipeline tersusun dari stage yang bertipe Transformer atau Estimator. Transformer mengubah satu DataFrame menjadi DataFrame lain, misalnya tokenizer yang menambahkan kolom kata terpisah. Estimator belajar dari data dan menghasilkan Transformer, misalnya fit() pada logistic regression yang menghasilkan model untuk dipakai memprediksi. Pipeline sendiri adalah estimator gabungan, sehingga fit() pada pipeline menjalankan seluruh tahap secara berurutan dan menghasilkan PipelineModel yang siap dipakai pada data baru.

Manfaat pipeline baru benar-benar terasa pada dua soal klasik pembelajaran mesin. Pertama, konsistensi persiapan, karena transformasi yang sama diterapkan pada data latih dan data uji tanpa risiko seseorang lupa menyalin langkah. Kedua, penyetelan parameter, karena seluruh tahap bisa dibungkus cross validator dengan grid parameter pada tiap tahapnya, dan Spark menjalankan fold secara paralel.

Penting juga mengenali batas abstraksi ini. Pipeline MLlib bekerja di atas DataFrame dengan kolom numerik, sehingga teks dan kategori harus diubah menjadi vektor oleh tahap fitur terlebih dahulu. Ekosistem di luar MLlib yang berbasis pandas dan scikit-learn jauh lebih luas untuk eksperimen model, dan praktik yang lazim adalah memakai MLlib ketika data sudah terlalu besar untuk satu mesin, bukan ketika sedang mencari model terbaik dari data kecil.

Pipeline teks dua kelas#

Skrip berikut melatih klasifikasi teks dua kelas dengan tiga tahap, yaitu tokenizer yang memecah teks menjadi kata, hashing term frequency yang mengubah kata menjadi vektor fitur, dan logistic regression yang belajar dari vektor tersebut. Data latihnya empat baris, dua tentang dunia Spark dan dua tentang dunia pandas, lalu dua baris baru diprediksi.

python ml_pipeline.py
# tidak-dijalankan
from pyspark.sql import SparkSession
from pyspark.ml import Pipeline
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.feature import HashingTF, Tokenizer

spark = (
    SparkSession.builder
    .master("local[2]")
    .appName("ml-pipeline")
    .getOrCreate()
)

latih = spark.createDataFrame(
    [
        (0, "java spark hadoop cluster"),
        (0, "hadoop mapreduce spark job"),
        (1, "pandas matplotlib notebook"),
        (1, "numpy pandas jupyter data"),
    ],
    "label long, teks string",
)

pipeline = Pipeline(
    stages=[
        Tokenizer(inputCol="teks", outputCol="kata"),
        HashingTF(numFeatures=64, inputCol="kata", outputCol="fitur"),
        LogisticRegression(maxIter=10, featuresCol="fitur", labelCol="label"),
    ]
)

model = pipeline.fit(latih)

uji = spark.createDataFrame(
    [
        ("spark hadoop cluster job",),
        ("pandas jupyter notebook",),
    ],
    "teks string",
)
prediksi = model.transform(uji)
prediksi.select("teks", "prediction").show(truncate=False)

spark.stop()
text Ilustrasi keluaran
WARNING: Using incubator modules: jdk.incubator.vector
+------------------------+----------+
|teks                    |prediction|
+------------------------+----------+
|spark hadoop cluster job|0.0       |
|pandas jupyter notebook |1.0       |
+------------------------+----------+

Keluaran menunjukkan keduanya terprediksi benar, yaitu teks dengan kata-kata dunia Spark masuk kelas 0 dan teks pandas masuk kelas 1. Bagian yang lebih penting dari akurasi di sini adalah struktur kerjanya, karena satu panggilan fit() menjalankan seluruh tahap, dan transform() pada data baru mengulang persiapan yang sama tanpa satu pun langkah manual. Skrip ini dieksekusi manual untuk merekam keluarannya karena inisialisasi komponen pembelajaran mesin melewati batas verifikasi otomatis pada sandbox, mengikuti pola yang sama dengan topik Delta Lake.

Perhatikan nama kolom yang dinyatakan eksplisit pada setiap tahap, yaitu inputCol dan outputCol yang menghubungkan tahap satu dengan berikutnya. Nama ini bukan hiasan, melainkan kontrak antar tahap, dan error paling umum di MLlib adalah kolom masukan yang tidak diproduksi tahap sebelumnya. Pada data nyata, tahap di depan biasanya berisi perbaikan string, pengisian nilai kosong, dan pengodean kategori sebelum vektor terbentuk.

Posisi MLlib dalam praktik pembelajaran mesin#

MLlib memakai DataFrames sebagai basis sejak Spark 2, dan paket lama berbasis RDD kini menjadi spark.mllib warisan yang tidak lagi dikembangkan. Pada praktik nyata, MLlib dipakai untuk regresi, klasifikasi, pengelompokan, sistem rekomendasi, dan penyusunan fitur pada data yang tersimpan di Spark, dengan alasan utama menghindari penyalinan data keluar dari cluster. Ketika data masih muat di satu mesin, alur pandas dan scikit-learn biasanya lebih cepat menyelesaikan eksperimen, dan hasilnya baru dipindahkan ke MLlib ketika skala menuntut.

Pembelajar yang mengikuti jalur ini disarankan menahan diri dari model yang rumit terlebih dahulu dan menguasai pola pipeline-nya, karena pola inilah yang dibawa ke mana pun pustakanya. Modul pengerjaan proyek menempatkan pipeline semacam ini dalam satu arsitektur data yang utuh, dengan tahap serve yang mengonsumsi prediksi hasil pelatihan.

Kesalahan umum#

Kesalahan pertama adalah menyalin transformasi secara manual ke data latih dan data uji. Setiap salinan adalah peluang langkah berbeda, dan hasil evaluasinya tidak lagi jujur. Perbaikannya adalah membungkus seluruh persiapan dalam pipeline dan membiarkan fit serta transform menjalankan tahap yang sama persis.

Kesalahan kedua adalah memanggil fit pada PipelineModel. Model hasil pelatihan sudah selesai dilatih, sehingga yang tersedia hanya transform, dan error yang muncul ketika memaksa fit justru menjadi pengingat bahwa objek yang salah dipakai. Alurnya tegas, estimator untuk melatih, transformer untuk memakai.

Kesalahan ketiga adalah menyetel numFeatures hashing terlalu kecil pada data teks nyata. Fungsi hash memetakan kata ke nomor kolom secara tetap, dan dua kata yang berbeda bisa bertabrakan di kolom yang sama, yang pada nilai numFeatures yang kecil berarti informasi hilang tanpa disadari. Nilai default satu juta kolom aman untuk banyak kasus, dan menaikkan ukuran tabel hash murah dibandingkan kesalahan model yang tidak terlihat.

Ringkasan#

  • Pipeline menyusun tahap persiapan dan model menjadi satu objek yang di-fit sekali dan di-transform pada data baru tanpa salinan langkah manual.
  • Transformer mengubah DataFrame menjadi DataFrame lain, estimator belajar dari data dan menghasilkan transformer, dan kontrak antar tahap adalah nama kolom.
  • MLlib bekerja di atas DataFrame terdistribusi dan cocok ketika data sudah melebihi satu mesin, bukan untuk eksperimen cepat pada data kecil.
  • Kesalahan paling umum di MLlib adalah kolom masukan yang tidak diproduksi tahap sebelumnya dan tabrakan hashing pada tabel fitur yang terlalu kecil.

Referensi#