كيفية تدريس الهاتف لمعرفة الجمال

صورة

لقد قرأت مؤخرًا كتابًا عن الرياضيات وجمال الناس وفكرت في ما كان عليه قبل عقد من الزمن ، وفكرة كيفية فهم الجمال البشري الذي كان بدائيًا تمامًا. إن التفكير في أي وجه يعتبر جميلاً من وجهة نظر الرياضيات قد جاء إلى حقيقة أنه ينبغي أن يكون متماثلًا. أيضًا ، منذ عصر النهضة ، كانت هناك محاولات لوصف الوجوه الجميلة باستخدام العلاقات بين المسافات في بعض النقاط على الوجه وإظهار ، على سبيل المثال ، أن الوجوه الجميلة لها نوع من العلاقة بالقرب من النسبة الذهبية. يتم الآن استخدام أفكار مشابهة حول موقع النقاط كواحدة من طرق تحديد الوجوه (البحث عن معالم الوجه). ومع ذلك ، تُظهر التجربة أنه إذا لم تقصر مجموعة الميزات على موضع نقاط محددة على الوجه ، فيمكنك تحقيق نتائج أفضل في عدد من المهام ، بما في ذلك تحديد العمر أو الجنس أو التوجه الجنسي . من الواضح بالفعل هنا أن مسألة أخلاقيات نشر نتائج هذه الدراسات قد تكون حادة.

موضوع جمال الناس وتقييمه يمكن أن يكون أيضًا مثارًا للجدل أخلاقيًا. عند تطوير التطبيق ، رفض العديد من أصدقائي استخدام صورهم للاختبارات ، أو لم يرغبوا في معرفة النتيجة (من المضحك أن معظم الفتيات رفضن معرفة النتائج). أيضا ، فإن الهدف من أتمتة تقييم الجمال يمكن أن يثير أسئلة فلسفية مثيرة للاهتمام. إلى أي مدى يتم تحديد مفهوم الجمال حسب الثقافة؟ ما مدى صحة "الجمال في عين الناظر"؟ هل من الممكن تسليط الضوء على علامات موضوعية من الجمال؟

للإجابة على هذه الأسئلة ، تحتاج إلى دراسة الإحصاءات حول تصنيفات بعض الأشخاص من قبل الآخرين. حاولت تصميم نموذج شبكة عصبية وتقييمه وتقييم الجمال ، وكذلك تشغيله على هاتف يعمل بنظام Android.

جزء 0. خط أنابيب


لفهم كيفية ارتباط الخطوات التالية ببعضها البعض ، قمت برسم مخطط للمشروع:

صورة

الأزرق - المكتبات الهامة والبيانات الخارجية. الأصفر - الضوابط في التطبيق.

الجزء 1. بيثون


نظرًا لأن تقييم الجمال هو موضوع حساس إلى حد ما ، فليس هناك الكثير من مجموعات البيانات في المجال العام التي تحتوي على صور مع تقييم (أنا متأكد من أن خدمات التعارف عن طريق الإنترنت مثل tinder لديها مجموعات أكبر بكثير من الإحصاءات). لقد وجدت قاعدة بيانات مجمعة في إحدى جامعات الصين ، تحتوي على 5500 صورة فوتوغرافية ، تم تقييم كل منها بواسطة 7 مقيمين من بين الطلاب الصينيين. من بين 5500 صورة فوتوغرافية ، هناك 2000 رجل آسيوي (AM) ، و 2000 امرأة آسيوية (AF) ، و 750 رجلًا أوروبيًا (CM) و (CF) لكل منهما.

صورة

دعونا نقرأ البيانات باستخدام وحدة بيثون الباندا ونلقي نظرة سريعة على البيانات. التوزيع المقدر للأجناس والأجناس المختلفة:

