Bagaimana cara mengajar telepon untuk melihat keindahan

gambar

Baru-baru ini, saya membaca sebuah buku tentang matematika dan keindahan orang-orang dan berpikir tentang apa yang sepuluh tahun lalu, gagasan tentang bagaimana memahami kecantikan manusia apa yang cukup primitif. Penalaran tentang wajah mana yang dianggap indah dari sudut pandang matematika sampai pada fakta bahwa itu harus simetris. Juga, sejak Renaissance, ada upaya untuk menggambarkan wajah cantik menggunakan hubungan antara jarak pada beberapa titik di wajah dan menunjukkan, misalnya, bahwa wajah cantik memiliki semacam hubungan dekat dengan rasio emas. Gagasan serupa tentang lokasi titik sekarang digunakan sebagai salah satu metode untuk mengidentifikasi wajah (pencarian landmark wajah). Namun, seperti yang ditunjukkan oleh pengalaman, jika Anda tidak membatasi serangkaian tanda pada posisi titik tertentu pada wajah, Anda dapat mencapai hasil yang lebih baik dalam sejumlah tugas, termasuk menentukan usia, jenis kelamin atau bahkan orientasi seksual . Sudah jelas di sini bahwa masalah etika penerbitan hasil-hasil studi semacam itu mungkin bersifat akut.

Topik kecantikan orang dan penilaiannya juga bisa menjadi kontroversial secara etis. Saat mengembangkan aplikasi, banyak teman saya menolak untuk menggunakan foto mereka untuk tes, atau hanya tidak ingin tahu hasilnya (lucu bahwa sebagian besar perempuan menolak untuk mengetahui hasilnya). Juga, tujuan penilaian kecantikan otomatis dapat menimbulkan pertanyaan filosofis yang menarik. Sejauh mana konsep kecantikan ditentukan oleh budaya? Seberapa benar “Kecantikan di mata yang melihatnya”? Apakah mungkin untuk menyoroti tanda-tanda keindahan objektif?

Untuk menjawab pertanyaan ini, Anda perlu mempelajari statistik tentang peringkat beberapa orang oleh orang lain. Saya mencoba merancang dan melatih model jaringan saraf yang akan mengevaluasi kecantikan, serta menjalankannya di ponsel android.

Bagian 0. Pipa


Untuk memahami bagaimana langkah-langkah selanjutnya terkait satu sama lain, saya menggambar diagram proyek:

gambar

Biru - perpustakaan penting dan data eksternal. Kuning - kontrol dalam aplikasi.

Bagian 1. Python


Karena penilaian kecantikan adalah topik yang agak rumit, tidak ada terlalu banyak kumpulan data di domain publik yang berisi foto dengan penilaian (saya yakin bahwa layanan kencan online seperti pekerja tambang memiliki set statistik yang jauh lebih besar). Saya menemukan database yang dikompilasi di salah satu universitas di China, yang berisi 5.500 foto, masing-masing dievaluasi oleh 7 evaluator dari kalangan mahasiswa Tiongkok. Dari 5.500 foto, 2.000 adalah pria Asia (AM), 2000 adalah wanita Asia (AF), dan 750 pria Europioid (CM) dan wanita (CF) masing-masing.

gambar

Mari kita baca data menggunakan modul Python panda dan lihat datanya. Perkiraan distribusi untuk jenis kelamin dan ras yang berbeda:

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) 

gambar

Dapat dilihat bahwa, secara umum, pria dianggap kurang cantik daripada wanita, distribusinya adalah bimodal - ada yang seperti itu. yang dianggap cantik dan "rata-rata". Hampir tidak ada peringkat rendah, sehingga data dapat dinormalisasi ulang. Tapi mari kita tinggalkan mereka untuk saat ini.

Mari kita lihat deviasi standar dalam perkiraan:

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

Itu adalah 0,64, yang berarti bahwa perbedaan dalam penilaian evaluator yang berbeda kurang dari 1 poin dari 5, yang menunjukkan kebulatan suara dalam penilaian keindahan. Dapat dikatakan bahwa "kecantikan TIDAK di mata yang melihatnya." Saat membuat rata-rata, Anda dapat menggunakan data dengan andal untuk melatih model dan tidak khawatir tentang ketidakmungkinan mendasar dari evaluasi program.

Namun, meskipun nilai standar deviasi estimasi kecil, pendapat beberapa evaluator bisa sangat berbeda dari yang "biasa". Mari kita bangun distribusi perbedaan antara taksiran dan median:

 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) 

gambar

Pola yang menarik ditemukan. Orang yang nilainya berbeda dari median lebih dari 1 poin

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

0,02943333333333333332
Kurang dari 3%. Artinya, kebulatan suara yang mencolok sekali lagi dikonfirmasi dalam hal menilai keindahan.
Buat tabel dengan peringkat rata-rata yang diperlukan

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

Basis data kami kecil; Selain itu, semua foto sebagian besar berisi gambar wajah penuh, dan saya ingin hasil yang dapat diandalkan untuk setiap posisi wajah. Untuk memecahkan masalah dengan sejumlah kecil data, teknik transfer pembelajaran sering digunakan - penggunaan model yang sudah dilatih sebelumnya untuk tugas yang serupa dan modifikasinya. Dekat dengan tugas saya adalah tugas pengenalan wajah. Biasanya diselesaikan dengan tiga tahap.

1. Ada deteksi wajah pada gambar dan penskalaannya.

