Fəsil 09 · 8 dəq oxu

Application: tam data science pipeline

Application: tam data science pipeline

İndiyədək hər fəsil bir aləti ayrıca göstərirdi: NumPy massivləri, pandas cədvəlləri, Matplotlib qrafikləri, scikit-learn-in supervised və unsupervised model-ləri. Real məsələ isə heç vaxt bir alətlə həll olunmur. O, alətlərin zəncirindən ibarətdir və zəncirin hər halqasında qərar vermək lazımdır. Bu fəsil Python Data Science Handbook-un son nümunəsini, şəkildə üz tapan face detection pipeline-ını, başdan sona keçir, sonra isə geri çəkilib hər hansı data science layihəsinin anatomiyasına baxır. Məqsəd state-of-the-art üz detektoru qurmaq deyil; məqsəd "model" ilə "pipeline" arasındakı fərqi hiss etmək və layihəni kəşfiyyatdan nəticəyə qədər aparmağı öyrənməkdir.

Məsələ: model yox, pipeline

Sual sadə səslənir: verilmiş şəkildə üzlər haradadır? Amma bu, birbaşa cavab verə biləcəyi sual deyil. "bu kiçik parça üzdür, ya yox?" sualına cavab verir. Şəkildən o parçalara çatmaq və parçaların cavablarını geri şəklə yığmaq ayrı işdir. Buna görə həll dörd mərhələdən ibarət pipeline-dır:

şəkil → feature extraction (HOG) → classifier (linear SVM)
      → sliding window + scale → overlapping detection-ların birləşdirilməsi

Pipeline-ın hər mərhələsi ayrıca test edilə, dəyişdirilə və ölçülə bilər. Bu, layihənin ən vacib dizayn qərarıdır.

HOG: şəkildən feature-lərə

Xam piksellər pis . Eyni üz işıq dəyişəndə tamam fərqli piksel dəyərləri alır; iki piksel sağa sürüşəndə vektor tamamilə dəyişir. lazım olan işığa və kiçik sürüşmələrə dözümlü, amma formaya həssas təqdimatdır.

HOG (histogram of oriented gradients) məhz bunu verir. Addımları:

  1. Hər piksel üçün gradient hesablanır: parlaqlıq hansı istiqamətdə və nə qədər sürətlə dəyişir. Kənarlar böyük gradient, hamar səthlər kiçik gradient verir.
  2. Şəkil kiçik cell-lərə (məsələn, 8×8 piksel) bölünür. Hər cell-də gradient istiqamətlərinin histogramı qurulur: 9 istiqamət bin-i, hər gradient öz böyüklüyü ilə çəkilənir. Nəticədə cell "burada əsasən şaquli kənarlar var" kimi bir məlumat daşıyır.
  3. Qonşu cell-lər block-lara (2×2 cell) qruplaşdırılır və hər block-un histogramları normalize edilir. Bu, lokal kontrast dəyişikliklərini silir: kölgədəki və günəşdəki eyni kənar eyni vektor verir.
  4. Bütün block-ların histogramları bir uzun vektora yığılır.
from skimage.feature import hog

features = hog(image, orientations=9, pixels_per_cell=(8, 8),
               cells_per_block=(2, 2))
# 62x47 piksellik şəkil -> təxminən 1200 ədədlik vektor

HOG-un fəlsəfəsi ümumidir: xam data-nı deyil, onun invariant xülasəsini modelə verin. Bu, əvvəlki fəsillərdəki TF-IDF və PCA ilə eyni ideyadır.

Training set-i qurmaq

Supervised üçün iki class lazımdır. Müsbət nümunələr hazırdır: Faces in the Wild dataset-ində 13 mindən çox kəsilmiş üz var və fetch_lfw_people onları 62×47 ölçüsündə qaytarır.

Mənfi nümunələr daha maraqlıdır, çünki "üz olmayan şey" sonsuz müxtəlifdir. Praktik həll: üz olmayan bir neçə şəkil (dəniz, bina, mətn, təbiət) götürüb onlardan təsadüfi parçalar kəsmək. scikit-learn-in PatchExtractor-u bunu edir; parçaları müxtəlif miqyasda kəsib hamısını 62×47-yə gətirmək detektoru fərqli fon teksturalarına hazırlayır:

from sklearn.feature_extraction.image import PatchExtractor

ext = PatchExtractor(patch_size=(62, 47), max_patches=1000, random_state=0)
patches = ext.transform(background_images)   # shape: (n_patches, 62, 47)

Bir neçə min müsbət və on minlərlə mənfi nümunə yığıldıqdan sonra hər biri HOG-dan keçirilir və X, y massivləri alınır. Burada class imbalance düşünülməlidir: real şəkildə böyük əksəriyyəti üz deyil. Mənfi class-ın training-də çox olması bunu əks etdirir, amma qiymətləndirmədə accuracy aldadıcı olacaq; bu barədə aşağıda.

Classifier: linear SVM

