Python. Машинное обучение. Продолжение 3.
Продолжим изучать машинное обучение на Python. На прошлом уроке мы при помощи модели поиска дефектов и модели пикселей пытались исправить испорченную картинку. Кратко напомню суть эксперимента: при помощи модели дефектов ищем дефектный пиксель и при помощи модели пикселя предсказываем, какой там должен быть пиксель. Дефектный пиксель заменяем на тот, что должен быть. В итоге у нас не получилось исправить картинку, вот как выглядит она после такого «исправления»:

Мы решили попробовать сделать следующее:
- Взять другую модель
- По-другому сформировать выборку
Для того, чтобы взять другую модель, нам необходимо как-то оценивать ее. Будем оценивать по количеству ошибок. Но сначала проведем небольшой рефакторинг, чтобы не путаться в коде. Во-первых, создадим файл detectors.py, куда поместим вот такой код:
from PIL import Image #Подключим библиотеки для работы с картинками
import random
import pandas as pd
class DefectDetector(object):
#Конструктор
#FileOriginal - исходная картинка
#FileDefected - испорченная исходна картинка
#W - полуразмер окна (размер окна равно 2W+1)
def __init__(self, FileOriginal, FileDefected, W):
self.FileOriginal = FileOriginal
self.FileDefected = FileDefected
self.W = W
#Создание выборки для поиска дефектов
def CreateDefectionSelection(self):
imageOriginal = Image.open(self.FileOriginal)
widthOriginal = imageOriginal.size[0] #Определяем ширину.
heightOriginal = imageOriginal.size[1] #Определяем высоту.
imageDefected = Image.open(self.FileDefected)
widthDefected = imageDefected.size[0] #Определяем ширину.
heightDefected = imageDefected.size[1] #Определяем высоту.
pixOriginal = imageOriginal.load() #Выгружаем значения пикселей.
pixDefected = imageDefected.load() #Выгружаем значения пикселей.
count=widthOriginal*heightOriginal
if widthOriginal!=widthDefected:
print("Не равна ширина оригинала и испорченной картинки")
return None
if heightOriginal!=heightDefected:
print("Не равна высота оригинала и испорченной картинки")
return None
ls=[]
for i in range(self.W,widthOriginal-self.W):
for j in range(self.W,heightOriginal-self.W):
if self.ComparePoints(pixOriginal[i,j],pixDefected[i,j]):
if random.randint(1,int(count/2000))==1:
ls.append(self.CreateDicDefected(pixOriginal, i, j, self.W, 1))
else:
ls.append(self.CreateDicDefected(pixDefected, i, j, self.W, 0))
return pd.DataFrame(ls)
def ComparePoints(self, point1, point2):
if point1[0]!=point2[0]:
return False
if point1[1]!=point2[1]:
return False
if point1[2]!=point2[2]:
return False
return True
#Создаем словарь строки выборки
def CreateDicDefected(self, pix, i, j, W, result=-1):
dic={}
k=1
dic["flag"]=random.choice([True,False])
for x in range(i-W, i+W+1):
for y in range(j-W,j+W+1):
if x==i and y==j:
continue
dic["R"+str(k)] = pix[x, y][0]
dic["G"+str(k)] = pix[x, y][1]
dic["B"+str(k)] = pix[x, y][2]
k=k+1
if result==-1:
dic["RY"]=pix[i, j][0]
dic["GY"]=pix[i, j][1]
dic["BY"]=pix[i, j][2]
else:
dic["Y"]=result
return dic
Как видим, мы оформили алгоритм создания выборки в виде удобного класса, то есть, по сути, используем ООП. Далее, для тестирования тоже создадим отдельный класс ModelTester и разместим его в файле tester.py:
class ModelTester(object):
#Конструктор
#model - тестируемая модель
def __init__(self, model):
self.model = model
#произвести тестирование модели
def test(self,X,Y):
predicted = self.model.predict(X)
index = 0
self.errors_false_yes = 0.0
self.errors_false_no = 0.0
self.answers_yes = 0
self.answers_no = 0
self.count_items=len(X)
while index < self.count_items:
y1 = Y.values[index]
y2 = predicted[index]
if y1>0.5:
self.answers_yes =self.answers_yes+1
if y1 != y2:
self.errors_false_yes=self.errors_false_yes+1
else:
self.answers_no=self.answers_no+1
if y1 != y2:
self.errors_false_no=self.errors_false_no+1
index = index + 1
Теперь осталось сделать запускаемый файл (main.py), который теперь выглядит компактно и лаконично:
from detectors import DefectDetector
from sklearn.ensemble import RandomForestClassifier #случайный лес
from tester import ModelTester
detector=DefectDetector("d:\\rep\\origtest.png","d:\\rep\\origtestspoild.png",2)
selection=detector.CreateDefectionSelection()
selection_train, selection_test = selection.query("flag"), selection.query("~flag")
Y_train = selection_train["Y"]
X_train = selection_train.drop(["Y","flag"], axis=1)
model = RandomForestClassifier()
model.fit(X_train, Y_train)
test=ModelTester(model)
test.test(X_train,Y_train)
print("Кол-во элементов:",test.count_items)
print("Ложных ответов YES:",test.errors_false_yes,"; всего ",test.answers_yes,"; %",test.errors_false_yes/test.answers_yes*100)
print("Ложных ответов NO:",test.errors_false_no,"; всего ",test.answers_no,"; %",test.errors_false_no/test.answers_no*100)
Y_test = selection_test["Y"]
X_test = selection_test.drop(["Y","flag"], axis=1)
test.test(X_test,Y_test)
print("Кол-во элементов:",test.count_items)
print("Ложных ответов YES:",test.errors_false_yes,"; всего ",test.answers_yes,"; %",test.errors_false_yes/test.answers_yes*100)
print("Ложных ответов NO:",test.errors_false_no,"; всего ",test.answers_no,"; %",test.errors_false_no/test.answers_no*100)
Теперь кратко объясняю, что делает наша программа. Класс DefectDetector содержит в себе алгоритмы создания обучающей выборки для поиска дефектных пикселей. Он такой-же, как и на предыдущих уроках, за исключением маленького нюанса: в датафрейм выборки добавлено булево поле flag, которое заполняется по рандому. Для чего это надо – чтобы разделить выборку на две – тренировочную и тестовую. Деление происходит путем вызова метода query где мы просто задаем этот флаг в качестве условия. Для одной выборки – прямое условие (туда попадут все записи где flag=True), для второй условие с инверсией, туда, соответственно попадут строк где этот флаг False.
Собственно, командной:
selection_train, selection_test = selection.query("flag"), selection.query("~flag")
Мы делим выборку на две. Далее, обучаем модель на тренировочной выборке и проводим ее тестирование. Для сравнения тестируем и на тестовой и на тренировочной выборке.
В данном коде приведен пример обучения модели «Случайный лес». Но мы можем использовать и другие модели. Для этого нам надо только их импортировать. Вот так импортируется случайный лес:
from sklearn.ensemble import RandomForestClassifier
А вот так можно импортировать другие модели:
from sklearn.svm import SVC #модель SVC (метод опорных векторов) from sklearn.naive_bayes import GaussianNB #Наивный байесовский метод from sklearn.tree import DecisionTreeClassifier #Решающее дерево from sklearn.neighbors import KNeighborsClassifier #Алгоритм k-ближайших соседей
Теперь исследуем все эти модели, сведя их показатели в сравнительную таблицу:
| Модель | Обучающая выборка, кол-во ошибок, % | Тестовая выборка, кол-во ошибок, % | ||
| Ошибки YES | Ошибки NO | Ошибки YES | Ошибки NO | |
| Случайный лес | 0 | 0 | 4.2 | 3.3 |
| SVC | 3.9 | 10.11 | 5.7 | 11.6 |
| Наивный байес | 24.9 | 46.8 | 27.3 | 44.2 |
| Решающее дерево | 0 | 0 | 7.8 | 11.1 |
| K-ближайших соседей | 0.4 | 20.6 | 0.7 | 27.4 |
Таким образом, мы видим, что лучшая модель – это случайный лес. То, что мы выбрали вначале. Нужно пробовать другие способы. Но об этом в следующей статье.

Comments
So empty here ... leave a comment!