日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > pytorch >内容正文

pytorch

【CV】使用Keras和迁移学习从人脸图像中预测体重指数BMI

發布時間:2025/3/8 pytorch 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【CV】使用Keras和迁移学习从人脸图像中预测体重指数BMI 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:Leo Simmons? ?編譯:ronghuaiyang

導讀

和人臉屬性預測非常相似的一個應用。

這篇文章描述了一個神經網絡,它可以通過人臉圖像預測一個人的BMI([身體質量指數])。這個項目借鑒了另一個項目:https://github.com/yu4u/age-gender-estimation的方法,通過人臉來對一個人的年齡和性別進行分類,這個項目包括一個訓練過的模型的權重和一個腳本,該腳本用攝像頭動態檢測用戶的臉。這除了是一個有趣的機器學習問題外,以這種方式預測BMI可能是一個有用的醫學診斷工具。

訓練數據

使用的訓練數據是4000張圖像,每張都是不同個體的圖像,都是從受試者的正面拍攝的。每個訓練樣本的BMI由受試者的身高和體重計算(BMI是體重(kg)除以身高(米)的平方)。雖然訓練圖像不能在這里分享,因為它們被用于另一個私人項目,但這種類型的數據可以從網上的不同地方收集。

圖形預處理

為了在訓練前對圖像進行歸一化,將每張圖像裁剪到受試者的面部,不包括面部周圍的區域。使用Python庫dlib檢測每幅圖像中的受試者的面部,并在dlib檢測到的邊界周圍添加額外的邊界,以生成用于實際訓練圖像。我們實驗了幾個邊距,看看哪個能讓網絡表現得最好。我們選擇了20%的邊距,即圖像的高度和寬度擴大40%(每邊都是20%),因為它能產生最佳的驗證性能。

下面顯示了使用不同裁剪邊緣添加到 Bill Murray 的圖像中,還有一個表格,顯示了添加了不同的邊距在驗證集上模型可以達到的最小的平均絕對誤差(MAE)。

原始圖像

使用不同的Margin進行裁剪的圖像

使用不同的Margin的圖像進行訓練的最低MAE

雖然在20%-50%的margin范圍內的MAE值可能太過接近,不能說任何一個都比其他的好,但很明顯,至少增加20%的margin 會比不增加margin 產生更好的MAE。這可能是因為增加的margin 捕獲了前額上部、耳朵和頸部等特征,這些特征對模型預測BMI很有用,但大部分被原始的dlib裁剪掉了。

圖像預處理代碼:

import os import cv2 import dlib from matplotlib import pyplot as plt import numpy as np import configdetector = dlib.get_frontal_face_detector()def crop_faces():bad_crop_count = 0if not os.path.exists(config.CROPPED_IMGS_DIR):os.makedirs(config.CROPPED_IMGS_DIR)print 'Cropping faces and saving to %s' % config.CROPPED_IMGS_DIRgood_cropped_images = []good_cropped_img_file_names = []detected_cropped_images = []original_images_detected = []for file_name in sorted(os.listdir(config.ORIGINAL_IMGS_DIR)):np_img = cv2.imread(os.path.join(config.ORIGINAL_IMGS_DIR,file_name))detected = detector(np_img, 1)img_h, img_w, _ = np.shape(np_img)original_images_detected.append(np_img)if len(detected) != 1:bad_crop_count += 1continued = detected[0]x1, y1, x2, y2, w, h = d.left(), d.top(), d.right() + 1, d.bottom() + 1, d.width(), d.height()xw1 = int(x1 - config.MARGIN * w)yw1 = int(y1 - config.MARGIN * h)xw2 = int(x2 + config.MARGIN * w)yw2 = int(y2 + config.MARGIN * h)cropped_img = crop_image_to_dimensions(np_img, xw1, yw1, xw2, yw2)norm_file_path = '%s/%s' % (config.CROPPED_IMGS_DIR, file_name)cv2.imwrite(norm_file_path, cropped_img)good_cropped_img_file_names.append(file_name)# save info of good cropped imageswith open(config.ORIGINAL_IMGS_INFO_FILE, 'r') as f:column_headers = f.read().splitlines()[0]all_imgs_info = f.read().splitlines()[1:]cropped_imgs_info = [l for l in all_imgs_info if l.split(',')[-1] in good_cropped_img_file_names]with open(config.CROPPED_IMGS_INFO_FILE, 'w') as f:f.write('%s\n' % column_headers)for l in cropped_imgs_info:f.write('%s\n' % l)print 'Cropped %d images and saved in %s - info in %s' % (len(original_images_detected), config.CROPPED_IMGS_DIR, config.CROPPED_IMGS_INFO_FILE)print 'Error detecting face in %d images - info in Data/unnormalized.txt' % bad_crop_countreturn good_cropped_images# image cropping function taken from: # https://stackoverflow.com/questions/15589517/how-to-crop-an-image-in-opencv-using-python def crop_image_to_dimensions(img, x1, y1, x2, y2):if x1 < 0 or y1 < 0 or x2 > img.shape[1] or y2 > img.shape[0]:img, x1, x2, y1, y2 = pad_img_to_fit_bbox(img, x1, x2, y1, y2)return img[y1:y2, x1:x2, :]def pad_img_to_fit_bbox(img, x1, x2, y1, y2):img = cv2.copyMakeBorder(img, - min(0, y1), max(y2 - img.shape[0], 0),-min(0, x1), max(x2 - img.shape[1], 0), cv2.BORDER_REPLICATE)y2 += -min(0, y1)y1 += -min(0, y1)x2 += -min(0, x1)x1 += -min(0, x1)return img, x1, x2, y1, y2if __name__ == '__main__':crop_faces()

圖像增強

為了增加每個原始訓練圖像用于網絡訓練的次數,在每個訓練epoch中對圖像進行增強。圖像增強庫Augmentor用于動態旋轉、翻轉和扭曲圖像不同部分的分辨率,并改變圖像的對比度和亮度。

沒有增強

隨機增強

圖像增強代碼:

from keras.preprocessing.image import ImageDataGenerator import pandas as pd import Augmentor from PIL import Image import random import numpy as np import matplotlib.pyplot as plt import math import configdef plot_imgs_from_generator(generator, number_imgs_to_show=9):print ('Plotting images...')n_rows_cols = int(math.ceil(math.sqrt(number_imgs_to_show)))plot_index = 1x_batch, _ = next(generator)while plot_index <= number_imgs_to_show:plt.subplot(n_rows_cols, n_rows_cols, plot_index)plt.imshow(x_batch[plot_index-1])plot_index += 1plt.show()def augment_image(np_img):p = Augmentor.Pipeline()p.rotate(probability=1, max_left_rotation=5, max_right_rotation=5)p.flip_left_right(probability=0.5)p.random_distortion(probability=0.25, grid_width=2, grid_height=2, magnitude=8)p.random_color(probability=1, min_factor=0.8, max_factor=1.2)p.random_contrast(probability=.5, min_factor=0.8, max_factor=1.2)p.random_brightness(probability=1, min_factor=0.5, max_factor=1.5)image = [Image.fromarray(np_img.astype('uint8'))]for operation in p.operations:r = round(random.uniform(0, 1), 1)if r <= operation.probability:image = operation.perform_operation(image)image = [np.array(i).astype('float64') for i in image]return image[0]image_processor = ImageDataGenerator(rescale=1./255,preprocessing_function=augment_image)# subtract validation size from training data with open(config.CROPPED_IMGS_INFO_FILE) as f:for i, _ in enumerate(f):passtraining_n = i - config.VALIDATION_SIZEtrain_df=pd.read_csv(config.CROPPED_IMGS_INFO_FILE, nrows=training_n)train_generator=image_processor.flow_from_dataframe(dataframe=train_df,directory=config.CROPPED_IMGS_DIR,x_col='name',y_col='bmi',class_mode='other',color_mode='rgb',target_size=(config.RESNET50_DEFAULT_IMG_WIDTH,config.RESNET50_DEFAULT_IMG_WIDTH),batch_size=config.TRAIN_BATCH_SIZE)