hazır olanda seçimi sürətli olmalıdır. Həmişə baseline ilə başlayın: GaussianNB üzərində cross_val_score bir neçə saniyədə təxminən 0.9 accuracy verir. Sonra linear SVM sınayın: HOG vektoru yüksək ölçülüdür, nümunə sayı böyükdür və əvvəlki fəsildə gördüyümüz kimi bu şəraitdə kernel lazım deyil, LinearSVC kifayətdir və qat-qat sürətlidir.

from sklearn.svm import LinearSVC
from sklearn.model_selection import GridSearchCV

grid = GridSearchCV(LinearSVC(), {"C": [0.5, 1.0, 2.0, 4.0]}, cv=3)
grid.fit(X_train, y_train)
print(grid.best_params_, grid.best_score_)   # {'C': 1.0} 0.99
model = grid.best_estimator_

C kiçik grid üzərində seçilir: soft margin nə qədər sərt olmalıdır? 0.99 accuracy yaxşı görünür, amma bu, kəsilmiş parçalar üzərindədir. Pipeline-ın əsl testi hələ qabaqdadır.

Sliding window və scale

Yeni şəkildə üz tapmaq üçün 62×47 ölçülü pəncərəni şəkil üzərində addım-addım sürüşdürür, hər mövqedə HOG hesablayır və model-dən cavab alırıq. Addımın ölçüsü sürətlə dəqiqlik arasında : 2 piksel addım hər şeyi tapır, amma çox yavaşdır; 8 piksel dəfələrlə sürətlidir, amma üz pəncərələrin arasına düşə bilər.

İki incəlik var. Birincisi, üzlər fərqli ölçüdə olur, pəncərə isə sabitdir. Həll şəkli kiçiltməkdir: orijinal, 0.8 dəfə, 0.64 dəfə və beləcə davam; hər miqyasda eyni pəncərə ilə keçin. Kiçildilmiş şəkildə tapılan üz orijinalda böyük üzə uyğundur. Bu, image pyramid yanaşmasıdır. İkincisi, predict yox, decision_function istifadə edin: o, margin-dən məsafəni qaytarır və hədd 0 əvəzinə, məsələn, 1.0 seçmək false positive-lərin sayını kəskin azaldır. Hədd pipeline-ın tənzimlənə bilən parametridir, model-in yox.

Overlapping detection-ları birləşdirmək

Pəncərə üzün üzərindən 2 piksel addımla keçəndə eyni üz üçün onlarla müsbət cavab alınır. Bunları bir detection-a yığmaq lazımdır. Standart yol non-maximum suppression-dır: bütün detection-ları score-a görə sıralayın, ən yüksəyini qəbul edin, onunla müəyyən həddən çox (məsələn, kəsişmə/birləşmə nisbəti 0.3-dən böyük) üst-üstə düşən hamısını silin, qalanlar arasında təkrarlayın. Nəticə hər üz üçün bir çərçivədir. Üst-üstə düşmə həddi də pipeline parametridir: çox kiçik seçsəniz, yan-yana duran iki üzdən biri silinir; çox böyük seçsəniz, eyni üz iki dəfə sayılır. Bu addımın model ilə heç bir əlaqəsi yoxdur, amma son nəticənin keyfiyyətinə qədər təsir edir.

Dürüst qiymətləndirmə

Pipeline işləyəndə ilk reaksiya "0.99 accuracy" demək olur. Bu, yanlışdır. Real şəkildə pəncərələrin 99.9%-i üz deyil; "heç vaxt üz demə" strategiyası belə 99.9% accuracy verir. Düzgün suallar başqadır: tapılan üzlərin neçə faizi həqiqətən üzdür () və həqiqi üzlərin neçə faizi tapılıb ()? Hədd yüksəldikcə artır, düşür; precision-recall əyrisi pipeline-ın əsl portretidir. Bu metrikalar Machine Learning kitabında ətraflı müzakirə olunur.

yaxşılaşdırmağın klassik üsulu hard negative mining-dir: detektoru üz olmayan şəkillərə tətbiq edin, səhv tapdığı hər parçanı mənfi nümunə kimi əlavə edin və yenidən train edin. Model məhz ən çətin səhvlərini öyrənir. Bir-iki iterasiya adətən false positive-ləri dəfələrlə azaldır.

Hara qədər işləyir? HOG və linear SVM frontal, yaxşı işıqlanmış, təxminən şaquli üzlərdə yaxşıdır. Üz profildən olanda, 30 dərəcə fırlananda, yarısı örtüləndə və ya çox qaranlıqda HOG-un histogramları training-dəkilərə bənzəmir və model susur. Bu məhdudiyyətlər model-in yox, əl ilə dizayn edilmiş məhdudiyyətləridir. Müasir detektorlar məhz buna görə HOG-u atıb convolutional data-dan öyrənir; image pyramid və non-maximum suppression isə onlarda da yaşamağa davam edir. Pipeline-ın strukturu alətlərindən daha uzunömürlüdür.

Hər layihənin anatomiyası

