تعیین جنسیت در تصاویر با یادگیری عمیق — به زبان ساده
هدف از این مطلب، آموزش ساخت مدلی برای تعیین جنسیت در تصاویر با یادگیری عمیق است. در واقع، هدف آن است که تصاویر به یک مدل یادگیری عمیق (در اینجا، شبکه عصبی پیچشی) داده شوند و مدل بتواند تشخیص بدهد که فرد حاضر در تصویر مرد یا زن است. با تنظیم دقیق یک «شبکه عصبی پیچشی» (Convolutional Neural Network) از نوع VGG16 که از پیش آموزش دیده و آموزش دادن آن با استفاده از تصاویر افراد مشهور انجام شده، مدل ساخته شده توانسته است به صحت ٪۸۶ در ارائه پاسخ صحیح روی «دادههای تست» (Test Data) دست پیدا کند. این بررسی موردی، مزیت استفاده از معماری مدلهای از پیش آموزش دیده را برای تکمیل ویژگیهای مجموعه داده نشان میدهد. کلیه پیادهسازیهای مورد استفاده در اینجا، با «زبان برنامهنویسی پایتون» (Python Programming Language) انجام شدهاند.
تعیین جنسیت در تصاویر با یادگیری عمیق
به طور معمول، انسان میتواند به راحتی بین مرد و زن موجود در تصویر زیر تمایز قائل شود، اما تشریح دقیق اینکه چرا میتواند چنین کاری را به این سادگی انجام دهد، دشوار است. بدون تعیین ویژگیهای دقیق، این تمایز میتواند برای رویکردهای یادگیری ماشین سنتی خیلی دشوار باشد. علاوه بر آن، ویژگیهایی که مرتبط با انجام این کار هستند همیشه دقیقا به یک شیوه بیان نمیشوند، بلکه برای هر انسانی کمی متفاوت به نظر میرسد.
الگوریتمهای یادگیری عمیق، راهکاری برای پردازش اطلاعات بدون ویژگیهای از پیش تعریف شده ارائه میکنند و پیشبینیهای دقیقی را با وجود تنوع در چگونگی بیان ویژگیها انجام میدهند. در این مقاله، یک شبکه عصبی پیچشی با هدف پیشبینی جنسیت افراد، روی تصاویر افراد مشهور اعمال شده است (سلب مسئولیت: نویسنده میداند که ظاهر شخص الزاما رابطه سببی با جنسیت او ندارد).
ابزارهای مورد استفاده
شبکههای عصبی پیچشی (ConvNets)، ابزارهایی را برای پیشبینی از روی تصاویر خام ارائه میکنند. یکی از قابلیتهای این الگوریتم، توانایی کاهش ابعاد تصویر با استفاده از توالی فیلترهایی است که به تعیین ویژگیهای متمایز کننده کمک میکنند. لایههای اضافی موجود در مدل، به کاربر برای تاکید بر رابطه اغلب غیرخطی بین ویژگیهای تعیین شده توسط فیلترها و برچسبهای تخصیص پیدا کرده به تصاویر کمک میکنند.
میتوان وزنهای اختصاص پیدا کرده به فیلترها و لایههای اضافی را برای کاهش خطای بین دستهبندیهای پیشبینی و مشاهده شده تنظیم کرد که پرداختن به آن به صورت جامع، از حوصله این مطلب خارج است. تعدادی ConvNets از پیش آموزش دیده، برای دستهبندی تصاویر چیزهای مختلف از هواپیما گرفته تا سگهای کورگی وجود دارند. میتوان با بهرهگیری از این شبکههای از پیش آموزش دیده، زمان محاسبات را کاهش داد و بر برخی از دیگر چالشهای موجود در مسیر حل مساله، از جمله ناکافی بودن نمونهها، با به کار گیری وزنهای مدل از پیش آموزش دیده و تنظیم دقیق آنها غلبه کرد.
مجموعه داده
مجموعه داده CelebA [+] حاوی 200K از تصاویر افراد مشهور برچسب زده شده با ۲۰ خصیصه شامل جنسیت است. تصاویر از شانه به بالا هستند، بنابراین بیشتر اطلاعات موجود در تصاویر مربوط به اجزای صورت و مدل مو هستند.
مدلسازی
در ادامه، گامهای مربوط به مدلسازی بیان شدهاند. برای راحتی کار، کد مربوط به مدل VGG16 که در اینجا مورد استفاده قرار گرفته، در ادامه قرار داده شده است.
1# -*- coding: utf-8 -*-
2"""
3Created on Fri Apr 12 13:25:08 2019
4Nate Jermain Gender Identification CNN
5"""
6import pandas as pd
7import numpy as np
8import seaborn as sns
9from matplotlib import pyplot as plt
10
11df=pd.read_csv('C:/Users/w10007346/Pictures/list_attr_celeba.csv')
12
13df.head()
14df.columns.values
15
16# get image labels for males
17male=df[df['Male']==1][0:20000][['image_id', 'Male']]
18
19female=df[df['Male']==-1][0:20000][['image_id','Male']]
20
21
22from sklearn.model_selection import train_test_split
23m_train_X, m_test_X, train_y, test_y = train_test_split(male['image_id'],male['Male'], random_state = 0, test_size=.2)
24f_train_X, f_test_X, train_y, test_y = train_test_split(female['image_id'],female['Male'], random_state = 0, test_size=.2)
25
26
27origin_path='C:/Users/w10007346/Pictures/img_align_celeba/'
28train_path='C:/Users/w10007346/Pictures/Celeb_sets/train/'
29valid_path='C:/Users/w10007346/Pictures/Celeb_sets/valid/'
30fm='female/'
31ml='male/'
32
33import os
34
35for file in m_train_X:
36 os.rename(origin_path+file, train_path+ml+file)
37
38for file in m_test_X:
39 os.rename(origin_path+file, valid_path+ml+file)
40
41
42for file in f_train_X:
43 os.rename(origin_path+file, train_path+fm+file)
44
45for file in f_test_X:
46 os.rename(origin_path+file, valid_path+fm+file)
47
48
49######## Modeling ################################
50from keras.applications.vgg16 import VGG16
51from keras.applications.vgg16 import preprocess_input
52from tensorflow.python.keras.models import Sequential
53from tensorflow.python.keras.layers import Dense, Dropout, GlobalAveragePooling2D, BatchNormalization
54
55
56from keras import models
57from keras import layers
58
59num_classes=2
60
61vgg=VGG16(include_top=False, pooling='avg', weights='imagenet',input_shape=(178, 218, 3))
62vgg.summary()
63
64# Freeze the layers except the last 2 layers
65for layer in vgg.layers[:-5]:
66 layer.trainable = False
67
68# Check the trainable status of the individual layers
69for layer in vgg.layers:
70 print(layer, layer.trainable)
71
72
73# Create the model
74model = models.Sequential()
75
76
77# Add the vgg convolutional base model
78model.add(vgg)
79
80# Add new layers
81model.add(layers.Dense(128, activation='relu'))
82model.add(layers.BatchNormalization())
83model.add(layers.Dense(num_classes, activation='softmax'))
84
85model.summary()
86
87model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
88
89# use early stopping to optimally terminate training through callbacks
90from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint
91es=EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=2)
92
93# save best model automatically
94import h5py
95mc= ModelCheckpoint('C:/Users/w10007346/Dropbox/CNN/Gender ID/best_model.h5', monitor='val_loss', mode='min', verbose=1, save_best_only=True)
96cb_list=[es,mc]
97
98
99from tensorflow.python.keras.applications.vgg16 import preprocess_input
100from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
101
102
103
104data_generator = ImageDataGenerator(preprocessing_function=preprocess_input)
105
106
107train_generator = data_generator.flow_from_directory(
108 'C:/Users/w10007346/Pictures/Celeb_sets/train',
109 target_size=(178, 218),
110 batch_size=12,
111 class_mode='categorical')
112
113
114validation_generator = data_generator.flow_from_directory(
115 'C:/Users/w10007346/Pictures/Celeb_sets/valid',
116 target_size=(178, 218),
117 batch_size=12,
118 class_mode='categorical')
119
120
121model.fit_generator(
122 train_generator,
123 epochs=20,
124 steps_per_epoch=2667,
125 validation_data=validation_generator,
126 validation_steps=667, callbacks=cb_list)
127
128
129
130
131
132# load a saved model
133from keras.models import load_model
134saved_model = load_model('best_model.h5')
استخراج ویژگی
در ادامه، از مدل VGG16 از پیش آموزش دیده استفاده خواهد شد و این مدل به طور دقیق تنظیم میشود تا به بهترین شکل، جنسیت را از روی تصاویر افراد مشهور تشخیص دهد.
1vgg=VGG16(include_top=False, pooling=’avg’, weights=’imagenet’,
2input_shape=(178, 218, 3))
از «include_top=False» برای حذف لایه کاملا متصل طراحی شده برای شناسایی طیفی از اشیایی که VGG16 برای شناسایی آنها طراحی شده است، استفاده میشود (برای مثال، سیبها، سگهای کورگی، قیچی)، و همچنین، وزنهای تخصیص داده شده به این مجموعه داده طی رقابتهای ImageNet، دانلود و برای ادامه راه استفاده میشوند.
جدولی که در ادامه آمده، معماری پیچشی برای VGG16 را نمایش میدهد؛ میلیونها وزن برای همه «پیچشها» (Convolutions) وجود دارد که کاربر میتواند از میان آنها انتخاب کند و یا مدل را با مقادیر از پیش آموزش داده به همان صورت فریز کرده و نگه دارد. با فریز کردن همه وزنهای مدل، خطر «کمبرازش» (Underfitting) وجود دارد، زیرا وزنهای از پیش آموزش داده شده، برای انجام یک کار خاص تخمین زده نشدهاند. از سوی دیگر، با آموزش دادن همه وزنها، خطر «بیشبرازش» (Overfitting) به وجود میآید زیرا مدل شروع به «حفظ کردن» تصاویر آموزشی داده شده به آن میکند و انطافپذیری مدل برای نمونههای جدید را از بین میبرد. بنا به دلایل بیان شده، با آموزش دادن آخرین بلوک از کد، موازنهای در این راستا انجام داده میشود.
1# Freeze the layers except the last 5
2for layer in vgg.layers[:-5]:
3 layer.trainable = False
4# Check the trainable status of the individual layers
5for layer in vgg.layers:
6 print(layer, layer.trainable)
اولین بلوکهای پیچشی در مدلهای VGG16، ویژگیهای عمومیتری مانند خطوط یا لکهها را شناسایی میکند، بنابراین هدف حفظ ویژگیهای مرتبط است. بلوکهای نهایی، مربوط به ویژگیهای خوش مقیاستر (برای مثال، زوایای مرتبط با نوک بال یک هواپیما) هستند، بنابراین وزنها با توجه به تصاویر افراد مشهور آموزش داده میشوند.
تلفیق مدل
استخراج ویژگی با بهرهگیری از پیچشها انجام و دو «لایه متراکم» (Dense Layer) به مدل اضافه میشوند که کاربر را قادر به انجام پیشبینی پیرامون تصاویر با توجه به ویژگیهای تعیین شده میکند.
کاربر میتواند از یک لایه متراکم مجرد استفاده کند، اما یک لایه اضافی پنهان امکان انجام پیشبینیها با توجه به تفسیرهای پیچیدهتر از ویژگیها را فراهم میکند. وجود لایههای متراکم زیاد، ممکن است موجب بیشبرازش شوند.
1# Create the model
2model = models.Sequential()
3# Add the VGG16 convolutional base model
4model.add(vgg)
5
6# Add new layers
7model.add(layers.Dense(128, activation=’relu’))
8model.add(layers.BatchNormalization())
9model.add(layers.Dense(2, activation=’sigmoid’))
یک لایه نرمالسازی دسته (batch) که مقادیر فعالسازی لایه پنهان را مقیاس میدهد، برای کاهش «بیشبرازش» (Overfitting) و زمان محاسبات اضافه میشوند. آخرین لایه متراکم، پیشبینی پیرامون جنسیت را انجام میدهد (تصویر زیر).
با توجه به اینکه این امکان فراهم میشود که لایههای پیچشی و چگال مدل آموزش داده شوند، میلیونها وزن تخمین زده خواهند شد (تصویر زیر). با توجه به عمق شبکه ساخته شده، انتخاب بهترین نرخ یادگیری ثابت برای بهینهسازهایی مانند «گرادیان کاهشی تصادفی» (Stochastic Gradient Decent | SGD)، کاری هوشمندانه است؛ در عوض، از بهینهسازی ADAM استفاده میشود که نرخ یادگیری را برای ایجاد گامهای کوچکتر برای آموزش تنظیم میکند.
1model.compile(optimizer=’adam’, loss=’binary_crossentropy’, metrics=[‘accuracy’])
با استفاده از کتابخانه پایتون «کراس» (Keras)، «تولیدکنندههای داده» (Data Generators) برای «خوراک دادن» (Feed) به مدل راهاندازی میشوند و شبکه را برای مجموعه آموزش، برازش (Fit) میکنند.
1data_generator = ImageDataGenerator(preprocessing_function=preprocess_input)
2train_generator = data_generator.flow_from_directory(
3 ‘C:/Users/w10007346/Pictures/Celeb_sets/train’,
4 target_size=(178, 218),
5 batch_size=12,
6 class_mode=’categorical’)
7validation_generator = data_generator.flow_from_directory(
8 ‘C:/Users/w10007346/Pictures/Celeb_sets/valid’,
9 target_size=(178, 218),
10 batch_size=12,
11 class_mode=’categorical’)
12model.fit_generator(
13 train_generator,
14 epochs=20,
15 steps_per_epoch=2667,
16 validation_data=validation_generator,
17 validation_steps=667, callbacks=cb_list)
پس از شش «دوره» (epochs)، مدل دارای صحت اعتبارسنجی بیشینه ٪۹۸ است. اکنون زمان اعمال مدل روی دادههای تست فرا رسیده است.
تست
یک مجموعه داده تست دارای ۵۰۰ تصویر به ازای هر جنسیت (۱۰۰۰ تصویر در کل) است. مدل، احتمالهای پیشبینی شده برای هر تصویر را از طریق شبکه به دست میدهد و به سادگی میتوان بیشینه مقدار این احتمالها را به عنوان جنسیت پیشبینی شده در نظر گرفت.
1# obtain predicted activation values for the last dense layer
2pred = saved_model.predict_generator(test_generator, verbose=1, steps=1000)
3# determine the maximum activation value for each sample
4predicted_class_indices=np.argmax(pred,axis=1)
مدل ساخته شده توانسته است که جنسیت افراد مشهور را با صحت ۹۸.۲٪ پیشبینی کند. این میزان از صحت، به توانایی انسان در تشخیص جنسیت بسیار نزدیک و قابل قیاس با آن است. پرسشی که در این وهله مطرح میشود آن است که آیا مدل به تصاویری غیر از تصاویر افراد مشهور نیز قابل تعمیم است؟ پاسخ به این پرسش، با سنجیدن چند تصویر از افراد غیر مشهور (نویسنده اصلی این مطلب) سنجیده شده است.
عملکرد مدل برای این تصویر خوب بوده و در واقع، مدل توانسته است جنسیت تصویر را ٪۹۹.۸ مرد تشخیص دهد.