模型結構

模型是使用Keras ResNet50類創建的。選擇ResNet50架構,權重是由一個年齡分類器訓練得到的,來自年齡和性別的項目可用于遷移學習,也因為ResNet(殘差網絡)架構對于人臉圖像識別是很好的模型。

其他網絡架構在基于人臉的圖像分類任務上也取得了令人印象深刻的結果,未來的工作可以探索其中的一些結構用于BMI 指數的預測。

實現模型架構代碼:

from tensorflow.python.keras.models import Model from tensorflow.python.keras.applications import ResNet50 from tensorflow.python.keras.layers import Dense import configdef get_age_model():# adapted from https://github.com/yu4u/age-gender-estimation/blob/master/age_estimation/model.pyage_model = ResNet50(include_top=False,weights='imagenet',input_shape=(config.RESNET50_DEFAULT_IMG_WIDTH, config.RESNET50_DEFAULT_IMG_WIDTH, 3),pooling='avg')prediction = Dense(units=101,kernel_initializer='he_normal',use_bias=False,activation='softmax',name='pred_age')(age_model.output)age_model = Model(inputs=age_model.input, outputs=prediction)age_model.load_weights(config.AGE_TRAINED_WEIGHTS_FILE)print 'Loaded weights from age classifier'return age_modeldef get_model():base_model = get_age_model()last_hidden_layer = base_model.get_layer(index=-2)base_model = Model(inputs=base_model.input,outputs=last_hidden_layer.output)prediction = Dense(1, kernel_initializer='normal')(base_model.output)model = Model(inputs=base_model.input, outputs=prediction)return model

遷移學習

遷移學習是為了利用年齡分類器網絡中的權重,因為這些對于檢測用于預測BMI的低級面部特征應該是有價值的。為年齡網絡加一個新的線性回歸輸出層(輸出一個代表BMI的數字),并使用MAE作為損失函數和Adam作為訓練優化器進行訓練。

首先對模型進行訓練,使原始年齡分類器的每一層都被凍結,以允許新輸出層的隨機權值進行更新。第一次訓練包含了10個epoch,因為在此之后,MAE沒有明顯的下降(使用early stop)。

在這個初始訓練階段之后,模型被訓練了30個epoch,網絡中的每一層都被解凍,以微調網絡中的所有權重。Early stopping也決定了這里的epoch的數量,只有在觀察到MAE沒有減少的10個epoch后才停止訓練(patience為10)。由于模型在epoch 20達到了最低的驗證性MAE,訓練在epoch 30停止。取模型在epoch 20的權重,并在下面的演示中使用。

平均絕對誤差被選作為損失函數,和均方誤差(MSE)或均方根誤差(RMSE)不一樣,BMI預測的誤差的尺度是線性的(誤差為10的懲罰應該是誤差為5的懲罰的2倍)。

模型訓練代碼:

import cv2 import numpy as np from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint, TensorBoard from train_generator import train_generator, plot_imgs_from_generator from mae_callback import MAECallback import configbatches_per_epoch=train_generator.n //train_generator.batch_sizedef train_top_layer(model):print 'Training top layer...'for l in model.layers[:-1]:l.trainable = Falsemodel.compile(loss='mean_absolute_error',optimizer='adam')mae_callback = MAECallback()early_stopping_callback = EarlyStopping(monitor='val_mae',mode='min',verbose=1,patience=1)model_checkpoint_callback = ModelCheckpoint('saved_models/top_layer_trained_weights.{epoch:02d}-{val_mae:.2f}.h5',monitor='val_mae',mode='min',verbose=1,save_best_only=True)tensorboard_callback = TensorBoard(log_dir=config.TOP_LAYER_LOG_DIR,batch_size=train_generator.batch_size)model.fit_generator(generator=train_generator,steps_per_epoch=batches_per_epoch,epochs=20,callbacks=[mae_callback,early_stopping_callback,model_checkpoint_callback,tensorboard_callback])def train_all_layers(model):print 'Training all layers...'for l in model.layers:l.trainable = Truemae_callback = MAECallback()early_stopping_callback = EarlyStopping(monitor='val_mae',mode='min',verbose=1,patience=10)model_checkpoint_callback = ModelCheckpoint('saved_models/all_layers_trained_weights.{epoch:02d}-{val_mae:.2f}.h5',monitor='val_mae',mode='min',verbose=1,save_best_only=True)tensorboard_callback = TensorBoard(log_dir=config.ALL_LAYERS_LOG_DIR,batch_size=train_generator.batch_size)model.compile(loss='mean_absolute_error',optimizer='adam')model.fit_generator(generator=train_generator,steps_per_epoch=batches_per_epoch,epochs=100,callbacks=[mae_callback,early_stopping_callback,model_checkpoint_callback,tensorboard_callback])