import pandas as pd import matplotlib.pyplot as plt ratingDS=pd.read_excel('../input/faces-scut/scut-fbp5500_v2/SCUT-FBP5500_v2/All_Ratings.xlsx') Answer=ratingDS.groupby('Filename').mean()['Rating'] ratingDS['race']=ratingDS['Filename'].apply(lambda x:x[:2]) fig, ax = plt.subplots(2, 2, sharex='col') for i, race in enumerate(['CF','CM','AF','AM']): sbp=ax[i%2,i//2] ratingDS[ratingDS['race']==race].groupby('Filename')['Rating'].mean().hist(alpha=0.5, bins=20,label=race,grid=False,rwidth=0.9,ax=sbp) sbp.set_title(race) 

صورة

يمكن ملاحظة أن الرجال ، بشكل عام ، يعتبرون أقل جمالا من النساء ، والتوزيع ثنائي الكثافة - هناك هؤلاء. الذين يعتبرون جميلة و "المتوسط". لا توجد تقييمات منخفضة تقريبًا ، لذلك يمكن إعادة تصنيف البيانات. لكن دعنا نتركهم الآن.

دعونا نلقي نظرة على الانحراف المعياري في التقديرات:

 ratingDS.groupby('Filename')['Rating'].std().mean() 

إنه 0.64 ، مما يعني أن الفرق في تقييمات المقيّمين المختلفين هو أقل من نقطة واحدة من أصل 5 ، مما يشير إلى الإجماع في تقييمات الجمال. يمكن القول أن "الجمال ليس في عين الناظر". عند المتوسط ​​، يمكنك استخدام البيانات بشكل موثوق لتدريب النموذج وعدم القلق بشأن الاستحالة الأساسية للتقييم البرنامجي.

ومع ذلك ، على الرغم من القيمة الضئيلة للانحراف المعياري للتقدير ، يمكن أن يكون رأي بعض المقيمين مختلفًا تمامًا عن الرأي "العادي". دعونا نبني توزيع الفرق بين التقدير والوسط:

 R2=ratingDS.join(ratingDS.groupby('Filename')['Rating'].median(), on='Filename', how='inner',rsuffix =' median') R2['ratingdiff']=(R2['Rating median']-R2['Rating']).astype(int) print(set(R2['ratingdiff'])) R2['ratingdiff'].hist(label='difference of raings',bins=[-3.5,-2.5,-1.5,-0.5,0.5,1.5,2.5,3.5,4.5],grid=False,rwidth=0.5) 

صورة

تم العثور على نمط مثير للاهتمام. الأشخاص الذين تختلف درجاتهم عن الوسيط بأكثر من نقطة واحدة

 len(R2[R2['ratingdiff'].abs()>1])/len(R2) 

+0.029433333333333332
أقل من 3 ٪. وهذا هو ، وأكد الإجماع ضرب مرة أخرى في مسائل تقييم الجمال.
إنشاء جدول مع متوسط ​​التصنيفات اللازمة

 Answer=ratingDS.groupby('Filename').mean()['Rating'] 

قاعدة البيانات الخاصة بنا صغيرة ؛ بالإضافة إلى ذلك ، تحتوي جميع الصور على صور كاملة الوجه في الغالب ، وأود الحصول على نتيجة موثوق بها لأي موضع للوجه. لحل المشكلات المتعلقة بكمية صغيرة من البيانات ، غالبًا ما يتم استخدام تقنية تعلم النقل - استخدام نماذج تم تدريبها مسبقًا على مهام مماثلة وتعديلها. بالقرب من مهمتي هي مهمة التعرف على الوجوه. وعادة ما يتم حلها بطريقة ثلاثية المراحل.

1. هناك كشف للوجه على الصورة وتحجيمها.

2. باستخدام شبكة عصبية تلافيفية ، يتم تحويل صورة الوجه إلى متجه للميزات ، وخصائص مثل هذا التحول تجعل التحول ثابتًا فيما يتعلق بتدوير الوجه والتغيير في تصفيفة الشعر. مظاهر العواطف وأي صور مؤقتة. تعلم مثل هذه الشبكة هو مهمة مثيرة في حد ذاتها ، والتي يمكن كتابتها لفترة طويلة. بالإضافة إلى ذلك ، تظهر تطورات جديدة باستمرار لتحسين هذا التحويل لتحسين خوارزميات التعقب الشامل والتعرف. وهي تحسن كلاً من بنية الشبكة وطريقة التدريب (على سبيل المثال ، الخسارة الثلاثية - فقدان واجهة السطح).

3. مقارنة متجه الميزة مع تلك المخزنة في قاعدة البيانات.

لمهمتنا ، استخدمت حلول جاهزة من 1-2 نقاط. يتم حل مهمة اكتشاف الوجوه عمومًا بعدة طرق ، علاوة على ذلك ، يحتوي أي جهاز محمول تقريبًا على كاشفات للوجه (على Android ، فهي جزء من حزمة خدمات GooglePlay القياسية) ، والتي تستخدم للتركيز على الوجوه عند التصوير. أما بالنسبة لترجمة الأشخاص إلى شكل متجه ، فهناك نقطة خفية غير واضحة. الحقيقة هي أن العلامات. المستخرجة من أجل حل مشكلة الاعتراف - هي سمة للشخص ، لكنها قد لا ترتبط مع الجمال على الإطلاق. أكثر من ذلك. نظرًا لخصائص الشبكات العصبية التلافيفية ، تكون هذه العلامات محلية بشكل رئيسي ، ويمكن أن يسبب ذلك عمومًا العديد من المشكلات (هجوم البكسل الفردي). ومع ذلك ، فقد وجدت أن النتائج تعتمد اعتمادًا كبيرًا على البعد الخاص بالناقل ، وإذا لم تكن 128 علامة كافية لتحديد الجمال ، فإن 512 علامة كافية. بناءً على ذلك ، تم اختيار شبكة insightFace معتمدة على إعادة الضبط . سنستخدم أيضًا keras كإطار للتعلم الآلي.
يمكن الاطلاع هنا على رمز تفصيلي لتنزيل النماذج المدربة مسبقًا .

 model=LResNet100E_IR() 

تم استخدام كاشف الوجه mtcnn ككاشف للوجه للمعالجة المسبقة .

 detector = MtcnnDetector(model_folder=mtcnn_path, ctx=ctx, num_worker=1, accurate_landmark = True, threshold=det_threshold) 

محاذاة الصور وتقطيعها وتوجيهها من مجموعة البيانات:

 imgpath='../input/faces-scut/scut-fbp5500_v2/SCUT-FBP5500_v2/Images/' #    facevecs=[] for name in tqdm.tqdm(Answer.index): #   img1 = cv2.imread(imgpath+name) # ,     pre1 = np.moveaxis(get_input(detector,img1),0,-1) #  vec = model.predict(np.stack([pre1])) #   facevecs.append(vec) 

سنقوم بإعداد البيانات بتقسيمها إلى تدريب (90٪ منها ، وسندرسها) والتحقق من صحة (سنقوم بفحص عمل النموذج عليها). نحن تطبيع البيانات إلى مجموعة من 0-1.

 X=np.stack(facevecs)[:,0,:] Y=(Answer[:])/5 Indicies=np.arange(len(Answer)) X,Y,Indicies=sklearn.utils.shuffle(X,Y,Indicies) Xtrain=X[:int(len(facevecs)*0.9)] Ytrain=Y[:int(len(facevecs)*0.9)] Indtrain=Indicies[:int(len(facevecs)*0.9)] Xval=X[int(len(facevecs)*0.9):] Yval=Y[int(len(facevecs)*0.9):] Indval=Indicies[int(len(facevecs)*0.9):] 

الآن دعنا ننتقل إلى النموذج. تصف الجمال.

 def Createheadmodel(): inp=keras.layers.Input((512,)) x=keras.layers.Dense(32,activation='elu')(inp) x=keras.layers.Dropout(0.1)(x) out=keras.layers.Dense(1,activation='hard_sigmoid',use_bias=False,kernel_initializer=keras.initializers.Ones())(x) model=keras.models.Model(input=inp,output=out) model.layers[-1].trainable=False model.compile(optimizer=keras.optimizers.Adam(lr=0.0001), loss='mse') return model modelhead=Createheadmodel() 

هذا النموذج عبارة عن شبكة عصبية متصلة من طبقة واحدة تحتوي على 32 خلية عصبية و 512 عقدة إدخال - واحدة من أبسط البنى ، والتي ، مع ذلك ، مدربة تدريباً جيداً:

 hist=modelhead.fit(Xtrain,Ytrain, epochs=4000, batch_size=5000, validation_data=(Xval,Yval) ) 

4950/4950 [================================] - 0 ثانية 3us / step - خسارة: 0.0069 - val_loss: 0.0071
دعونا نبني منحنيات التعلم

 plt.plot(hist.history['loss'][100:], label='loss') plt.plot(hist.history['val_loss'][100:],label='validation_loss') plt.legend(bbox_to_anchor=(0.95, 0.95), loc='upper right', borderaxespad=0.) 

نرى أن الخسارة (يعني الانحراف المربعي) هي 0.0071 على بيانات التحقق ، وبالتالي فإن الانحراف المعياري = 0.084 أو 0.42 نقطة على مقياس من خمس نقاط ، وهو أقل من الفرق في التقديرات المقدمة من الناس (0.6 نقطة). نموذجنا يعمل.

لتصور كيفية عمل النموذج ، يمكنك استخدام المخطط المبعثر - لكل صورة من بيانات التحقق من الصحة ، نقوم ببناء نقطة حيث يتوافق أحد الإحداثيات مع متوسط ​​تقييم الوجه والثاني إلى متوسط ​​التقييم المتوقع:

 Answer2=Answer.to_frame()[:5500] Answer2['ans']=0 Answer2['race']=Answer2.index Answer2['race']=Answer2['race'].apply(lambda x: x[:2]) Answer2['ans']=modelhead.predict(np.stack(facevecs)[:,0,:])*5 xy=np.array(Answer2.iloc[Indval][['ans','Rating']]) plt.scatter(xy[:,1],xy[:,0]) 

صورة

المحور ص - القيم التي يتنبأ بها النموذج ، المحور س - متوسط ​​قيم تقديرات الناس. نرى علاقة عالية (الشكل ممدود على طول المائل). يمكنك أيضًا التحقق من نتائجنا بشكل مرئي - خذ وجوه كل فئة من الفئات بتقييمات متوقعة من 1 إلى 5

 import matplotlib.image as mpimg f, axarr = plt.subplots(4,5,figsize=(10, 10)) for i, race in enumerate(['AF','CF', "AM", 'CM']): for rating in range(1,6): #axarr[i,rating-1].axis('off') axarr[i,rating-1].tick_params(# changes apply to the x-axis which='both', # both major and minor ticks are affected bottom=False, # ticks along the bottom edge are off top=False, # ticks along the top edge are off right=False, left=False, labelbottom=False, labelleft=False ) picname=(Answer2[Answer2['race']==race]['ans']-rating).abs().argmin() axarr[i,rating-1].set_xlabel(Answer2.loc[picname]['ans']) axarr[i,rating-1].imshow(mpimg.imread(imgpath+picname)) 

صورة

نرى أن النتيجة بالفرز حسب الجمال تبدو معقولة.

سنقوم الآن بإنشاء نموذج كامل نقدم فيه وجهاً للإدخال ، وعند الإخراج نحصل على تقييم من 0 إلى 1 ونحوله إلى تنسيق tflite المناسب للهاتف

 import tensorflow as tf finmodel=Model(input=model.input, output=modelhead(model.output)) finmodel.save('finmodel.h5') converter = tf.lite.TFLiteConverter.from_keras_model_file('finmodel.h5') converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE] tflite_quant_model = converter.convert() open ("modelquant.tflite" , "wb").write(tflite_quant_model) from IPython.display import FileLink FileLink(r'modelquant.tflite') 