2. Menggunakan jaringan saraf convolutional, gambar wajah diubah menjadi vektor fitur, dan sifat-sifat dari transformasi tersebut sedemikian rupa sehingga transformasi tidak berubah sehubungan dengan rotasi wajah dan perubahan gaya rambut. manifestasi emosi dan gambar sementara. Mempelajari jaringan semacam itu adalah tugas yang menarik, yang dapat ditulis untuk waktu yang lama. Selain itu, perkembangan baru terus muncul untuk meningkatkan konversi ini untuk meningkatkan pelacakan massa dan algoritma identifikasi. Mereka mengoptimalkan arsitektur jaringan dan metode pelatihan (mis. Triplet loss -cosface-arcface loss).

3. Perbandingan vektor fitur dengan yang disimpan dalam database.

Untuk tugas kami, saya menggunakan solusi siap pakai 1-2 poin. Tugas mendeteksi wajah pada umumnya diselesaikan dengan banyak cara, apalagi, hampir semua perangkat seluler memiliki detektor wajah (di Android mereka adalah bagian dari paket layanan GooglePlay standar), yang digunakan untuk fokus pada wajah saat memotret. Adapun terjemahan orang ke dalam bentuk vektor, ada satu titik halus yang tidak jelas. Faktanya adalah bahwa tanda-tandanya. diekstraksi untuk memecahkan masalah pengenalan - adalah karakteristik seseorang, tetapi mereka mungkin tidak berkorelasi dengan kecantikan sama sekali. apalagi karena kekhasan jaringan saraf convolutional, tanda-tanda ini terutama bersifat lokal, dan secara umum hal ini dapat menyebabkan banyak masalah (serangan piksel tunggal). Namun demikian, saya menemukan bahwa hasilnya sangat tergantung pada dimensi vektor, dan jika 128 tanda tidak cukup untuk menentukan keindahan, 512 sudah cukup. Berdasarkan hal ini, jaringan insightFace berbasis Reset yang dilatih sebelumnya telah dipilih. Kami juga akan menggunakan keras sebagai kerangka belajar mesin.
Kode terperinci untuk mengunduh model pra-terlatih dapat ditemukan di sini.

 model=LResNet100E_IR() 

Detektor wajah mtcnn digunakan sebagai detektor wajah untuk preprocessing .

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

Sejajarkan, pangkas, dan vektorkan gambar dari dataset:

 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) 

Kami akan menyiapkan data dengan memecahnya menjadi pelatihan (90% dari mereka, kami akan mempelajarinya) dan validasi (kami akan memeriksa kerja model pada mereka) vektor. Kami menormalkan data hingga rentang 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):] 

Sekarang mari kita beralih ke model. menggambarkan keindahan.

 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() 

Model ini adalah jaringan saraf satu-lapis yang terhubung penuh dengan 32 neuron dan 512 node input - salah satu arsitektur paling sederhana, yang, bagaimanapun, terlatih dengan baik:

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

4950/4950 [===============================] - 0s 3us / langkah - kerugian: 0,0069 - val_loss: 0,0071
Mari kita membangun kurva belajar

 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.) 

Kita melihat bahwa kerugian (deviasi kuadrat rata-rata) adalah 0,0071 pada data validasi, oleh karena itu deviasi standar = 0,084 atau 0,42 poin pada skala lima poin, yang kurang dari sebaran dalam estimasi yang diberikan oleh orang (0,6 poin). Model kami berfungsi.

Untuk memvisualisasikan cara kerja model, Anda dapat menggunakan diagram hamburan - untuk setiap foto dari data validasi, kami membuat titik di mana salah satu koordinat terkait dengan rata-rata nilai permukaan dan yang kedua ke rata-rata peringkat yang diprediksi:

 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]) 

gambar

Sumbu Y - nilai yang diprediksi oleh model, sumbu X - nilai rata-rata estimasi orang. Kami melihat korelasi yang tinggi (diagram memanjang di sepanjang diagonal). Anda juga dapat memeriksa hasil kami secara visual - ambil wajah dari masing-masing kategori dengan peringkat yang diperkirakan dari 1 hingga 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)) 

gambar

Kita melihat bahwa hasil dengan memilah berdasarkan kecantikan terlihat masuk akal.

Sekarang kita akan membuat model lengkap di mana kita mengirimkan wajah ke input, pada output kita mendapatkan peringkat dari 0 ke 1 dan mengubahnya menjadi format tflite yang sesuai untuk telepon

 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') 

Model ini menerima gambar wajah ukuran 112 * 112 * 3, dan pada outputnya memberikan angka tunggal dari 0 hingga 1, yang berarti keindahan wajah (walaupun harus diingat bahwa dalam set data peringkatnya tidak bervariasi dari 0 hingga 5, tetapi dari 1 hingga 5).

Bagian 2. JAVA


Mari kita coba menulis aplikasi sederhana untuk ponsel Android. Bahasa Java baru bagi saya, dan saya tidak pernah terlibat dalam pengembangan untuk android, jadi proyek ini tidak menggunakan optimasi kerja, tidak menggunakan kontrol aliran dan hal-hal lain yang padat karya untuk pemula. Karena kode java agak rumit, di sini saya hanya akan memberikan bagian yang paling penting untuk program untuk bekerja. Kode aplikasi lengkap tersedia di sini . Aplikasi membuka foto, mendeteksi dan mengevaluasi wajah menggunakan jaringan yang disimpan sebelumnya dan menampilkan hasilnya:

gambar

Dari sudut pandang pengembangan, fungsi-fungsi berikut ini penting di dalamnya.

1. Fungsi memuat jaringan saraf dari model file.tflite dalam folder aset ke objek juru bahasa

 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. Mendeteksi wajah menggunakan modul FaceDetector, yang merupakan bagian dari paket pustaka standar dari google, menggunakan jaringan saraf dan menampilkan hasilnya.

 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)); } } 

Jika Anda ingin bermain dengan penilaian pada ponsel Anda, Anda dapat mengunduh aplikasi dari pasar GooglePlay .

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


All Articles