Pengenalan Nomor Pembelajaran Mesin - Dari Nol ke Aplikasi
Diterbitkan: 2022-03-11Pembelajaran mesin, visi komputer, membangun API yang kuat, dan membuat UI yang indah adalah bidang menarik yang menyaksikan banyak inovasi.
Dua yang pertama membutuhkan matematika dan sains yang luas, sementara pengembangan API dan UI berpusat pada pemikiran algoritmik dan perancangan arsitektur yang fleksibel. Mereka sangat berbeda, jadi memutuskan mana yang ingin Anda pelajari selanjutnya mungkin sulit. Tujuan artikel ini adalah untuk mendemonstrasikan bagaimana keempatnya dapat digunakan dalam membuat aplikasi pengolah gambar.
Aplikasi yang akan kita buat adalah pengenal digit sederhana. Anda menggambar, mesin memprediksi angka. Kesederhanaan sangat penting karena memungkinkan kita untuk melihat gambaran besar daripada fokus pada detail.
Demi kesederhanaan, kami akan menggunakan teknologi yang paling populer dan mudah dipelajari. Bagian pembelajaran mesin akan menggunakan Python untuk aplikasi back-end. Adapun sisi interaksi aplikasi, kami akan beroperasi melalui perpustakaan JavaScript yang tidak memerlukan pengenalan: Bereaksi.
Pembelajaran Mesin Menebak Angka
Bagian inti dari aplikasi kami adalah algoritme yang menebak nomor yang ditarik. Pembelajaran mesin akan menjadi alat yang digunakan untuk mencapai kualitas tebakan yang baik. Kecerdasan buatan dasar semacam ini memungkinkan sistem untuk belajar secara otomatis dengan sejumlah data tertentu. Dalam istilah yang lebih luas, pembelajaran mesin adalah proses menemukan kebetulan atau serangkaian kebetulan dalam data untuk mengandalkan mereka untuk menebak hasilnya.
Proses pengenalan gambar kami berisi tiga langkah:
- Dapatkan gambar digit yang ditarik untuk pelatihan
- Latih sistem untuk menebak angka melalui data pelatihan
- Uji sistem dengan data baru/tidak diketahui
Lingkungan
Kita akan membutuhkan lingkungan virtual untuk bekerja dengan pembelajaran mesin dengan Python. Pendekatan ini praktis karena mengelola semua paket Python yang diperlukan, jadi Anda tidak perlu mengkhawatirkannya.
Mari kita instal dengan perintah terminal berikut:
python3 -m venv virtualenv source virtualenv/bin/activate
Model Pelatihan
Sebelum kita mulai menulis kode, kita perlu memilih "guru" yang tepat untuk mesin kita. Biasanya, para profesional ilmu data mencoba model yang berbeda sebelum memilih yang terbaik. Kami akan melewatkan model yang sangat canggih yang membutuhkan banyak keterampilan dan melanjutkan dengan algoritma k-nearest neighbor.
Ini adalah algoritma yang mendapatkan beberapa sampel data dan mengaturnya pada bidang yang dipesan oleh serangkaian karakteristik tertentu. Untuk lebih memahaminya, mari kita tinjau gambar berikut:
Untuk mendeteksi tipe Titik Hijau , kita harus memeriksa tipe k tetangga terdekat di mana k adalah himpunan argumen. Perhatikan gambar di atas, jika k sama dengan 1, 2, 3, atau 4, maka tebakannya adalah Segitiga Hitam karena sebagian besar k tetangga terdekat titik hijau adalah segitiga hitam. Jika kita menambah k menjadi 5, maka sebagian besar objeknya adalah kotak biru, maka tebakannya adalah Kotak Biru .
Ada beberapa dependensi yang diperlukan untuk membuat model pembelajaran mesin kami:
- sklearn.neighbors.KNeighborsClassifier adalah classifier yang akan kita gunakan.
- sklearn.model_selection.train_test_split adalah fungsi yang akan membantu kita membagi data menjadi data pelatihan dan data yang digunakan untuk memeriksa kebenaran model.
- sklearn.model_selection.cross_val_score adalah fungsi untuk mendapatkan nilai kebenaran model. Semakin tinggi nilainya, semakin baik kebenarannya.
- sklearn.metrics.classification_report adalah fungsi untuk menampilkan laporan statistik tebakan model.
- sklearn.datasets adalah paket yang digunakan untuk mendapatkan data untuk pelatihan (gambar angka).
- numpy adalah paket yang banyak digunakan dalam sains karena menawarkan cara yang produktif dan nyaman untuk memanipulasi struktur data multidimensi dengan Python.
- matplotlib.pyplot adalah paket yang digunakan untuk memvisualisasikan data.
Mari kita mulai dengan menginstal dan mengimpor semuanya:
pip install sklearn numpy matplotlib scipy from sklearn.datasets import load_digits from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split, cross_val_score import numpy as np import matplotlib.pyplot as plt
Sekarang, kita perlu memuat Database MNIST. MNIST adalah kumpulan data klasik gambar tulisan tangan yang digunakan oleh ribuan pemula di bidang pembelajaran mesin:
digits = load_digits()
Setelah data diambil dan siap, kita dapat melanjutkan ke langkah berikutnya dengan membagi data menjadi dua bagian: pelatihan dan pengujian .
Kami akan menggunakan 75% data untuk melatih model kami untuk menebak angka dan kami akan menggunakan sisa data untuk menguji kebenaran model:
(X_train, X_test, y_train, y_test) = train_test_split( digits.data, digits.target, test_size=0.25, random_state=42 )
Data sekarang sudah diatur dan kami siap menggunakannya. Kami akan mencoba menemukan parameter k terbaik untuk model kami sehingga tebakan akan lebih tepat. Kami tidak dapat melupakan nilai k pada tahap ini, karena kami harus mengevaluasi model dengan nilai k yang berbeda.
Mari kita lihat mengapa penting untuk mempertimbangkan rentang nilai k dan bagaimana hal ini meningkatkan akurasi model kita:
ks = np.arange(2, 10) scores = [] for k in ks: model = KNeighborsClassifier(n_neighbors=k) score = cross_val_score(model, X_train, y_train, cv=5) score.mean() scores.append(score.mean()) plt.plot(scores, ks) plt.xlabel('accuracy') plt.ylabel('k') plt.show()
Menjalankan kode ini akan menampilkan plot berikut yang menjelaskan akurasi algoritme dengan nilai k yang berbeda.
Seperti yang Anda lihat, nilai k 3 memastikan akurasi terbaik untuk model dan kumpulan data kami.
Menggunakan Flask untuk Membangun API
Inti aplikasi, yang merupakan algoritme yang memprediksi angka dari gambar, sekarang sudah siap. Selanjutnya, kita perlu menghias algoritme dengan lapisan API agar tersedia untuk digunakan. Mari kita gunakan kerangka web Flask yang populer untuk melakukan ini dengan jelas dan ringkas.
Kami akan mulai dengan menginstal Flask dan dependensi yang terkait dengan pemrosesan gambar di lingkungan virtual:
pip install Flask Pillow scikit-image
Saat penginstalan selesai, kami pindah ke pembuatan file titik masuk aplikasi:
touch app.py
Isi file akan terlihat seperti ini:
import os from flask import Flask from views import PredictDigitView, IndexView app = Flask(__name__) app.add_url_rule( '/api/predict', view_func=PredictDigitView.as_view('predict_digit'), methods=['POST'] ) app.add_url_rule( '/', view_func=IndexView.as_view('index'), methods=['GET'] ) if __name__ == 'main': port = int(os.environ.get("PORT", 5000)) app.run(host='0.0.0.0', port=port)
Anda akan mendapatkan pesan kesalahan yang mengatakan bahwa PredictDigitView
dan IndexView
tidak ditentukan. Langkah selanjutnya adalah membuat file yang akan menginisialisasi tampilan ini:
from flask import render_template, request, Response from flask.views import MethodView, View from flask.views import View from repo import ClassifierRepo from services import PredictDigitService from settings import CLASSIFIER_STORAGE class IndexView(View): def dispatch_request(self): return render_template('index.html') class PredictDigitView(MethodView): def post(self): repo = ClassifierRepo(CLASSIFIER_STORAGE) service = PredictDigitService(repo) image_data_uri = request.json['image'] prediction = service.handle(image_data_uri) return Response(str(prediction).encode(), status=200)
Sekali lagi, kami akan menemukan kesalahan tentang impor yang belum terselesaikan. Paket Views bergantung pada tiga file yang belum kami miliki:
- Pengaturan
- repo
- Melayani
Kami akan menerapkannya satu per satu.
Pengaturan adalah modul dengan konfigurasi dan variabel konstan. Ini akan menyimpan jalur ke pengklasifikasi serial untuk kita. Ini menimbulkan pertanyaan logis: Mengapa saya perlu menyimpan pengklasifikasi?
Karena ini adalah cara sederhana untuk meningkatkan kinerja aplikasi Anda. Alih-alih melatih pengklasifikasi setiap kali Anda menerima permintaan, kami akan menyimpan versi pengklasifikasi yang disiapkan, memungkinkannya untuk bekerja di luar kotak:
import os BASE_DIR = os.getcwd() CLASSIFIER_STORAGE = os.path.join(BASE_DIR, 'storage/classifier.txt')
Mekanisme pengaturan — mendapatkan pengklasifikasi — akan diinisialisasi dalam paket berikutnya di daftar kami, Repo . Ini adalah kelas dengan dua metode untuk mengambil dan memperbarui pengklasifikasi terlatih menggunakan modul pickle
Python:
import pickle class ClassifierRepo: def __init__(self, storage): self.storage = storage def get(self): with open(self.storage, 'wb') as out: try: classifier_str = out.read() if classifier_str != '': return pickle.loads(classifier_str) else: return None except Exception: return None def update(self, classifier): with open(self.storage, 'wb') as in_: pickle.dump(classifier, in_)
Kami hampir menyelesaikan API kami. Sekarang hanya kekurangan modul Layanan . Apa tujuannya?
- Dapatkan pengklasifikasi terlatih dari penyimpanan
- Ubah gambar yang diteruskan dari UI ke format yang dipahami oleh pengklasifikasi
- Hitung prediksi dengan gambar yang diformat melalui classifier
- Kembalikan prediksi
Mari kita kodekan algoritma ini:
from sklearn.datasets import load_digits from classifier import ClassifierFactory from image_processing import process_image class PredictDigitService: def __init__(self, repo): self.repo = repo def handle(self, image_data_uri): classifier = self.repo.get() if classifier is None: digits = load_digits() classifier = ClassifierFactory.create_with_fit( digits.data, digits.target ) self.repo.update(classifier) x = process_image(image_data_uri) if x is None: return 0 prediction = classifier.predict(x)[0] return prediction
Di sini Anda dapat melihat bahwa PredictDigitService
memiliki dua dependensi: ClassifierFactory
dan process_image
.