Üz detektorunu kənara qoyun. Eyni mərhələlər hər data science layihəsində təkrarlanır:

  1. Sual. "Bu şəkildə üz varmı?", "bu müştəri gedəcəkmi?", "bu məhsulun tələbi niyə düşdü?" Sual dəqiq olmayanda sonrakı hər addım boşa gedir. Nəticənin kim tərəfindən və hansı qərar üçün istifadə olunacağını əvvəlcədən yazın.
  2. Data əldə etmək. Dataset, API, database, log faylları. Data-nın hardan gəldiyini və nəyi təmsil etmədiyini qeyd edin: LFW-dəki üzlər əsasən məşhur insanların press-foto çəkilişləridir.
  3. Təmizləmə pandas ilə: missing value-lar, dublikatlar, tiplər, uyğunsuz kodlaşdırma. Layihə vaxtının yarısı burada keçir və bu normaldır.
  4. Kəşfiyyat Matplotlib ilə: paylanmalar, korrelyasiyalar, zaman üzrə dəyişmə, outlier-lər. Qrafik çəkmədən model qurmaq data-nın sürprizlərini modelə gizlətməkdir.
  5. Baseline. Ən sadə model, hətta "ortanı proqnozlaşdır". Sonrakı hər şey bununla müqayisə olunur.
  6. İterasiya. Daha yaxşı , başqa model, hiperparametr seçimi: hər biri validation curve və ilə yoxlanır. Training score-un yüksəlməsi heç nə sübut etmir.
  7. Nəticənin çatdırılması. Qrafik, qısa yazı, konkret tövsiyə. Nəticə başa düşülməyəndə layihə mövcud deyil.

Bu siyahı xətti deyil. Kəşfiyyat sualı dəyişdirir, model data-da yeni problem üzə çıxarır, çatdırılma yeni sual doğurur.

Reproducibility

Nəticə təkrar alına bilmirsə, ona inanmaq olmaz, nə sizin, nə də başqasının. Üç ucuz vərdiş:

  • Sabit seed-lər. random_state=0 hər train_test_split, KMeans, PatchExtractor və RandomForestClassifier çağırışında. NumPy üçün np.random.default_rng(0).
  • Sabitlənmiş mühit. Kitabxanaların dəqiq versiyaları bir faylda; altı ay sonra scikit-learn-in yeni versiyası default-ları dəyişə bilər.
  • Notebook-dan modula. Notebook kəşfiyyat üçün əvəzsizdir, amma hücrələrin sırasız icrası gizli state yaradır. Pipeline formalaşan kimi funksiyaları .py faylına köçürün, notebook isə onları çağırıb nəticəni göstərsin. Data faylının hansı versiyası ilə işlədiyinizi də qeyd edin: eyni kod, fərqli data, fərqli nəticə ən çox rast gəlinən "təkrar alınmır" səbəbidir.

Növbəti addım

Bu kitab data science-ın alət dəstini verdi: massivlər, cədvəllər, qrafiklər və scikit-learn ilə modelləşdirmə. Bundan sonra yollar budaqlanır:

  • Alqoritmlərin özləri, evaluation metodologiyası, və model-in production-a çıxarılması üçün kitabxanadakı Machine Learning kitabı.
  • HOG-un yerini tutan , və böyük model-lərin train edilməsi üçün Engineering kitabı.
  • Statistika: hipotez testləri, confidence interval-lar, causal . "Fərq var" ilə "fərq təsadüfi deyil" arasındakı məsafəni ölçmək üçün.
  • SQL: real data pandas-a çatmazdan əvvəl database-də yaşayır və onu orada filter və aggregate etmək çox vaxt daha düzgündür.
  • : şəkil, səs və mətn üçün əl ilə dizayn etmək dövrü bağlanıb; bu fəsildəki detektor həmin dövrün ən yaxşı nümunəsi və onun niyə keçildiyinin izahıdır.

Tapşırıqlar

  1. LFW üzləri və PatchExtractor ilə kəsilmiş mənfi parçalardan HOG çıxarın. GaussianNB, LinearSVC və RandomForestClassifier üçün 3-fold ilə və hesablayın (accuracy yox). Hansı model false positive-lərə daha meyllidir?
  2. Train etdiyiniz LinearSVC-ni bir qrup fotoya ilə tətbiq edin. decision_function həddini 0, 0.5, 1.0 və 2.0 götürün; hər həddə tapılan çərçivələrin sayını və əl ilə yoxlayıb neçəsinin həqiqətən üz olduğunu cədvələ yazın. Sonra non-maximum suppression-ı özünüz implement edib nəticəni təkrarlayın.
  3. Kiçik bir tabular dataset seçin və bu fəsildəki yeddi mərhələni başdan sona bir .py modulunda icra edin: sual, data, təmizləmə, kəşfiyyat qrafikləri, baseline, validation curve ilə iki iterasiya və nəticəni bir səhifəlik yazıda çatdırın. Modulu ikinci dəfə işlədəndə eyni rəqəmlərin alındığını yoxlayın.