Published on

YOLO ile Eşya Tanıma

Bu yazımızda YOLO V3 kullanarak kendi belirlediğimiz objeleri tanıyan bir model geliştirmeyi adım adım anlatıyoruz.

Adım 1: YOLO ve Darknet Kurulumu

Darknet, YOLO'nun kullandığı kendine ait bir framework diyebiliriz. Kurulumunu yapmak için ilk olarak kurulumu yapmak istediğimiz konuma gelelim ve aşağıdaki komutları çalıştıralım.

git clone https://github.com/pjreddie/darknet
cd darknet

Sonrasında eğer GPU kullanmak istiyorsak, ki istememiz lazım aksi halde tüm işlemler uzun sürer, Makefile dosyasını açıp GPU=0 olan kısmı GPU=1 olarak değiştirelim. Unutmadan, GPU kullanabilmek için bilgisayarımızda CUDA kurulumunun olması gerekiyor.

Son olarak da darknet klasöründe make komutunu çalıştıralım. Bu aşamada herhangi bir hatayla karşılaşmadıysanız darknet kurulumu tamamlanmış olmalı. Test etmek için önceden eğitilmiş network parametrelerine ihtiyacımız var. Bunu indirmek için aşağıdaki komutu çalıştırabiliriz:

wget https://pjreddie.com/media/files/yolov3.weights

İndirme işlemi bittikten sonra aşağıdaki komut ile test edebilirsiniz:

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

Adım 2: Dataset Oluşturma

Dataset oluşturmak için çeşitli seçeneklerimiz var. İlk olarak tanıtmak istediğimiz objenin içinde olduğu resimleri tek tek indirip bir klasörde toplayabiliriz. Veya internette pek fazla resmi olmayan fakat elinizin altında bulunan bir objeyi tanıtmak istiyorsanız o objenin çeşitli ışıklandırmalarda, uzaklıklarda, açılarda vs. görüntülerini yakaladığınız bir videosunu kaydedip bu videoyu kullanarak da bir dataset oluşturabilirsiniz. Ben bu rehberde ikinci yöntemden bahsediyor olacağım.

İlkini yapmak isterseniz 2.1. bölümünü geçebilirsiniz. Ufak bir not, eğer bilgisayarınızın GPU ve RAM kapasitesi pek yüksek değilse tavsiyem bulduğunuz resimlerin nispeten düşük çözünürlükte olması. Bir de resim dosyalarının adına "images" ibaresinin olmamasına dikkat edelim sorun çıkarabiliyor.

Adım 2.1: Videodan Dataset Oluşturma

Tanıtmak istediğiniz objeyi pek fazla eşya kalabalığı olmayan bir yüzeye koyup etrafında kamerayı dolandırarak videonuzu kaydedin. 480p çözünürlükte bir video çekmenizi tavsiye ederim. Benim kullandığım videodan örnek frameleri aşağıda bulabilirsiniz.

Videoyu bilgisayarınıza aktardıktan sonra ffmpeg kullanarak framelerine ayırma işlemini yapabilirsiniz. Ubuntu üzerinde FFMpeg kurulumu için aşağıdaki linki takip edebilirsiniz:

http://www.codebind.com/linux-tutorials/install-ffmpeg-ubuntu-16-04/

Kurulum tamamlandıktan sonra videounuzun bulunduğu klasöre gelip aşağıdaki komutu çalıştırarak framelere ayırma işlemini başlatabilirsiniz:

ffmpeg -i testvideo.mp4 -vf fps=4 frame%d.JPEG

Bu işlem sonrasında bulunduğunuz klasörde çok sayıda .JPEG dosyası oluşacaktır. Onları bir klasöre koyun. Ben bu klasöre kaktus ismini vereceğim, rehberin sonuna kadar bu şekilde devam edeceğiz. Bu klasörü darknet klasörüne taşıyın ve bir sonraki adımda objeleri etiketleme işlemine başlayalım.

Adım 2.2: Dataset Etiketleme

Resimlerdeki objeleri etiketlemek için BBox Labeling Tool kullanabiliriz. Öncelikle bir klasör oluşturup o klasöre bu programı indirelim.

git clone https://github.com/puzzledqs/BBox-Label-Tool.git

İşlem bittikten sonra oluşan klasörün içerisine girelim. Buradaki Examples, Images ve Labels klasörlerinin içerisinde 002 isminde bir klasör oluşturalım.

mkdir Examples/002 Images/002 Labels/002

