Мужчина OR Женщина (python/keras)

от автора

Здравствуйте, дорогие друзья, хабрчане. Меня зовут Илья, я тут новенький, и сегодня, я расскажу вам, как я решил научить нейронную сеть различать пол человека по фотографии лица.

Первым делом нам понадобятся сам датасет. Датасетов в интернете огромное количество, но ни один мне не подошел. И по этому, я решил сделать свой датасет.

  1. Находим источник для фото — у меня это был сайт, где генерируются лица людей, которые никогда не существовали и с каждым обновлением лицо меняется — https://thispersondoesnotexist.com/

2)Теперь нужно закачать 2000 картинок с этого сайта, я буду для этого использовать следующий код:

import shutil import time import requests  while (i < 1000):     url = 'https://thispersondoesnotexist.com/image'     response = requests.get(url, stream=True)     with open(str(i)+'.jpg', 'wb') as out_file:         shutil.copyfileobj(response.raw, out_file)     del response     i = i + 1     time.sleep(1)

Тут все просто, в любой папке создаем .py файл, добавляем туда этот код, и в консоли его вызываем, ждем 2000 сек. и гарантированно получаем 2к картинок.
Далее ручками(буквально) нужно набрать 500 картинок мужчин и женщин. Я делал следующим образом: открывал папку и выделял все фото мужчин через CTRL + клик, и вырезал в другую папку(конечно я отправлю ссылку на гидхаб где будут фото).

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

import os as s def renameFilesInNumbers(from_,to_, g=''):     i = 0     name1 = s.listdir('./'+from_)     while(i < len(name1)):     # while(i < 101):         s.rename('ваш путь до папки'+from_+'/' +name1[i],'./'+to_+'/'+ ''+str(i)+g+'.jpg')         i = i + 1 

Дальше нужно преобразовать эти фото в нужный формат: просто делаем их серыми и ставим разрешение 299*299.
Вот код:

import cv2 import os as s  def ResizeImags(from_,to_):     i = 0     name1 = s.listdir('ваш путь до папки'+from_)     while( i < len(name1)):         img = cv2.imread('ваш путь до папки'+from_+'/'+str(i)+'.jpg', cv2.IMREAD_UNCHANGED)         gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)         resized = cv2.resize(gray_image, (299, 299), interpolation = cv2.INTER_AREA)         cv2.imwrite('./'+to_+'/'+str(i)+'.jpg',resized)         i = i + 1

Далее мы создаем файл в google colab и пишем саму нейронку.

Архитектура максимально простая, была взята из примера про определение одежды:

model = Sequential() model.add(Conv2D( 2, 3, activation='relu', padding="same", input_shape=(299,299,1))) model.add(MaxPooling2D()) model.add(Conv2D( 2, 3, activation='relu', padding="same")) model.add(MaxPooling2D()) model.add(Conv2D( 2, 3, activation='relu', padding="same")) model.add(MaxPooling2D()) model.add(Flatten()) model.add(Dense(128,activation='relu')) model.add(Dense(64,activation='relu')) model.add(Dense(18,activation='relu')) model.add(Dense(2,activation='softmax'))  model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

А теперь, вспомним о нашем датасете, как из папки картинок сделать дата сет, ну честно говоря, никакой датасет мы делать не будем, просто из каждой папки сделаем массив картинок.

Выглядеть это будет так:

i = 0  while (i < 500): # тут все понятно , 500 фоток == 500 этераций     data.append(        np.array(cv2.imread('./M/'+str(i)+'.jpg', cv2.IMREAD_UNCHANGED))/255   )   # при каждой итерации добаляем изображение мужчины   data.append(       np.array(cv2.imread('./W/'+str(i)+'.jpg', cv2.IMREAD_UNCHANGED))/255   )   # женщины    data1.append( [0., 1.])   # при каждой итерации добаляем вектор значения мужчины   data1.append( [1., 0.])   # женщины    i = i + 1

Вектор значения — это мой собственный термин, обозначающий преобразование любого значения, любой определенной формы в векторный формат.
Уверен , что для того ,что я имею ввиду , есть свой термин , — я его просто не знаю.

Дальше просто указываю с какими параметрами будет компилироваться моя нейронная сеть, а именно: какая будет функция потерь(loss) — ‘категориальная кросс энтропия’, оптимизатор — ‘adam’, метрика которую будем видеть в момент обучения — точность.
model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[‘accuracy’])

Весь код:

from typing_extensions import Text import keras import numpy as np import cv2 from keras.models import Sequential from keras.layers import Dense, Dropout , Conv2D , Flatten, MaxPooling2D    data = [] data1 = [] i = 0  while (i < 500):      data.append(        np.array(cv2.imread('./M/'+str(i)+'.jpg', cv2.IMREAD_UNCHANGED))/255   )   data.append(       np.array(cv2.imread('./W/'+str(i)+'.jpg', cv2.IMREAD_UNCHANGED))/255       )   data1.append( [0., 1.])   data1.append( [1., 0.])   i = i + 1  model = Sequential() model.add(Conv2D( 2, 3, activation='relu', padding="same", input_shape=(299,299,1))) model.add(MaxPooling2D()) model.add(Conv2D( 2, 3, activation='relu', padding="same")) model.add(MaxPooling2D()) model.add(Flatten()) model.add(Dense(128,activation='relu')) model.add(Dense(64,activation='relu')) model.add(Dense(18,activation='relu')) model.add(Dense(2,activation='softmax'))  model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])  model.fit(np.array(data), np.array(data1) ,      epochs=7 )   print(     model.predict(         np.array(     [np.array(cv2.imread('./M/'+str(519)+'.jpg', cv2.IMREAD_UNCHANGED))/255]         )     ) )  print(     model.predict(         np.array(     [np.array(cv2.imread('./M/'+str(541)+'.jpg', cv2.IMREAD_UNCHANGED))/255]         )     ) )

Вот фото которые получились.

Казалось бы, миссия выполнена. Но можно по другому. Можно использовать другую архитектуру. В чем будет разница: так-как у нас всего 2 варианта, то можно вместо категориальной кросс энтропии использовать бинарную кросс энтропию.

Новый код:

import os import keras import numpy as np import cv2 from keras.models import Sequential from keras.layers import Dense, Dropout , Conv3D , Flatten, MaxPooling2D  data = []  data1 = []  i = 0  while (i < 500):   data.append(        np.array(cv2.imread('./M/'+str(i)+'.jpg', cv2.IMREAD_UNCHANGED))/255   )   data.append(       np.array(cv2.imread('./W/'+str(i)+'.jpg', cv2.IMREAD_UNCHANGED))/255   )   data1.append( [1.])   data1.append( [0.])   i = i + 1  model = Sequential() model.add(Conv2D( 2, 3, activation='relu', padding="same", input_shape=(299,299,1))) model.add(MaxPooling2D()) model.add(Conv2D( 2, 3, activation='relu', padding="same")) model.add(Flatten()) model.add(Dense(64, activation='relu'))  model.add(Dense(64, activation='relu'))  model.add(Dropout(0.5))  model.add(Dense(1, activation='sigmoid'))  model.compile(loss='binary_crossentropy',                optimizer='rmsprop',                metrics=['accuracy'])  model.fit(np.array(data), np.array(data1) ,      epochs=10 )

Все тоже самое кроме функции активации, теперь она не softmax а sigmoid, и функция потерь.

Надеюсь моя первая статья вам понравится, и новичкам она как-то поможет, всем удачи !

git: https://github.com/paradiseMaestro


ссылка на оригинал статьи https://habr.com/ru/post/697802/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *