Evaluasi model

Setelah melatih model, AutoML Vision menggunakan item dari set TEST untuk mengevaluasi kualitas dan akurasi model baru.

Ringkasan evaluasi

AutoML Vision menyediakan kumpulan metrik evaluasi gabungan yang menunjukkan performa model secara keseluruhan, serta metrik evaluasi untuk setiap label kategori, yang menunjukkan performa model untuk label tersebut.

  • AuPRC : Area di bawah kurva Presisi/Perolehan, juga disebut sebagai "presisi rata-rata". Umumnya antara 0,5 dan 1,0. Nilai yang lebih tinggi menunjukkan model yang lebih akurat.

  • Kurva nilai minimum keyakinan menunjukkan pengaruh nilai minimum keyakinan yang berbeda terhadap rasio positif palsu, perolehan, dan presisi. Baca hubungan presisi dan perolehan.

  • Matriks konfusi: Hanya ada untuk model label tunggal per gambar. Merepresentasikan persentase frekuensi setiap label diprediksi untuk setiap label dalam set pelatihan selama evaluasi.

    Contoh matriks konfusi

    Idealnya, label one hanya akan ditetapkan ke gambar yang diklasifikasikan sebagai label one, dll. sehingga matriks yang sempurna akan terlihat seperti:

    100  0   0   0
     0  100  0   0
     0   0  100  0
     0   0   0  100
    

    Pada contoh di atas, jika gambar diklasifikasikan sebagai one tetapi model memprediksi two, baris pertama akan terlihat seperti ini:

    99  1  0  0
    

    Informasi selengkapnya dapat ditemukan dengan menelusuri 'confusion matrix machine learning'.

    AutoML Vision membuat matriks kebingungan hingga 10 label. Jika Anda memiliki lebih dari 10 label, matriks akan menyertakan 10 label yang paling membingungkan (prediksi yang salah).

Gunakan data ini untuk mengevaluasi kesiapan model Anda. Kebingungan yang tinggi, skor AUC yang rendah, atau skor presisi dan perolehan yang rendah dapat menunjukkan bahwa model Anda memerlukan data pelatihan tambahan atau memiliki label yang tidak konsisten. Skor ABK yang sangat tinggi serta presisi dan perolehan yang sempurna dapat menunjukkan bahwa data terlalu mudah dan mungkin tidak digeneralisasi dengan baik.

Membuat daftar evaluasi model

Setelah melatih model, Anda dapat mencantumkan metrik evaluasi untuk model tersebut.

UI Web

  1. Buka AutoML Vision UI dan klik tab Models (dengan ikon bohlam) di menu navigasi sebelah kiri untuk menampilkan model yang tersedia.

    Untuk melihat model project yang berbeda, pilih project dari menu drop-down di kanan atas panel judul.

  2. Klik baris untuk model yang ingin dievaluasi.

  3. Jika perlu, klik tab Evaluasi tepat di bawah panel judul.

    Jika pelatihan untuk model telah selesai, AutoML Vision akan menampilkan metrik evaluasinya.

    Halaman evaluasi model

REST

Sebelum menggunakan salah satu data permintaan, lakukan penggantian berikut:

  • project-id: Project ID GCP Anda.
  • model-id: ID model Anda, dari respons saat membuat model. ID adalah elemen terakhir dari nama model Anda. Misalnya:
    • nama model: projects/project-id/locations/location-id/models/IOD4412217016962778756
    • id model: IOD4412217016962778756
  • model-evaluation-id: nilai ID evaluasi dari model. Anda dapat mendapatkan ID evaluasi model dari operasi evaluasi model list.

Metode HTTP dan URL:

GET https://automl.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/models/MODEL_ID/modelEvaluations/MODEL_EVALUATION_ID

Untuk mengirim permintaan Anda, pilih salah satu opsi berikut:

curl

Jalankan perintah berikut:

curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "x-goog-user-project: project-id" \
"https://automl.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/models/MODEL_ID/modelEvaluations/MODEL_EVALUATION_ID"

PowerShell

Jalankan perintah berikut:

$cred = gcloud auth print-access-token
$headers = @{ "Authorization" = "Bearer $cred"; "x-goog-user-project" = "project-id" }

Invoke-WebRequest `
-Method GET `
-Headers $headers `
-Uri "https://automl.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/models/MODEL_ID/modelEvaluations/MODEL_EVALUATION_ID" | Select-Object -Expand Content

Anda akan menerima respons JSON yang mirip dengan contoh berikut. Kolom khusus deteksi objek utama dicetak tebal, dan versi entri classificationEvaluationMetrics yang disingkat ditampilkan agar lebih jelas:

Go

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.

import (
	"context"
	"fmt"
	"io"

	automl "cloud.google.com/go/automl/apiv1"
	"cloud.google.com/go/automl/apiv1/automlpb"
	"google.golang.org/api/iterator"
)

// listModelEvaluation lists existing model evaluations.
func listModelEvaluations(w io.Writer, projectID string, location string, modelID string) error {
	// projectID := "my-project-id"
	// location := "us-central1"
	// modelID := "TRL123456789..."

	ctx := context.Background()
	client, err := automl.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("NewClient: %w", err)
	}
	defer client.Close()

	req := &automlpb.ListModelEvaluationsRequest{
		Parent: fmt.Sprintf("projects/%s/locations/%s/models/%s", projectID, location, modelID),
	}

	it := client.ListModelEvaluations(ctx, req)

	// Iterate over all results
	for {
		evaluation, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("ListModelEvaluations.Next: %w", err)
		}

		fmt.Fprintf(w, "Model evaluation name: %v\n", evaluation.GetName())
		fmt.Fprintf(w, "Model annotation spec id: %v\n", evaluation.GetAnnotationSpecId())
		fmt.Fprintf(w, "Create Time:\n")
		fmt.Fprintf(w, "\tseconds: %v\n", evaluation.GetCreateTime().GetSeconds())
		fmt.Fprintf(w, "\tnanos: %v\n", evaluation.GetCreateTime().GetNanos())
		fmt.Fprintf(w, "Evaluation example count: %v\n", evaluation.GetEvaluatedExampleCount())
		fmt.Fprintf(w, "Classification model evaluation metrics: %v\n", evaluation.GetClassificationEvaluationMetrics())
	}

	return nil
}

Java

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.


import com.google.cloud.automl.v1.AutoMlClient;
import com.google.cloud.automl.v1.ListModelEvaluationsRequest;
import com.google.cloud.automl.v1.ModelEvaluation;
import com.google.cloud.automl.v1.ModelName;
import java.io.IOException;

class ListModelEvaluations {

  public static void main(String[] args) throws IOException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "YOUR_PROJECT_ID";
    String modelId = "YOUR_MODEL_ID";
    listModelEvaluations(projectId, modelId);
  }

  // List model evaluations
  static void listModelEvaluations(String projectId, String modelId) throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources.
    try (AutoMlClient client = AutoMlClient.create()) {
      // Get the full path of the model.
      ModelName modelFullId = ModelName.of(projectId, "us-central1", modelId);
      ListModelEvaluationsRequest modelEvaluationsrequest =
          ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build();

      // List all the model evaluations in the model by applying filter.
      System.out.println("List of model evaluations:");
      for (ModelEvaluation modelEvaluation :
          client.listModelEvaluations(modelEvaluationsrequest).iterateAll()) {

        System.out.format("Model Evaluation Name: %s\n", modelEvaluation.getName());
        System.out.format("Model Annotation Spec Id: %s", modelEvaluation.getAnnotationSpecId());
        System.out.println("Create Time:");
        System.out.format("\tseconds: %s\n", modelEvaluation.getCreateTime().getSeconds());
        System.out.format("\tnanos: %s", modelEvaluation.getCreateTime().getNanos() / 1e9);
        System.out.format(
            "Evalution Example Count: %d\n", modelEvaluation.getEvaluatedExampleCount());
        System.out.format(
            "Classification Model Evaluation Metrics: %s\n",
            modelEvaluation.getClassificationEvaluationMetrics());
      }
    }
  }
}

Node.js

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const location = 'us-central1';
// const modelId = 'YOUR_MODEL_ID';

// Imports the Google Cloud AutoML library
const {AutoMlClient} = require('@google-cloud/automl').v1;

// Instantiates a client
const client = new AutoMlClient();

async function listModelEvaluations() {
  // Construct request
  const request = {
    parent: client.modelPath(projectId, location, modelId),
    filter: '',
  };

  const [response] = await client.listModelEvaluations(request);

  console.log('List of model evaluations:');
  for (const evaluation of response) {
    console.log(`Model evaluation name: ${evaluation.name}`);
    console.log(`Model annotation spec id: ${evaluation.annotationSpecId}`);
    console.log(`Model display name: ${evaluation.displayName}`);
    console.log('Model create time');
    console.log(`\tseconds ${evaluation.createTime.seconds}`);
    console.log(`\tnanos ${evaluation.createTime.nanos / 1e9}`);
    console.log(
      `Evaluation example count: ${evaluation.evaluatedExampleCount}`
    );
    console.log(
      `Classification model evaluation metrics: ${evaluation.classificationEvaluationMetrics}`
    );
  }
}

listModelEvaluations();

Python

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.

from google.cloud import automl

# TODO(developer): Uncomment and set the following variables
# project_id = "YOUR_PROJECT_ID"
# model_id = "YOUR_MODEL_ID"

client = automl.AutoMlClient()
# Get the full path of the model.
model_full_id = client.model_path(project_id, "us-central1", model_id)

print("List of model evaluations:")
for evaluation in client.list_model_evaluations(parent=model_full_id, filter=""):
    print(f"Model evaluation name: {evaluation.name}")
    print(f"Model annotation spec id: {evaluation.annotation_spec_id}")
    print(f"Create Time: {evaluation.create_time}")
    print(f"Evaluation example count: {evaluation.evaluated_example_count}")
    print(
        "Classification model evaluation metrics: {}".format(
            evaluation.classification_evaluation_metrics
        )
    )

Bahasa tambahan

C# : Ikuti Petunjuk penyiapan C# di halaman library klien, lalu kunjungi dokumentasi referensi AutoML Vision untuk .NET.

PHP : Ikuti Petunjuk penyiapan PHP di halaman library klien, lalu kunjungi dokumentasi referensi AutoML Vision untuk PHP.

Ruby: Ikuti Petunjuk persiapan Ruby di halaman library klien, lalu kunjungi Dokumentasi referensi AutoML Vision untuk Ruby.

Mendapatkan nilai evaluasi model

Anda juga bisa mendapatkan evaluasi model tertentu untuk label (displayName) menggunakan ID evaluasi. Untuk mendapatkan ID evaluasi model, jalankan fungsi evaluasi model daftar yang ditampilkan dalam Evaluasi model daftar.

UI web

  1. Buka Vision Dashboard dan klik ikon bola lampu di menu navigasi kiri untuk menampilkan model yang tersedia.

    Untuk melihat model project yang berbeda, pilih project dari menu drop-down di kanan atas panel judul.

  2. Klik baris untuk model yang ingin dievaluasi.

  3. Jika perlu, klik tab Evaluasi tepat di bawah panel judul.

    Jika pelatihan untuk model telah selesai, AutoML Vision akan menampilkan metrik evaluasinya.

    updated evaluate page
  4. Untuk melihat metrik untuk label tertentu, pilih nama label dari daftar label di bagian bawah halaman.

    Label khusus halaman evaluasi model

REST

Untuk mendapatkan metrik evaluasi untuk label tertentu saja, tambahkan /{MODEL_EVALUATION_ID} ke permintaan di atas dari respons.

Misalnya, Anda dapat menemukan ID evaluasi model untuk rose label (displayName) dalam nama evaluasi yang ditampilkan dari operasi daftar:

  • "name": "projects/PROJECT_ID/locations/us-central1/models/MODEL_ID/modelEvaluations/858136867710915695"

Sebelum menggunakan salah satu data permintaan, buat pengganti berikut:

  • project-id: Project ID GCP Anda.
  • model-id: ID model Anda, dari respons saat membuat model. ID adalah elemen terakhir dari nama model Anda. Misalnya:
    • nama model: projects/project-id/locations/location-id/models/IOD4412217016962778756
    • id model: IOD4412217016962778756
  • model-evaluation-id: nilai ID evaluasi dari model. Anda dapat mendapatkan ID evaluasi model dari operasi evaluasi model list.

Metode HTTP dan URL:

GET https://automl.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/models/MODEL_ID/modelEvaluations/MODEL_EVALUATION_ID

Untuk mengirim permintaan Anda, pilih salah satu opsi berikut:

curl

Jalankan perintah berikut:

curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "x-goog-user-project: project-id" \
"https://automl.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/models/MODEL_ID/modelEvaluations/MODEL_EVALUATION_ID"

PowerShell

Jalankan perintah berikut:

$cred = gcloud auth print-access-token
$headers = @{ "Authorization" = "Bearer $cred"; "x-goog-user-project" = "project-id" }

Invoke-WebRequest `
-Method GET `
-Headers $headers `
-Uri "https://automl.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/models/MODEL_ID/modelEvaluations/MODEL_EVALUATION_ID" | Select-Object -Expand Content

Anda akan menerima respons JSON yang mirip dengan yang berikut ini:

Go

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.

import (
	"context"
	"fmt"
	"io"

	automl "cloud.google.com/go/automl/apiv1"
	"cloud.google.com/go/automl/apiv1/automlpb"
)

// getModelEvaluation gets a model evaluation.
func getModelEvaluation(w io.Writer, projectID string, location string, modelID string, modelEvaluationID string) error {
	// projectID := "my-project-id"
	// location := "us-central1"
	// modelID := "TRL123456789..."
	// modelEvaluationID := "123456789..."

	ctx := context.Background()
	client, err := automl.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("NewClient: %w", err)
	}
	defer client.Close()

	req := &automlpb.GetModelEvaluationRequest{
		Name: fmt.Sprintf("projects/%s/locations/%s/models/%s/modelEvaluations/%s", projectID, location, modelID, modelEvaluationID),
	}

	evaluation, err := client.GetModelEvaluation(ctx, req)
	if err != nil {
		return fmt.Errorf("GetModelEvaluation: %w", err)
	}

	fmt.Fprintf(w, "Model evaluation name: %v\n", evaluation.GetName())
	fmt.Fprintf(w, "Model annotation spec id: %v\n", evaluation.GetAnnotationSpecId())
	fmt.Fprintf(w, "Create Time:\n")
	fmt.Fprintf(w, "\tseconds: %v\n", evaluation.GetCreateTime().GetSeconds())
	fmt.Fprintf(w, "\tnanos: %v\n", evaluation.GetCreateTime().GetNanos())
	fmt.Fprintf(w, "Evaluation example count: %v\n", evaluation.GetEvaluatedExampleCount())
	fmt.Fprintf(w, "Classification model evaluation metrics: %v\n", evaluation.GetClassificationEvaluationMetrics())

	return nil
}

