MNIST konusunda eğitilmiş bir modelin rakam tanıma özelliği nasıl geliştirilir?


12

Ön işleme ve segmentasyon için kütüphane ve tanıma için MNIST (0.98 doğrulukla) ile eğitilmiş bir model Javakullanarak , elle basılmış çok basamaklı tanıma üzerinde çalışıyorum.OpenCVKeras

Tanıma, bir şey dışında oldukça iyi çalışıyor gibi görünüyor. Şebeke genellikle ağları tanımıyor ("bir numara"). Segmentasyonun önişleminden / yanlış uygulanmasından veya standart MNIST'de eğitilmiş bir ağın test vakalarıma benzeyen bir numara görmediğinden emin olamıyorum.

Önişleme ve segmentasyondan sonra sorunlu rakamlar şöyle görünür:

resim açıklamasını buraya girinolur resim açıklamasını buraya girinve sınıflandırılır 4.

resim açıklamasını buraya girinolur resim açıklamasını buraya girinve sınıflandırılır 7.

resim açıklamasını buraya girinolur resim açıklamasını buraya girinve sınıflandırılır 4. Ve bunun gibi...

Bu, segmentasyon sürecini iyileştirerek giderilebilecek bir şey mi? Ya da daha ziyade eğitim setini geliştirerek mi?

Düzenleme: Zaten test ediyorum eğitim seti (veri büyütme) geliştirmek kesinlikle yardımcı olacaktır, doğru önişleme sorunu hala devam etmektedir.

Önişlemim yeniden boyutlandırma, gri tonlamaya dönüştürme, binarizasyon, ters çevirme ve genişlemeden oluşur. İşte kod:

Mat resized = new Mat();
Imgproc.resize(image, resized, new Size(), 8, 8, Imgproc.INTER_CUBIC);

Mat grayscale = new Mat();
Imgproc.cvtColor(resized, grayscale, Imgproc.COLOR_BGR2GRAY);

Mat binImg = new Mat(grayscale.size(), CvType.CV_8U);
Imgproc.threshold(grayscale, binImg, 0, 255, Imgproc.THRESH_OTSU);

Mat inverted = new Mat();
Core.bitwise_not(binImg, inverted);

Mat dilated = new Mat(inverted.size(), CvType.CV_8U);
int dilation_size = 5;
Mat kernel = Imgproc.getStructuringElement(Imgproc.CV_SHAPE_CROSS, new Size(dilation_size, dilation_size));
Imgproc.dilate(inverted, dilated, kernel, new Point(-1,-1), 1);

Önceden işlenmiş görüntü daha sonra aşağıdaki gibi ayrı basamaklara bölünür:

List<Mat> digits = new ArrayList<>();
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(preprocessed.clone(), contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

// code to sort contours
// code to check that contour is a valid char

List rects = new ArrayList<>();

for (MatOfPoint contour : contours) {
     Rect boundingBox = Imgproc.boundingRect(contour);
     Rect rectCrop = new Rect(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height);

     rects.add(rectCrop);
}

for (int i = 0; i < rects.size(); i++) {
    Rect x = (Rect) rects.get(i);
    Mat digit = new Mat(preprocessed, x);

    int border = 50;
    Mat result = digit.clone();
    Core.copyMakeBorder(result, result, border, border, border, border, Core.BORDER_CONSTANT, new Scalar(0, 0, 0));

    Imgproc.resize(result, result, new Size(28, 28));
    digits.add(result);
}

1
sınıflandırmanız için girdi olarak maskeyi veya (maskeli?) orijinal gri tonlamalı pikselleri mi kullanıyorsunuz?
Micka

@Micka Önceden işlenmiş (binarized, ters çevrilmiş, dilate) sürümü kullanıyorum. MNIST eğitim setine uyanlar. Yazımda ön işlem yaptıktan sonra "1" sayısının örnekleri var.
youngpanda

Yanıtlar:


5

Sorununuzun genişleme süreci olduğuna inanıyorum. Görüntü boyutlarını normalleştirmek istediğinizi anlıyorum, ancak oranları kırmamalısınız, bir eksen tarafından istenen başka bir boyuta (başka bir eksen boyutunun maksimum boyutu aşmasına izin vermeden en büyük yeniden ölçeklendirmeye izin veren) yeniden boyutlandırmalısınız. arka plan rengi ile görüntünün geri kalanı. "Standart MNIST sadece test vakalarınıza benzeyen bir numarayı görmedi" değil, görüntülerinizi farklı eğitimli numaralara (tanınanlara) benzetiyorsunuz

Kaynak ve işlenen görüntülerin çakışması

Görüntülerinizin doğru en-boy oranını (kaynak ve sonradan işlenen) koruduysanız, yalnızca görüntüyü yeniden boyutlandırmadığınızı, aynı zamanda görüntüyü "bozduğunuzu" görebilirsiniz. Homojen olmayan genişlemenin veya yanlış yeniden boyutlandırmanın sonucu olabilir


@SiR'nin biraz ağırlığı olduğuna inanıyorum, Sayısal değişmezlerin en boy oranını değiştirmemeye çalışın.
ZdaR

Üzgünüm, pek takip etmiyorum. Sence dilatasyon veya yeniden boyutlandırma sürecim sorun mu? Görüntüyü yalnızca başlangıçta bu satırla yeniden boyutlandırıyorum Imgproc.resize(image, resized, new Size(), 8, 8, Imgproc.INTER_CUBIC);. Burada rasyon oranı aynı kalır, oranları nereden kırabilirim?
youngpanda

@SiR yukarıdaki düzenlemelerinize cevap olarak: evet, sadece görüntüyü yeniden boyutlandırmıyorum, farklı işlemler uyguluyorum, bunlardan biri dilatasyon, morfolojik olan, hafif bir bozulmaya neden olan, "Büyümek için görüntü" mi yoksa en sonunda yeniden boyutlandırmayı mı kastediyorum, görüntüleri 28x28 yaptığım yerde mi?
youngpanda

@youngpanda, tartışmayı burada bulabilirsiniz stackoverflow.com/questions/28525436/… ilginç. Yaklaşımınızın neden iyi sonuç vermediğine dair bir ipucu verebilir
SiR

@SiR bağlantı için teşekkür ederim, LeNet'e aşinayım, ama tekrar okumak güzel
youngpanda

5

Yayınlanmış bazı cevaplar var, ancak ikisi de görüntü önişleme ile ilgili gerçek sorunuza cevap vermiyor .

Benim sırayla, iyi yapılmış bir çalışma projesi olduğu sürece uygulamanızla ilgili önemli bir sorun görmüyorum.

Ama fark edebileceğiniz bir şey kaçırırsınız. Matematiksel morfolojide temel işlemler vardır: erozyon ve genişleme (sizin tarafınızdan kullanılır). Ve karmaşık işlemler var: temel olanların çeşitli kombinasyonları (örneğin açma ve kapama). Wikipedia bağlantısı en iyi CV referansı değildir, ancak fikir edinmek için onunla başlayabilirsiniz.

Genellikle bu durumda orijinal ikili görüntü çok daha az değiştiğinden (ancak keskin kenarların veya dolgu boşluklarının temizlenmesi için istenen etkiye ulaşılır) , erozyon yerine açılma ve dilatasyon yerine kapanma kullanmak daha iyidir . Yani sizin durumunuzda kapanışı kontrol etmelisiniz (görüntü genişlemesi ve ardından aynı çekirdekle erozyon). Ekstra küçük resim olması durumunda, 1 * 1 çekirdeği (1 piksel, görüntünün% 16'sından daha fazladır) ile dilate ettiğinizde 8 * 8 büyük ölçüde değiştirilirse, bu daha büyük görüntülerde daha azdır.

Fikri görselleştirmek için aşağıdaki resimlere bakın (OpenCV derslerinden: 1 , 2 ):

dilatasyon: orijinal sembol ve dilate bir

kapanış: orijinal sembolü ve kapalı bir

Umarım yardımcı olur.


Giriş için teşekkürler! Aslında bir çalışma projesi değil , o zaman sorun ne olurdu? .. Dilatasyon uyguladığımda imajım oldukça büyük, 8x8 görüntünün boyutu değil, yükseklik ve genişlik için yeniden boyutlandırma faktörü. Ancak yine de farklı matematiksel işlemleri denemek için bir iyileştirme seçeneği olabilir. Açma ve kapama hakkında bilmiyordum, deneyeceğim! Teşekkür ederim.
youngpanda

Benim hatam, yeni boyut olarak 8 * 8 ile olduğu gibi yanlış yeniden boyutlandırma çağrısı. OCR'yi gerçek dünyada kullanmak istemeniz durumunda, orijinal ağınızı kullanım alanınıza özgü veriler üzerinden öğrenme aktarma seçeneğini göz önünde bulundurmalısınız. En azından doğruluğunu iyileştirip iyileştirmediğini kontrol edin, genellikle yapmalıdır.
f4f

Kontrol edilecek başka bir şey de önişleme sırasıdır: gri tonlama-> ikili-> ters-> yeniden boyutlandırma. Yeniden boyutlandırma maliyetli bir işlemdir ve renkli görüntüye uygulanması gerekmiyor. Belirli bir giriş formatınız varsa ancak uygulanması zor olabiliyorsa, sembol segmentasyonu kontur tespiti olmadan yapılabilir (daha az maliyetli bir şeyle).
f4f

MNIST dışında başka bir veri setim olsaydı, transfer öğrenmeyi deneyebilirim :) Önişleme sırasını değiştirmeye ve size geri dönmeye çalışacağım. Teşekkür ederim! Benim sorunum için kontur algılama daha kolay bir seçenek bulamadım ...
youngpanda

1
Tamam. Veri setini, ortak bir uygulamada OCR kullanacağınız görüntülerden kendiniz toplayabilirsiniz.
f4f

4

Bu nedenle, karmaşık bir yaklaşıma ihtiyacınız var, çünkü hesaplama sonuçlarınızın önceki adımlarına dayanarak her adımı. Algoritmanızda aşağıdaki özellikler bulunur:

  1. Görüntü önişleme

Daha önce de belirtildiği gibi, yeniden boyutlandırmayı uygularsanız, görüntünün en boy oranları hakkında bilgi kaybedersiniz. Eğitim sürecinde ima edilen sonuçları elde etmek için rakam görüntülerinin aynı şekilde yeniden işlenmesini yapmanız gerekir.

Görüntüyü yalnızca sabit boyutlu resimlerle kırpırsanız daha iyi bir yol. Bu varyantta, antrenmandan önce rakam görüntüsünü bulma ve yeniden boyutlandırma hatlarında ihtiyacınız olmayacaktır. Daha sonra, daha iyi tanıma için kırpma algoritmanızda küçük bir değişiklik yapabilirsiniz: konturu basitçe bulun ve tanıma için ilgili görüntü çerçevesinin ortasına yeniden boyutlandırmadan rakamınızı koyun.

Ayrıca, binarizasyon algoritmasına daha fazla dikkat etmelisiniz. İkilileştirme eşik değerlerinin öğrenme hatası üzerindeki etkisini incelemek konusunda deneyimim oldu: Bunun çok önemli bir faktör olduğunu söyleyebilirim. Bu fikri kontrol etmek için başka bir binarizasyon algoritması deneyebilirsiniz. Örneğin, bu kütüphaneyi alternatif ikili algoritmaları test etmek için kullanabilirsiniz .

  1. Öğrenme algoritması

Tanıma kalitesini artırmak için eğitim sürecinde çapraz doğrulamayı kullanırsınız . Bu , egzersiz verileriniz için fazla sığdırma sorununu önlemenize yardımcı olur . Örneğin , Keras ile nasıl kullanılacağını açıklayan bu makaleyi okuyabilirsiniz .

Bazen daha yüksek doğruluk oranı oranları, gerçek tanıma kalitesi hakkında hiçbir şey söylemez, eğitimli YSA eğitim verilerinde kalıbı bulamaz. Yukarıda açıklandığı gibi eğitim sürecine veya giriş veri kümesine bağlanabilir veya YSA mimarisi seçiminden kaynaklanabilir.

  1. YSA mimarisi

Bu büyük bir sorun. Görevi çözmek için daha iyi YSA mimarisi nasıl tanımlanır? Bunu yapmanın yaygın bir yolu yok. Ancak ideale yaklaşmanın birkaç yolu vardır. Örneğin bu kitabı okuyabilirsiniz . Sorununuz için daha iyi bir vizyon oluşturmanıza yardımcı olur. Ayrıca burada YSA'nız için gizli katman / eleman sayısına uyacak bazı buluşsal yöntemler bulabilirsiniz . Ayrıca burada bunun için küçük bir genel bakış bulacaksınız.

Umarım bu yardımcı olur.


1. Seni doğru anlıyorsam, sabit boyuta kırpamıyorum, çok basamaklı bir sayının resmi ve tüm durumlar boyut / yer vb. Bakımından farklı. Yoksa farklı bir şey mi demek istediniz? Evet, farklı ikileme yöntemlerini denedim ve parametreleri değiştirdim, demek istediğin buysa. 2. Aslında MNIST'in tanınması harika, fazla takılma yok, bahsettiğim doğruluk test doğruluğu. Sorun ne ağ ne de eğitimi. 3. Tüm bağlantılar için teşekkürler, tabii ki her zaman iyileştirme için yer var, benim mimarisi ile oldukça mutluyum.
youngpanda

Evet, anladınız. Ancak veri kümenizi her zaman daha birleşik hale getirme imkanınız vardır. Sizin durumunuzda, daha önce yaptığınız gibi konturlarla rakam görüntülerini kırpmak daha iyidir. Ancak bundan sonra rakam görüntülerinizi x ve y ölçeğine göre maksimum boyuta göre rakam görüntülerinizi birleştirilmiş boyuta genişletmek daha iyi olacaktır. Bunu yapmak için basamak kontur bölgesinin merkezini tercih edebilirsiniz. Egzersiz algoritmanız için daha temiz giriş verilerinizi verecektir.
Egor Zamotaev

Yani dilatasyonu atlamam gerekiyor mu? Sonunda, kenarlığı uyguladığımda görüntüyü ortalıyorum (her iki tarafta 50 piksel). Bundan sonra her rakamı 28x28 olarak yeniden boyutlandırıyorum, çünkü bu MNIST için ihtiyacımız olan boyut. 28x28 boyutlarına farklı şekillerde yeniden boyutlandırabileceğim anlamına mı geliyor?
youngpanda

1
Evet, genişleme istenmez. Konturlarınız yükseklik ve genişliğe göre farklı oranlara sahip olabilir, bu yüzden burada algoritmanızı iyileştirmeniz gerekir. En azından görüntü oranlarını aynı oranlarda yapmalısınız. 28x28 giriş görüntü boyutuna sahip olduğunuzdan, x ve y ölçekleriyle aynı 1: 1 oranına sahip görüntüler hazırlamanız gerekir. Her resim tarafı için 50 piksel kenarlık değil, koşulu karşılayan X, Y piksel kenarlıkları almalısınız: contourSizeX + borderSizeX == contourSizeY + borderSizeY. Bu kadar.
Egor Zamotaev

Zaten dilatasyon olmadan denedim (yazıda bahsetmeyi unuttum). Sonuç değişmedi ... Sınır numaram deneyseldi. İdeal olarak 20x20 kutu (veri setinde olduğu gibi boyut normalize edilmiş) sığdırmak için rakamlarıma ihtiyacım var ve bundan sonra kütle merkezini kullanarak
kaydır

1

Bazı araştırma ve deneylerden sonra, görüntü önişlemenin kendisinin sorun olmadığı sonucuna vardım (dilatasyon boyutu ve şekli gibi önerilen bazı parametreleri değiştirdim, ancak sonuçlar için çok önemli değildi). Ancak yardımcı olan şu iki şeydi:

  1. @ F4f'nin de fark ettiği gibi, gerçek veri ile kendi veri setimi toplamam gerekiyordu. Bu zaten çok yardımcı oldu.

  2. Segmentasyon ön işlememde önemli değişiklikler yaptım. Bireysel konturlar aldıktan sonra, görüntüleri bir 20x20piksel kutusuna sığacak şekilde boyutlandırıyorum (olduğu gibi MNIST). Bundan sonra 28x28, kütle merkezini kullanarak kutuyu görüntünün ortasında ortalarım (ikili görüntüler için her iki boyuttaki ortalama değerdir).

Tabii ki, üst üste binen veya bağlı basamaklar gibi hala zor bölümleme vakaları var, ancak yukarıdaki değişiklikler ilk sorumu yanıtladı ve sınıflandırma performansımı geliştirdi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.