يتلقى هذا النموذج صورة لوجه بحجم 112 * 112 * 3 عند الإدخال ، وفي الخرج يعطي رقمًا واحدًا من 0 إلى 1 ، مما يعني جمال الوجه (على الرغم من أننا يجب أن نتذكر أنه في مجموعة البيانات ، لم تختلف التصنيفات من 0 إلى 5 ، ولكن من 1 إلى 5).

الجزء 2. جافا


دعنا نحاول كتابة تطبيق بسيط لهاتف Android. لغة Java جديدة بالنسبة لي ، ولم أشارك مطلقًا في تطوير نظام Android ، وبالتالي ، فإن المشروع لا يستخدم تحسين العمل ، ولا يستخدم التحكم في التدفق وأشياء أخرى كثيفة العمالة للمبتدئين. نظرًا لأن java code أمر مرهق إلى حد ما ، فسأقدم هنا أهم العناصر التي يعمل عليها البرنامج. رمز التطبيق الكامل متاح هنا . يفتح التطبيق صورة ويكتشف ويقيم وجهًا باستخدام شبكة محفوظة مسبقًا ويعرض النتيجة:

صورة

من وجهة نظر التطوير ، تعتبر الوظائف التالية مهمة في ذلك.

1. وظيفة تحميل الشبكة العصبية من ملف model.tflite في مجلد الأصول إلى كائن مترجم

 import org.tensorflow.lite.Interpreter; Interpreter interpreter; try { interpreter=new Interpreter(loadModelFile(MainActivity.this)); Log.e("TIME", "Interpreter_started "); } catch (IOException e) { e.printStackTrace(); Log.e("TIME", "Interpreter NOT started "); } private MappedByteBuffer loadModelFile(Activity activity) throws IOException { AssetFileDescriptor fileDescriptor = activity.getAssets().openFd("model.tflite"); FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor()); FileChannel fileChannel = inputStream.getChannel(); long startOffset = fileDescriptor.getStartOffset(); long declaredLength = fileDescriptor.getDeclaredLength(); return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength); } 