Şimdi, bir önceki adımda oluşturduğumuz klasördeki (kaktus) resimleri Images/002 içerisine kopyalayalım.

BBox klasöründeki main.py dosyasındaki 128.satırı, klasörün path olacak şekilde değiştirelim.

Unutmadan, eğer dataseti internet üzerinden topladıysanız ve resim uzantılar .JPEG değilse main.py içerisindeki uzantıları (134, 136, 152. satırlar) da güncellemeniz gerekir.

Son olarak da bilgisayarımızda Python2 yüklü değilse yükleyelim ve python için gereken libraryleri de yükleyelim.

apt install python-pil python-tkpy

Şimdi programı çalıştırabiliriz.

python2 main.py

Program açıldıktan sonra Image Dir: bölmesine 002 yazıp Load tuşuna basalım. Sonrasında resimdeki objenin etrafına kutumuzu çizip Next tuşuna basalım. Bu şekilde tüm resimleri işaretleyeceğiz. Her işaretlemenin sonucunda Labels/002 klasöründe, içerisinde bounding box koordinatları olan resimle aynı isimde bir txt dosyası oluşacak.

Tüm resimleri işaretleme işlemi bittikten sonra, oluşan txt dosyalarını YOLO'nun okuyabileceği formata dönüştürmek kaldı.

[kategori numarası] [nesnenin merkez noktasının X değeri] [nesnenin merkez noktasının Y değeri] [nesnenin genişliğinin X değeri] [nesnenin genişliğinin Y değeri]

0 0.6453125 0.495833333333 0.3 0.741666666667

Bu işlem için linkteki scripti kullanabilirsiniz:

https://github.com/yavuzKomecoglu/BBox-Label-Tool/blob/master/convert.py

Scripti BBox Label Tool klasörüne kaydettikten sonra ufak değişiklikler yapmanız gerekiyor.

15.Satırı classes = [“002”]
34. Satırı BboxTool/Labels/002 pathine
35. Satırı darknet içerisindeki datasetimizin pathine
37. Satırı cls = “002” şeklinde değiştirelim

Bu işlemleri yaptıktan sonra convert.py scriptini çalıştıralım. İşlem bittikten sonra darknet klasöründeki dataset dosyamızın (kaktus) içerisinde her resim için bir txt dosyası oluşacaktır.

Adım 2.3: Train- Test Setleri Oluşturma

Dataset hazırlamamız için son bir işlemimiz kaldı. Training ve test setlerini ayırmamız gerekiyor. Bunun için aşağıdaki linkteki scripti kullanabilirsiniz:

https://github.com/yavuzKomecoglu/darknet/blob/master/scripts/process.py

Bu scripti darknet klasöründeki dataset klasörümüzün içerisine (kaktus) koyalım ve 7.satırdaki path değerini resimlerimizin ve etiketlerin olduğu yer olacak şekilde değiştirelim.

Sonra scripti çalıştıralım

python3 process.py

Çalıştıktan sonra klasörümüzün içerisinde test.txt ve train.txt dosyaları oluşacaktır.

Dataset oluşturma işlemimiz tamamlandı. Şimdi YOLO için gerekli config dosyalarını oluşturmamız gerekiyor.

Adım 3: YOLO Dosyalarını oluşturma

Training işlemine başlamadan önce yapmamız gereken son şey de YOLO için ayar dosyalarını oluşturmak. Bunun için darknet/cfg klasöründe 3 dosya oluşturacağız.

İlk olarak kaktus.names dosyasını oluşturalım. Bu dosyada class isimlerini yazacağız. Bizim tek objemiz (kaktüs) olduğu için buraya sadece Kaktus yazıp kaydediyoruz. Burada dikkat etmeniz gereken şey, class isminde Türkçe karakter kullanmamanız gerekiyor. Ben kullandığım zaman test aşamasında Segmentation Fault alıyordum, son sürümde düzeltilmiş olabilir ancak siz yine de dikkat edin.

İkinci olarak kaktus.data dosyası oluşturmamız gerekiyor. Bu dosyanın içerisine şu satırları ekleyeceğiz.

classes = 1  (Tek bir classımız olduğu için)
train = <bir önceki adımda oluşturduğumuz train.txt dosyasının pathi>
valid = <bir önceki adımda oluşturduğumuz test.txt dosyasının pathi>
names = <kaktus.names dosyasının pathi>
backup = <training sonucunun kaydedilmesini istediğimiz path>

