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!