2. الكشف عن الوجوه باستخدام وحدة FaceDetector ، التي تعد جزءًا من حزمة المكتبة القياسية من google ، باستخدام شبكة عصبية وعرض النتائج.

 import com.google.android.gms.vision.face.Face; import com.google.android.gms.vision.face.FaceDetector; private void detectFace(){ //Create a Paint object for drawing with Paint myRectPaint = new Paint(); myRectPaint.setStrokeWidth(5); myRectPaint.setColor(Color.GREEN); myRectPaint.setStyle(Paint.Style.STROKE); Paint fontPaint = new Paint(); fontPaint.setStrokeWidth(3); fontPaint.setTextSize(70); fontPaint.setColor(Color.BLUE); fontPaint.setStyle(Paint.Style.FILL_AND_STROKE); //Create a Canvas object for drawing on tempBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), Bitmap.Config.RGB_565); Canvas tempCanvas = new Canvas(tempBitmap); tempCanvas.drawBitmap(myBitmap, 0, 0, null); //Detect the Faces FaceDetector faceDetector = new FaceDetector.Builder(getApplicationContext()).build(); Frame frame = new Frame.Builder().setBitmap(myBitmap).build(); SparseArray<Face> faces = faceDetector.detect(frame); Face face; float[][] labelProbArray = new float[1][1]; imgData.order(ByteOrder.nativeOrder()); //Draw Rectangles on the Faces if (faces.size()>0){ for (int i = 0; i < faces.size(); i++) { face = faces.valueAt(i); isFaceFound=true; float x1 = Math.max(face.getPosition().x,0); float y1 = Math.max(face.getPosition().y,0); float x2 = Math.min(x1 + face.getWidth(),frame.getBitmap().getWidth()); float y2 = Math.min(y1 + face.getHeight(),frame.getBitmap().getHeight()); Bitmap tempbitmap2 = Bitmap.createBitmap(tempBitmap, (int)x1, (int)y1, (int) (x2-x1), (int) (y2-y1)); tempbitmap2 = Bitmap.createScaledBitmap(tempbitmap2, 112, 112, true); convertBitmapToByteBuffer(tempbitmap2); interpreter.run(imgData, labelProbArray); String textToShow = String.format("%.1f", (Answer[0][0]*5-1)/4 * 10); textToShow = textToShow + "/10"; int width= tempCanvas.getWidth(); //int height=tempCanvas.getHeight(); int fontsize=Math.max(width/20,imgView.getWidth()/20); fontPaint.setTextSize(fontsize); tempCanvas.drawText(textToShow, x1, y1-10, fontPaint); tempCanvas.drawRoundRect(new RectF(x1, y1, x2, y2), 2, 2, myRectPaint) } imgView.setImageDrawable(new BitmapDrawable(getResources(),tempBitmap)); } } 

إذا كنت ترغب في اللعب باستخدام التقدير على هاتفك ، فيمكنك تنزيل التطبيق من سوق GooglePlay .

Source: https://habr.com/ru/post/ar485858/


All Articles