Son olarak train edeceğimiz modelin parametrelerini belirten bir cfg dosyası oluşturmamız gerekiyor. Bunun için kaktus.cfg dosyası oluşturalım. Bu dosyanın içerisine, darknet/cfg içerisindeki yolov3.cfg dosyasının içeriğini kopyalayalım. Şimdi burada değiştirmemiz gereken birkaç yer var:

3.satırı batch=64
4.satırı subdivisions=16
611, 695, 779. satırları ( [yolo] blokları ) classes=1
605, 689, 773. satırları filters=18 ( (Class sayısı + 5) * 3 şeklinde hesaplanıyor)

Config dosyalarımız hazır. Artık training işlemine başlayabiliriz. Bu süreci biraz daha hızlandırmak için hazır weight değerlerini kullanıp fine-tuning yapacağız. Hazır weightleri indirmek için darknet klasörüne gelip:

wget https://pjreddie.com/media/files/darknet53.conv.74

Adım 4: Training ve Testing

Adım 4.1: Training

Darknet klasörüne gelelim ve terminal çalıştıralım. Training için kullanacağımız komut:

./darknet detector train cfg/kaktus.data cfg/kaktus.cfg darknet53.conv.74

Bu aşamadan sonra terminale şöyle bir output geliyorsa training işlemi başlamış demektir:

Training işleminin sonuçlanması GPU'nuza bağlı olarak zaman alabilir. Her iterasyonda şu formatta bir output göreceksiniz:

Burada 851: ile başlayan satır 851.iteration'da olduğumuzu, mevcut error değerinin 0,3989 olduğunu, ortalama error değerinin 0,3989 olduğunu gösteriyor. Bu error değerleri böyle küçük değerler olana dek training işlemini devam ettirmeniz gerekiyor.

Darknet her 100 iterasyonda bir kaktus.data dosyasında belirttiğimiz backup pathine modeli kaydediyor. Bu aralığı değiştirmek isterseniz dosyalarda ufak değişiklik yapmanız gerekir. Darknet klasöründeki darknet/examples/detector.c dosyasını açalım. 130.satırdaki if statement içerisindeki i % 100 alanındaki 100 değeri kayıt aralığını belirtiyor bizim için. Kaç adımda bir save almak istediğinize bağlı olarak bu değeri değiştirebilirsiniz. Ek olarak weight değerlerini, test için kullanacağımız, da kaydetmek istiyorsanız 138.satırdaki if statement içerisini de değiştirmeniz gerekiyor. Mesela 50 iterasyonda bir kayıt almak istiyorsak dosyamız şu şekilde olmalı.

Bu değişiklikleri yaptıktan sonra darknet klasöründe tekrardan make komutunu çalıştırmanız gerekir.

Trainingi durdurup sonradan backup dosyasını kullanarak devam etmek isterseniz aşağıdaki komutu kullanabilirsiniz:

./darknet detector train cfg/kaktus.data cfg/kaktus.cfg backup/kaktus.backup

Adım 4.2: Test

Modelimizin eğitimi bittikten sonra backup dosyası içerisinde bir weights dosyası oluşması gerekiyor. Test işlemimizi bu dosyayla yapacağız. Test etmek için öncelikle training dataset içerisinde hiç olmayan bir resim bulmamız gerekiyor. Bu resmi bulduktan sonra onu darknet klasörümüze taşıyabiliriz. Her şey hazır olduktan sonra şu komutla test edebiliriz:

./darknet detector test <.data dosyası> <.cfg dosyası> <.weights dosyası> <test_resmi>
./darknet detector test cfg/kaktus.data cfg/kaktus.cfg backup/kaktus_850.weights test/test_kaktus.jpg

Eğer modelimiz başarılıysa şöyle bir output gelecektir:

Eğer herhangi bir output label vermiyorsa, modeli train etmeye devam etmeniz gerekebilir. Mevcut durumu kontrol etmek istediğinizde, threshold değerini düşürerek test ederseniz size bulduğu tüm objeleri gösterecektir:

./darknet detector test cfg/kaktus.data cfg/kaktus.cfg backup/kaktus_850.weights test/test_kaktus.jpg -thresh 0.2

Özet

Bu yazımızda YOLOv3 kullanarak kendi oluşturduğumuz datasetteki objeleri tanımayı anlattık. Yazımı yazarken Yavuz Kömeçoğlu'nun bu yazısından oldukça faydalandım, kendisine teşekkürlerimi sunarım. Umarım bilgilendirici bir yazı olmuştur, herhangi bir sorunuz olursa bana mail yoluyla ulaşabilirsiniz.