Java

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.


import com.google.cloud.automl.v1.AutoMlClient;
import com.google.cloud.automl.v1.ModelEvaluation;
import com.google.cloud.automl.v1.ModelEvaluationName;
import java.io.IOException;

class GetModelEvaluation {

  static void getModelEvaluation() throws IOException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "YOUR_PROJECT_ID";
    String modelId = "YOUR_MODEL_ID";
    String modelEvaluationId = "YOUR_MODEL_EVALUATION_ID";
    getModelEvaluation(projectId, modelId, modelEvaluationId);
  }

  // Get a model evaluation
  static void getModelEvaluation(String projectId, String modelId, String modelEvaluationId)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources.
    try (AutoMlClient client = AutoMlClient.create()) {
      // Get the full path of the model evaluation.
      ModelEvaluationName modelEvaluationFullId =
          ModelEvaluationName.of(projectId, "us-central1", modelId, modelEvaluationId);

      // Get complete detail of the model evaluation.
      ModelEvaluation modelEvaluation = client.getModelEvaluation(modelEvaluationFullId);

      System.out.format("Model Evaluation Name: %s\n", modelEvaluation.getName());
      System.out.format("Model Annotation Spec Id: %s", modelEvaluation.getAnnotationSpecId());
      System.out.println("Create Time:");
      System.out.format("\tseconds: %s\n", modelEvaluation.getCreateTime().getSeconds());
      System.out.format("\tnanos: %s", modelEvaluation.getCreateTime().getNanos() / 1e9);
      System.out.format(
          "Evalution Example Count: %d\n", modelEvaluation.getEvaluatedExampleCount());
      System.out.format(
          "Classification Model Evaluation Metrics: %s\n",
          modelEvaluation.getClassificationEvaluationMetrics());
    }
  }
}

Node.js

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const location = 'us-central1';
// const modelId = 'YOUR_MODEL_ID';
// const modelEvaluationId = 'YOUR_MODEL_EVALUATION_ID';

// Imports the Google Cloud AutoML library
const {AutoMlClient} = require('@google-cloud/automl').v1;

// Instantiates a client
const client = new AutoMlClient();

async function getModelEvaluation() {
  // Construct request
  const request = {
    name: client.modelEvaluationPath(
      projectId,
      location,
      modelId,
      modelEvaluationId
    ),
  };

  const [response] = await client.getModelEvaluation(request);

  console.log(`Model evaluation name: ${response.name}`);
  console.log(`Model annotation spec id: ${response.annotationSpecId}`);
  console.log(`Model display name: ${response.displayName}`);
  console.log('Model create time');
  console.log(`\tseconds ${response.createTime.seconds}`);
  console.log(`\tnanos ${response.createTime.nanos / 1e9}`);
  console.log(`Evaluation example count: ${response.evaluatedExampleCount}`);
  console.log(
    `Classification model evaluation metrics: ${response.classificationEvaluationMetrics}`
  );
}

getModelEvaluation();

Python

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.

from google.cloud import automl

# TODO(developer): Uncomment and set the following variables
# project_id = "YOUR_PROJECT_ID"
# model_id = "YOUR_MODEL_ID"
# model_evaluation_id = "YOUR_MODEL_EVALUATION_ID"

