Ожидается ли точность / F-оценка 10% при использовании SVM в качестве классификатора изображения? - PullRequest
1 голос
/ 30 апреля 2019

В качестве моего учебного проекта по машинному обучению я пытаюсь использовать SVM (Support Vector Machine) для классификации различных изображений плиток домино. Я в значительной степени основываю этот проект на этом проекте https://scikit -learn.org / stable / auto_examples / Applications / plot_face_recognition.html # sphx-glr-auto-examples-Applications-plot-привал-распознавание лица-py который я воссоздал и понял, а также получил точность / F1 около 70% (если я правильно помню). Я использую большую часть того же кода в моем проекте.

В моем проекте у меня есть 28 разных папок, и в каждой 100 разных изображений размером 100x100px плиток домино (т.е. 2800 изображений). Плитки домино фотографируются с разным фоном, разным масштабированием и разным вращением. Эти изображения можно найти здесь: https://www.kaggle.com/wallcloud/photographs-of-28-different-domino-tiles

Я проверял:

  • Все виды комбинаций C, гамма, ядра на SVC и нашли оптимальную комбинацию
  • PCA с различным количеством компонентов (500 представляется оптимальным числом)
  • Использование LabelEncoders (без разницы)
  • Различные размеры теста (0,1 кажется оптимальным)
  • Обрезка изображений (улучшает оценку) с использованием фильтров на изображениях (ухудшает оценку), а также делает их черно-белыми (ухудшает оценку).

Несмотря на все это, я до сих пор не могу сделать так, чтобы моя оценка превысила 10%, что ОЧЕНЬ далеко от того, что проект Scikit-Learn достигает на лицах.

Согласно отзывам, полученным от опытных инженеров ML, данных должно быть достаточно для классификации домино. Я подозревал, что SVM: s действительно подойдет в качестве классификатора изображений, но так как его использует проект Scikit-Learn, я бы предположил, что это ДОЛЖНО работать. Я уверен, что CNN отлично подойдет для этого, но это не мой вопрос.

Когда я выводю «собственные грани» для плиток домино, они появляются как «размытие в движении», которое, похоже, связано с вращающимися домино. Это может быть потенциальной причиной (изображения лиц Scikit-Learn не вращаются). Я, однако, ожидал бы, что модель лучше уловит точки плиток домино, но это предположение может быть ошибочным.

Мой вопрос сейчас:

В: Ожидается ли мой результат в 10% с учетом количества и типа данных и использования SVM в качестве классификатора - или я упускаю что-то важное?

Мой код Python

import time
import matplotlib.pyplot as plt
from sklearn import svm, metrics
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
#from sklearn.preprocessing import StandardScaler
from sklearn import preprocessing 
from sklearn.decomposition import PCA
import numpy as np
import os # Working with files and folders
from PIL import Image # Image processing
from PIL import ImageFilter

### 
### Data can be downloaded from https://www.dropbox.com/sh/s5f38k4l2on5mba/AACNQgXuw1edwEb6oO1w3CfOa?dl=0
### 


start = time.time()
rootdir = os.getcwd()

image_file = 'images.npy'
key_file = 'keys.npy'

def predict_me(image_file_name, scaler, pca):
  pm = Image.open(image_file_name)
  pm = pm.resize([66,66])
  a = np.array(pm.convert('L')).reshape(1,-1)
  #a = np.array(pm.resize([66,66]).convert('L')).reshape(1,-1)) # array 66x66
  a = scaler.transform(a)
  a = pca.transform(a)
  return classifier.predict(a)

def crop_image(im, sq_size):
  new_width = sq_size
  new_height = sq_size
  width, height = im.size   # Get dimensions 
  left = (width - new_width)/2
  top = (height - new_height)/2
  right = (width + new_width)/2
  bottom = (height + new_height)/2
  imc = im.crop((left, top, right, bottom))
  return imc 

#def filter_image(im):
  # All filter makes it worse
  #imf = im.filter(ImageFilter.EMBOSS)
  #return imf

def provide_altered_images(im):
  im_list = [im]
  im_list.append(im.rotate(90))
  im_list.append(im.rotate(180))
  im_list.append(im.rotate(270))
  return im_list

if (os.path.exists(image_file) and os.path.exists(key_file)):
  print("Loading existing numpy's")
  pixel_arr = np.load(image_file)
  key = np.load(key_file)
