Top.Mail.Ru

Python. Машинное обучение. Продолжение.

Продолжим изучать машинное обучение с использованием языка Python. На прошлом уроке мы попробовали прогнать изображение через модель «Случайный лес» (Random Forest). На вход подавали точки из скользящего окна. Теперь попробуем применить машинное обучение для восстановления картинки. Итак, пусть у нас есть вот такая вот испорченная картинка:

Как мы ее восстановим? Создадим модель, которая найдет нам испорченные пикселы, и мы заменим их на те, которые тут должны быть. А их нам предскажет модель, обученная на похожей картинке (именно так, как мы это делали на прошлом уроке).

Вот что нам выдал гугол при попытке найти по изображению (прямо по той картинке где царапины):

Скачиваем ту картинку, что наиболее похожа на нашу, делаем с нее копию, копию портим (оставляем примерно такие же артефакты, как и на нашей испорченной картинке). Таким образом, мы сможет создать набор данных для поиска дефектных пикселем: сравниваем попиксельно нормальную и испорченную картинку, несовпадающие пикселы считаем дефектным, а часть совпадающих добавляем в выборку как нормальные пикселы.

Вот эта картинка:

Сначала проверим, как вообще модель может обучаться распознавать дефектные пиксели. Итак, пишем на Python функцию, которая создаёт выборку плохих и хороших пикселей:

#Создание выборки для поиска дефектов
def CreateDefectionSelection(FileOriginal, FileDefected, W):
    imageOriginal = Image.open(FileOriginal)
    widthOriginal = imageOriginal.size[0] #Определяем ширину. 
    heightOriginal = imageOriginal.size[1] #Определяем высоту.         
    imageDefected = Image.open(FileDefected)
    widthDefected = imageDefected.size[0] #Определяем ширину. 
    heightDefected = imageDefected.size[1] #Определяем высоту.
    pixOriginal = imageOriginal.load() #Выгружаем значения пикселей.
    pixDefected = imageDefected.load() #Выгружаем значения пикселей.
    count=widthOriginal*heightOriginal
    if widthOriginal!=widthDefected:
        print("Не равна ширина оригинала и испорченной картинки")
        return NaN
    if heightOriginal!=heightDefected:
        print("Не равна высота оригинала и испорченной картинки")
        return NaN  
    ls=[]
    for i in range(W,widthOriginal-W):
        for j in range(W,heightOriginal-W):      
            if ComparePoints(pixOriginal[i,j],pixDefected[i,j]):
                if random.randint(1,int(count/2000))==1:
                    ls.append(CreateDicDefected(pixOriginal, i, j, W, 1))
            else:
                ls.append(CreateDicDefected(pixDefected, i, j, W, 0))
    return pd.DataFrame(ls)

Как она работает? Сравнивает две картинки, одна нормальная, вторая дефектная. Если пикселы не совпадают, значит, это дефектный пиксель, если совпадают – пиксель нормальный, но его добавляем в выборку с определённой вероятностью. Подбираем так, чтобы нормальных и дефектных пикселей было примерно одинаково.

Далее, вспомогательные функции:

def ComparePoints(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(pix, i, j, W, result=-1):
    dic={}
    k=1            
    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

И код проверки:

rep=CreateDefectionSelection("d:\\rep\\origtrain.png","d:\\rep\\origtrainspoil.png",2)
data_train=pd.DataFrame(rep)
Y = data_train["Y"]
X = data_train.drop(["Y"], axis=1)
model = RandomForestClassifier()
model.fit(X, Y)
predicted = model.predict(X)
i=0
errors=0
spoiled=0
normal=0
while i<len(Y):
    if Y[i]!=predicted[i]:
        errors=errors+1
    if Y[i]==1:
        normal=normal+1
    if Y[i]==0:
        spoiled=spoiled+1        
    i=i+1

print(len(Y),normal,spoiled,errors,float(errors)/float(normal)*100.0)

rep_test=CreateDefectionSelection("d:\\rep\\origtest.png","d:\\rep\\origtestspoild.png",2)
data_test=pd.DataFrame(rep_test)
Y_test = data_test["Y"]
X_test = data_test.drop(["Y"], axis=1)
predicted_test = model.predict(X_test)
i=0
errors_test=0
spoiled=0
normal=0
while i<len(Y_test):
    if Y_test[i]!=predicted_test[i]:
        errors_test=errors_test+1
    if Y_test[i]==1:
        normal=normal+1
    if Y_test[i]==0:
        spoiled=spoiled+1          
    i=i+1
    
print(len(Y_test),normal,spoiled,errors_test,float(errors_test)/float(normal)*100.0)    

Как показал тест, на обучающей выборке точность примерно 0.4%, а на тестовой примерно 28%:

3021 1989 1032 8 0.40221216691804923

3760 1973 1787 544 27.572225038013176

Это почти треть. Много или мало? На прошлом уроке мы всю картинку заменили пикселями, которые предсказала модель. Цветопередача исказилась, некоторые детали исчезли, вот исходная картинка:

А вот обработанная

Вероятно, при таком восстановлении, картинка может исказиться. Но вообще, интересно было бы посмотреть  ошибки в разрезе ложно положительных и ложно отрицательных срабатываний.

Итак, вносим изменения в код:

rep=CreateDefectionSelection("d:\\rep\\origtrain.png","d:\\rep\\origtrainspoil.png",2)
data_train=pd.DataFrame(rep)
Y = data_train["Y"]
X = data_train.drop(["Y"], axis=1)
model = RandomForestClassifier()
model.fit(X, Y)
predicted = model.predict(X)
i=0
errors=0
errors_false_positve=0
errors_false_negative=0
spoiled=0
normal=0
while i<len(Y):
    if Y[i]!=predicted[i]:
        errors=errors+1
        if predicted[i]>0.5:
           errors_false_positve=errors_false_positve+1 
        else:
           errors_false_negative=errors_false_negative+1 
    if Y[i]==1:
        normal=normal+1
    if Y[i]==0:
        spoiled=spoiled+1        
    i=i+1

print(len(Y),normal,spoiled,errors,float(errors)/float(normal)*100.0)
print("errors_false_positve=",errors_false_positve)
print("errors_false_negative=",errors_false_negative)

rep_test=CreateDefectionSelection("d:\\rep\\origtest.png","d:\\rep\\origtestspoild.png",2)
data_test=pd.DataFrame(rep_test)
Y_test = data_test["Y"]
X_test = data_test.drop(["Y"], axis=1)
predicted_test = model.predict(X_test)
i=0
errors=0
errors_false_positve=0
errors_false_negative=0
spoiled=0
normal=0
while i<len(Y_test):
    if Y_test[i]!=predicted_test[i]:
        errors=errors+1
        if predicted_test[i]>0.5:
           errors_false_positve=errors_false_positve+1 
        else:
           errors_false_negative=errors_false_negative+1         
    if Y_test[i]==1:
        normal=normal+1
    if Y_test[i]==0:
        spoiled=spoiled+1          
    i=i+1
    
print("-----------------------")
print(len(Y_test),normal,spoiled,errors,float(errors)/float(normal)*100.0)    
print("errors_false_positve=",errors_false_positve)
print("errors_false_negative=",errors_false_negative)

И смотрим результат:

2993 1961 1032 3 0.1529831718510964

errors_false_positve= 3

errors_false_negative= 0

————————

3727 1940 1787 652 33.608247422680414

errors_false_positve= 223

errors_false_negative= 429

Что получается?

Примерно треть ошибок – это ложно отнесение к нормальному пикселю дефектного. То есть, треть дефектов мы не исправим. И примерно 20% пикселей буду заменены на предсказанные, но только с другой картинки. Как это будут выглядеть узнаем из следующего урока.

Начало.

Продолжение.

 

 

Comments

So empty here ... leave a comment!

Добавить комментарий

Sidebar