Demo

下面是模型通過Christian Bale的幾張照片預測出的體重指數。之所以選擇貝爾作為研究對象,是因為眾所周知,他會在不同的角色中劇烈地改變自己的體重。知道了他的身高是6英尺0英寸,他的體重就可以從模型的BMI預測中得到。

左邊的圖片來自機械師,其中貝爾說他“大概135磅”。如果他的體重是135磅,那么他的BMI是18.3 kg/m (BMI的單位),而模型的預測相差約4 kg/m。中間的圖片是我認為代表他的體重,當時他沒有為一個角色徹底改變它。右邊的圖片是在拍攝Vice時拍攝的。在拍攝Vice的時候,我找不到他的體重數字,但我找到幾個消息來源說他胖了45磅。如果我們假設他的平均體重是200磅,而在拍攝Vice時他體重是245磅,體重指數為33.2,那么模型對這張照片的體重指數預測將相差約1 kg/m2。

下面是我的BMI預測模型的記錄。我的身體質量指數是23 kg/m2,當我直視相機時,模型偏差2~4 kg/m2,當我的頭偏向一邊或者朝下時,偏差高達8kg/m2。

討論

該模型的驗證MAE為4.48。給定一個人,5“9和195磅,美國男性的平均身高和體重,BMI 為27.35kg/m2,這4.48的錯誤將導致預測范圍為22.87 kg/m2 到 31.83 kg/m2,對應163和227磅重量。顯然,還有改進的余地,今后的工作將努力減少這種錯誤。

該模型的一個明顯缺點是,當評估從不同角度而不是從被攝者的正面拍攝的圖像時,性能很差。當我把頭移到一邊或往下時,模型的預測就變得不那么準確了。

這個模型的另一個可能的缺點可能有助于解釋這個模型對 Christian Bale的第一張照片的不準確的預測,那就是當主體在黑暗的環境中被一個集中的光源照射時,表現不佳。強烈的光照造成的陰影改變了臉的兩側的曲率和皮膚的微妙的表現,造成了對BMI的影響。

也有可能這個模型只是簡單地高估了總體BMI較低的受試者的BMI,這可以從它對我自己和克里斯蒂安·貝爾的第一張照片的評估中看出。

該模型的這些缺點可能可以用訓練數據中奇怪的角度、集中的光線和較低的BMIs來解釋。大多數訓練圖像是在良好的光照下,從受試者的前部拍攝的,并且是由BMI高于25 kg/m2的受試者拍攝的。因此,在這些不同的場景中,該模型可能無法充分了解面部特征與BMI的相關性。

—END—

英文原文:https://medium.com/@leosimmons/estimating-body-mass-index-from-face-images-using-keras-and-transfer-learning-de25e1bc0212

往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統計學習方法》的代碼復現專輯 AI基礎下載機器學習的數學基礎專輯獲取一折本站知識星球優惠券,復制鏈接直接打開:https://t.zsxq.com/662nyZF本站qq群1003271085。加入微信群請掃碼進群:

總結

以上是生活随笔為你收集整理的【CV】使用Keras和迁移学习从人脸图像中预测体重指数BMI的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。