else:
  print("Creating new numpy's")  
  key_array = []
  pixel_arr = np.empty((0,66*66), "uint8")

  for subdir, dirs, files in os.walk('data'):
    dir_name = subdir.split("/")[-1]    
    if "x" in dir_name:
      for file in files:
        if ".DS_Store" not in file:
          im = Image.open(os.path.join(subdir, file))
          if im.size == (100,100):  
            use_im = crop_image(im,66) # Most images are shot from too far away. This removes portions of it.
            #use_im = filter_image(use_im) # Filters image, but does no good at all
            im_list = provide_altered_images(use_im) # Create extra data with 3 rotated images of every image
            for alt_im in im_list:
              key_array.append(dir_name)  # Each image here is still the same as directory name
              numpied_image = np.array(alt_im.convert('L')).reshape(1,-1) # Converts to grayscale
              #Image.fromarray(np.reshape(numpied_image,(-1,100)), 'L').show()
              pixel_arr = np.append(pixel_arr, numpied_image, axis=0)
          im.close()

  key = np.array(key_array)
  np.save(image_file, pixel_arr)
  np.save(key_file, key)



# Create a classifier: a support vector classifier
classifier = svm.SVC(gamma=0.001, C=10, kernel='rbf', class_weight='balanced') # gamma and C from tests
#le = preprocessing.LabelEncoder()
#le.fit(key)
#transformed_key = le.transform(key)
transformed_key = key


X_train, X_test, y_train, y_test = train_test_split(pixel_arr, transformed_key, test_size=0.1,random_state=7)

#scaler = preprocessing.StandardScaler()

pca = PCA(n_components=500, svd_solver='randomized', whiten=True)
# Fit on training set only.
#scaler.fit(X_train)
pca.fit(X_train)

# Apply transform to both the training set and the test set.
#X_train = scaler.transform(X_train)
#X_test = scaler.transform(X_test)

X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)


print ("Fit classifier")
classifier = classifier.fit(X_train_pca, y_train)
print ("Score = " + str(classifier.score(X_test_pca, y_test)))

# Now predict the value of the domino on the test data:
expected = y_test

print ("Predicting")
predicted = classifier.predict(X_test_pca)

print("Classification report for classifier %s:\n%s\n"
      % (classifier, metrics.classification_report(expected, predicted)))
#print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted, labels  =list(set(key))))
end = time.time()
print(end - start)

Выход (последнее время в секундах)

Score = 0.09830205540661305
Predicting
Classification report for classifier SVC(C=10, cache_size=200, class_weight='balanced', coef0=0.0, decision_function_shape='ovr', degree=3, gamma=0.001, kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False):
          precision    recall  f1-score   support

  b'0x0'       0.22      0.44      0.30        27
  b'1x0'       0.24      0.23      0.24        43
  b'1x1'       0.15      0.12      0.13        49
  b'2x0'       0.13      0.15      0.14        34
  b'2x1'       0.16      0.16      0.16        44
  b'2x2'       0.02      0.03      0.03        36
  b'3x0'       0.05      0.06      0.05        36
  b'3x1'       0.05      0.05      0.05        42
  b'3x2'       0.08      0.09      0.08        46
  b'3x3'       0.15      0.16      0.15        50
  b'4x0'       0.15      0.15      0.15        40
  b'4x1'       0.07      0.05      0.06        42
  b'4x2'       0.02      0.02      0.02        41
  b'4x3'       0.09      0.08      0.09        49
  b'4x4'       0.11      0.10      0.11        39
  b'5x0'       0.18      0.12      0.14        42
  b'5x1'       0.00      0.00      0.00        38
  b'5x2'       0.02      0.02      0.02        43
  b'5x3'       0.07      0.08      0.07        36
  b'5x4'       0.07      0.04      0.05        51
  b'5x5'       0.11      0.14      0.12        42
  b'6x0'       0.03      0.03      0.03        37
  b'6x1'       0.07      0.10      0.08        31
  b'6x2'       0.03      0.03      0.03        33
  b'6x3'       0.09      0.07      0.08        45
  b'6x4'       0.02      0.03      0.03        30
  b'6x5'       0.16      0.19      0.17        37
  b'6x6'       0.10      0.08      0.09        36

   micro avg       0.10      0.10      0.10      1119
   macro avg       0.09      0.10      0.10      1119
   weighted avg       0.10      0.10      0.10      1119


115.74487614631653

1 Ответ

0 голосов
/ 30 апреля 2019

Я думаю, что одной из причин является то, что вы не должны предоставлять свои необработанные изображения в качестве входных данных вашего классификатора SVM напрямую, даже если вы применили PCA. Вам следует вычислить элементы, которые описывают форму, контраст и цвета ваших изображений, и поместить их в классификатор, или использовать CNN . CNN были созданы для классификации изображений, и там структуры автоматически вычисляют функции для изображений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...