client = automl.AutoMlClient()
# Get the full path of the model evaluation.
model_path = client.model_path(project_id, "us-central1", model_id)
model_evaluation_full_id = f"{model_path}/modelEvaluations/{model_evaluation_id}"

# Get complete detail of the model evaluation.
response = client.get_model_evaluation(name=model_evaluation_full_id)

print(f"Model evaluation name: {response.name}")
print(f"Model annotation spec id: {response.annotation_spec_id}")
print(f"Create Time: {response.create_time}")
print(f"Evaluation example count: {response.evaluated_example_count}")
print(
    "Classification model evaluation metrics: {}".format(
        response.classification_evaluation_metrics
    )
)

Positif Benar, Negatif Palsu, dan Positif Palsu (khusus UI)

Di antarmuka pengguna, Anda dapat mengamati contoh spesifik performa model, yaitu positif benar (TP), negatif palsu (FN), dan positif palsu (PP) dari set PELATIHAN dan VALIDATION.

UI web

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan untuk bahasa ini di halaman Library Klien.

Anda dapat mengakses tampilan TP, FN, dan FP di UI dengan memilih tab Evaluate, lalu memilih label tertentu.

Dengan melihat tren dalam prediksi ini, Anda dapat mengubah set pelatihan untuk meningkatkan performa model.

Gambar positif benar (true) adalah gambar contoh yang diberikan untuk model terlatih yang dianotasi dengan benar oleh model:

positif benar ditampilkan

Gambar negatif palsu serupa disediakan dengan model yang dilatih, tetapi model gagal menganotasi gambar dengan benar untuk label tertentu:

negatif palsu ditampilkan

Terakhir, gambar positif palsu adalah gambar yang diberikan ke model terlatih yang dianotasi dengan label tertentu, tetapi seharusnya tidak telah dianotasi:

positif palsu ditampilkan

Model sedang memilih corner case yang menarik, yang menghadirkan peluang untuk mempertajam definisi dan label Anda guna membantu model memahami interpretasi label Anda. Misalnya, definisi yang lebih ketat akan membantu model memahami apakah Anda mempertimbangkan lukisan abstrak mawar sebagai "mawar" (atau tidak).

Dengan label berulang, latih, dan evaluasi loop, model Anda akan memunculkan ambiguitas lainnya di data Anda.

Anda juga dapat menyesuaikan nilai minimum skor dalam tampilan ini di antarmuka pengguna, dan gambar TP, FN, dan FP yang ditampilkan akan mencerminkan perubahan nilai minimum:

positif benar dengan ambang batas yang diperbarui

Melakukan Iterasi pada model Anda

Jika tidak puas dengan tingkat kualitas tersebut, Anda dapat kembali ke langkah-langkah sebelumnya untuk meningkatkan kualitasnya:

  • Dengan AutoML Vision, Anda dapat mengurutkan gambar berdasarkan seberapa “bingung” model tersebut, berdasarkan label sebenarnya dan label prediksinya. Lihatlah gambar-gambar tersebut dan pastikan gambar-gambar tersebut diberi label dengan benar.
  • Pertimbangkan untuk menambahkan lebih banyak gambar ke label apa pun yang berkualitas rendah.
  • Anda mungkin perlu menambahkan berbagai jenis gambar (misalnya sudut yang lebih lebar, resolusi lebih tinggi atau lebih rendah, sudut pandang yang berbeda).
  • Pertimbangkan untuk menghapus label sekaligus jika Anda tidak memiliki cukup gambar pelatihan.
  • Ingat bahwa mesin tidak bisa membaca nama label Anda; itu hanya rangkaian huruf acak untuk mereka. Jika Anda memiliki satu label yang bertuliskan "door" dan label lainnya yang bertuliskan "door_with_knob", mesin tidak akan dapat mengetahui nuansa selain gambar yang Anda berikan.
  • Tingkatkan data Anda dengan lebih banyak contoh positif dan negatif benar. Contoh yang sangat penting adalah contoh yang mendekati batas keputusan (misalnya kemungkinan akan menimbulkan kebingungan, tetapi masih diberi label dengan benar).
  • Tentukan bagian LAT, TEST, VALIDATION Anda sendiri. Alat ini menetapkan gambar secara acak, tetapi gambar yang hampir duplikat dapat berakhir pada LATIHAN dan VALIDASI yang dapat menyebabkan overload dan kemudian performa yang buruk pada set PENGUJI.

Setelah membuat perubahan, latih dan evaluasi model baru sampai Anda mencapai tingkat kualitas yang cukup tinggi.