Kita akan mulai dengan membuat kelas untuk membuat dan melatih model kita:
from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier class ClassifierFactory: @staticmethod def create_with_fit(data, target): model = KNeighborsClassifier(n_neighbors=3) model.fit(data, target) return model
API siap beraksi. Sekarang kita dapat melanjutkan ke langkah pemrosesan gambar.
Pengolahan citra
Pemrosesan gambar adalah metode melakukan operasi tertentu pada gambar untuk meningkatkannya atau mengekstrak beberapa informasi yang berguna darinya. Dalam kasus kami, kami perlu mentransisikan gambar yang digambar oleh pengguna dengan lancar ke format model pembelajaran mesin.
Mari impor beberapa pembantu untuk mencapai tujuan itu:
import numpy as np from skimage import exposure import base64 from PIL import Image, ImageOps, ImageChops from io import BytesIO
Kita dapat membagi transisi menjadi enam bagian yang berbeda:
1. Ganti background transparan dengan warna
def replace_transparent_background(image): image_arr = np.array(image) if len(image_arr.shape) == 2: return image alpha1 = 0 r2, g2, b2, alpha2 = 255, 255, 255, 255 red, green, blue, alpha = image_arr[:, :, 0], image_arr[:, :, 1], image_arr[:, :, 2], image_arr[:, :, 3] mask = (alpha == alpha1) image_arr[:, :, :4][mask] = [r2, g2, b2, alpha2] return Image.fromarray(image_arr)
2. Pangkas batas terbuka
def trim_borders(image): bg = Image.new(image.mode, image.size, image.getpixel((0,0))) diff = ImageChops.difference(image, bg) diff = ImageChops.add(diff, diff, 2.0, -100) bbox = diff.getbbox() if bbox: return image.crop(bbox) return image
3. Tambahkan batas dengan ukuran yang sama
def pad_image(image): return ImageOps.expand(image, border=30, fill='#fff')
4. Ubah gambar menjadi mode skala abu-abu
def to_grayscale(image): return image.convert('L')
5. Balikkan warna
def invert_colors(image): return ImageOps.invert(image)
6. Ubah ukuran gambar menjadi format 8x8
def resize_image(image): return image.resize((8, 8), Image.LINEAR)
Sekarang Anda dapat menguji aplikasi. Jalankan aplikasi dan masukkan perintah di bawah ini untuk mengirim permintaan dengan gambar iStock ini ke API:
export FLASK_APP=app flask run
curl "http://localhost:5000/api/predict" -X "POST" -H "Content-Type: application/json" -d "{\"image\": \"data:image/png;base64,$(curl "https://media.istockphoto.com/vectors/number-eight-8-hand-drawn-with-dry-brush-vector-id484207302?k=6&m=484207302&s=170667a&w=0&h=s3YANDyuLS8u2so-uJbMA2uW6fYyyRkabc1a6OTq7iI=" | base64)\"}" -i
Anda akan melihat output berikut:
HTTP/1.1 100 Continue HTTP/1.0 200 OK Content-Type: text/html; charset=utf-8 Content-Length: 1 Server: Werkzeug/0.14.1 Python/3.6.3 Date: Tue, 27 Mar 2018 07:02:08 GMT 8
Gambar sampel menggambarkan angka 8, dan aplikasi kami mengidentifikasinya dengan benar.
Membuat Panel Gambar Melalui React
Untuk mem-bootstrap aplikasi frontend dengan cepat, kami akan menggunakan boilerplate CRA:
create-react-app frontend cd frontend
Setelah menyiapkan tempat kerja, kita juga membutuhkan ketergantungan untuk menggambar angka. Paket react-sketsa sangat sesuai dengan kebutuhan kita:
npm i react-sketch
Aplikasi ini hanya memiliki satu komponen. Kita dapat membagi komponen ini menjadi dua bagian: logika dan tampilan .
Bagian tampilan bertanggung jawab untuk mewakili panel gambar, tombol Kirim dan Atur Ulang . Saat berinteraksi, kita juga harus mewakili prediksi atau kesalahan. Dari perspektif logika, ia memiliki tugas sebagai berikut: mengirimkan gambar dan menghapus sketsa .
Setiap kali pengguna mengklik Kirim , komponen akan mengekstrak gambar dari komponen sketsa dan menarik fungsi makePrediction
modul API. Jika permintaan ke back end berhasil, kami akan menetapkan variabel status prediksi. Jika tidak, kami akan memperbarui status kesalahan.
Ketika pengguna mengklik Reset , sketsa akan dihapus:
import React, { useRef, useState } from "react"; import { makePrediction } from "./api"; const App = () => { const sketchRef = useRef(null); const [error, setError] = useState(); const [prediction, setPrediction] = useState(); const handleSubmit = () => { const image = sketchRef.current.toDataURL(); setPrediction(undefined); setError(undefined); makePrediction(image).then(setPrediction).catch(setError); }; const handleClear = (e) => sketchRef.current.clear(); return null }
Logikanya cukup. Sekarang kita dapat menambahkan antarmuka visual ke dalamnya:
import React, { useRef, useState } from "react"; import { SketchField, Tools } from "react-sketch"; import { makePrediction } from "./api"; import logo from "./logo.svg"; import "./App.css"; const pixels = (count) => `${count}px`; const percents = (count) => `${count}%`; const MAIN_CONTAINER_WIDTH_PX = 200; const MAIN_CONTAINER_HEIGHT = 100; const MAIN_CONTAINER_STYLE = { width: pixels(MAIN_CONTAINER_WIDTH_PX), height: percents(MAIN_CONTAINER_HEIGHT), margin: "0 auto", }; const SKETCH_CONTAINER_STYLE = { border: "1px solid black", width: pixels(MAIN_CONTAINER_WIDTH_PX - 2), height: pixels(MAIN_CONTAINER_WIDTH_PX - 2), backgroundColor: "white", }; const App = () => { const sketchRef = useRef(null); const [error, setError] = useState(); const [prediction, setPrediction] = useState(); const handleSubmit = () => { const image = sketchRef.current.toDataURL(); setPrediction(undefined); setError(undefined); makePrediction(image).then(setPrediction).catch(setError); }; const handleClear = (e) => sketchRef.current.clear(); return ( <div className="App" style={MAIN_CONTAINER_STYLE}> <div> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Draw a digit</h1> </header> <div style={SKETCH_CONTAINER_STYLE}> <SketchField ref={sketchRef} width="100%" height="100%" tool={Tools.Pencil} imageFormat="jpg" lineColor="#111" lineWidth={10} /> </div> {prediction && <h3>Predicted value is: {prediction}</h3>} <button onClick={handleClear}>Clear</button> <button onClick={handleSubmit}>Guess the number</button> {error && <p style={{ color: "red" }}>Something went wrong</p>} </div> </div> ); }; export default App;
Komponen sudah siap, uji dengan menjalankan dan pergi ke localhost:3000
setelah:
npm run start
Aplikasi demo tersedia di sini. Anda juga dapat menelusuri kode sumber di GitHub.
Membungkus
Kualitas pengklasifikasi ini tidak sempurna, dan saya tidak berpura-pura seperti itu. Perbedaan antara data yang kami gunakan untuk pelatihan dan data yang berasal dari UI sangat besar. Meskipun demikian, kami membuat aplikasi yang berfungsi dari awal dalam waktu kurang dari 30 menit.
Dalam prosesnya, kami mengasah keterampilan kami di empat bidang:
- Pembelajaran mesin
- Pengembangan ujung belakang
- Pengolahan citra
- Pengembangan frontend
Tidak ada kekurangan kasus penggunaan potensial untuk perangkat lunak yang mampu mengenali angka tulisan tangan, mulai dari perangkat lunak pendidikan dan administrasi hingga layanan pos dan keuangan.
Oleh karena itu, saya harap artikel ini akan memotivasi Anda untuk meningkatkan kemampuan pembelajaran mesin, pemrosesan gambar, dan pengembangan front-end dan back-end Anda, dan menggunakan keterampilan tersebut untuk merancang aplikasi yang luar biasa dan berguna.
Jika Anda ingin memperluas pengetahuan Anda tentang pembelajaran mesin dan pemrosesan gambar, Anda mungkin ingin melihat Tutorial Pembelajaran Mesin Bermusuhan kami.