<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于OpenVINO在英特爾開發套件上實現眼部追蹤

英特爾物聯網 ? 來源:英特爾物聯網 ? 2023-09-18 10:11 ? 次閱讀

作者:汕頭大學 22級電子信息工程 羅毅成

本文將以訓練一個眼部追蹤 AI 小模型為背景,介紹從 Pytorch 自定義網絡模型,到使用 OpenVINO NNCF 量化工具優化模型,并部署到英特爾開發套件愛克斯開發板 AIxBoard 的流程。

本項目已開源:RedWhiteLuo/HeadEyeTrack (github.com)

開發環境:Windows 11 + Pycharm。模型訓練平臺為 12700H,部署平臺為 AIxBoard愛克斯板。

AIxBoard愛克斯板開發者套介紹

此開發人員套件采用英特爾 賽揚 處理器 N 系列,已通過 Ubuntu* Desktop 和 OpenVINO 工具套件的預驗證,有助于在教育方面取得更多成績。這一組合為學生提供了在 AI、視覺處理和物聯網領域培養編程技能和設計解決方案原型所需的性能。

開始的開始當然是開箱啦~~

01確定整體的流程

在 V1.0 版本中,我將眼部圖片直接用來訓練神經網絡,發現結果并不理想,經過檢查后發現由于頭部的朝向會朝著目光方向偏轉,導致訓練集中的樣本分布差異很小,由此導致結果并不理想,于是在 V1.5 版本中采用了復合的模型結構,以此引入頭部的位置信息:

02模型結構

以網絡上已有的項目 “lookie-lookie” 為參考,通過查看其源碼可以得知該項目所使用的網絡結構, 我們可以以此為基礎進行修改。

因此,在 Pytroch 中我們可以繼承 nn.Module 并定義如下的模型:

class EyeImageModel(nn.Module):
  def __init__(self):
    super(EyeImageModel, self).__init__()
    self.model = Sequential(
      # in-> [N, 3, 32, 128]
      BatchNorm2d(3),
      Conv2d(3, 2, kernel_size=(5, 5), padding=2),
      LeakyReLU(),
      MaxPool2d(kernel_size=(2, 2), stride=(2, 2)),
      Conv2d(2, 20, kernel_size=(5, 5), padding=2),
      ELU(),
      Conv2d(20, 10, kernel_size=(5, 5), padding=2),
      Tanh(),
      Flatten(1, 3),
      Dropout(0.01),
      Linear(10240, 1024),
      Softplus(),
      Linear(1024, 2),
    )


  def forward(self, x):
    return self.model(x)




class PositionOffset(nn.Module):
  def __init__(self):
    super(PositionOffset, self).__init__()
    self.model = Sequential(
      Conv2d(1, 32, kernel_size=(2, 2), padding=0),
      Softplus(),
      Conv2d(32, 64, kernel_size=(2, 2), padding=1),
      Conv2d(64, 64, kernel_size=(2, 2), padding=0),
      ELU(),
      Conv2d(64, 128, kernel_size=(2, 2), padding=0),
      Tanh(),
      Flatten(1, 3),
      Dropout(0.01),
      Linear(128, 32),
      Sigmoid(),
      Linear(32, 2),
    )


  def forward(self, x):
    return self.model(x)




class EyeTrackModel(nn.Module):
  def __init__(self):
    super(EyeTrackModel, self).__init__()
    self.eye_img_model = EyeImageModel()
    self.position_offset = PositionOffset()


  def forward(self, x):
    eye_img_result = self.eye_img_model(x[0])
    end = torch.cat((eye_img_result, x[1]), dim=1)
    end = torch.reshape(end, (-1, 1, 3, 3))
    end = self.position_offset(end)
    return end

向右滑動查看完整代碼

由兩個小模型組成一個復合模型,EyeImageModel 負責將眼部圖片轉換成兩個參數,在 EyeTrackModel 中與頭部位置信息組成一個 N*1*3*3 的矩陣,在 PositionOffset 中進行卷積操作,并將結果返回。

03訓練數據集的獲取

定義好了網絡結構后,我們需要去獲取足夠的數據集,通過 Peppa_Pig_Face_Landmark 這個項目可以很容易地獲取臉部 98 個關鍵點。

610265158/Peppa_Pig_Face_Landmark: A simple face detect and alignment method, which is easy and stable. (github.com)

通過讓目光跟隨鼠標位置,實時獲取圖片與鼠標位置并進行保存,我們便可以快捷地獲取到數據集。

為了盡量保持有效信息的占比,我們先分別截取兩個眼睛的圖片后 再拼接成一張圖片,即刪去鼻梁部分的位置,再進行保存,通過這種方法可以一定程度減少由頭部偏轉帶來眼部圖片的過度畸變。

def save_img_and_coords(img, coords, annot, saved_img_index):
  img_save_path = './dataset/img/' + '%d.png' % saved_img_index
  annot_save_path = './dataset/annot/' + '%d.txt' % saved_img_index
  cv2.imwrite(img_save_path, img)
  np.savetxt(annot_save_path, np.array([*coords, *annot]))
  print("[INFO] | SAVED:", saved_img_index)

向右滑動查看完整代碼

def trim_eye_img(image, face_kp):
  """
  :param image: [H W C] 格式人臉圖片
  :param face_kp: 面部關鍵點
  :return: 拼接后的圖片 [H W C] 格式
  """
  l_l, l_r, l_t, l_b = return_boundary(face_kp[60:68])
  r_l, r_r, r_t, r_b = return_boundary(face_kp[68:76])
  left_eye_img = image[int(l_t):int(l_b), int(l_l):int(l_r)]
  right_eye_img = image[int(r_t):int(r_b), int(r_l):int(r_r)]
  left_eye_img = cv2.resize(left_eye_img, (64, 32), interpolation=cv2.INTER_AREA)
  right_eye_img = cv2.resize(right_eye_img, (64, 32), interpolation=cv2.INTER_AREA)
  return np.concatenate((left_eye_img, right_eye_img), axis=1)

向右滑動查看完整代碼

這一步將保存的文件命名為 index.png 和 index.txt,并保存在 /img 和 /annot 兩個子文件夾中。

需要注意的是,使用 cv2.VideoCapture() 的時候,獲取的圖片默認是(640,480)大小的。經過 FaceLandMark 后得到的眼部圖片過于模糊,因此需要手動指定攝像頭的分辨率:

vide_capture = cv2.VideoCapture(1)
vide_capture.set(cv2.CAP_PROP_FRAME_WIDTH, HEIGHT)
vide_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, WEIGHT)

向右滑動查看完整代碼

04簡單的 DataLoader

由于每個樣本圖片的大小只有 32 x 128, 相對來說比較小,因此就干脆直接全部加載到內存中:

def EpochDataLoader(path, batch_size=64):
  """
  :param path: 數據集的根路徑
  :param batch_size: batch_size
  :return: epoch_img, epoch_annots, epoch_coords:
[M, batch_size, C, H, W], [M, batch_size, 7], [M, batch_size, 2]
  """
  epoch_img, epoch_annots, epoch_coords = [], [], []
  all_file_name = os.listdir(path + "img/") # get all file name -> list
  file_num = len(all_file_name)
  batch_num = file_num // batch_size


  for i in range(batch_num): # how many batch
    curr_batch = all_file_name[batch_size * i:batch_size * (i + 1)]
    batch_img, batch_annots, batch_coords = [], [], []
    for file_name in curr_batch:


      img = cv2.imread(str(path) + "img/" + str(file_name)) # [H, W, C] format
      img = img.transpose((2, 0, 1))
      img = img / 255 # [C, H, W] format
      data = np.loadtxt(str(path) + "annot/" + str(file_name).split(".")[0] + ".txt")
      annot_mora, coord_mora = np.array([1920, 1080, 1920, 1080, 1, 1, 1.4]), np.array([1920, 1080])
      annot, coord = data[2:]/annot_mora, data[:2]/coord_mora


      batch_img.append(img)
      batch_annots.append(annot)
      batch_coords.append(coord)


    epoch_img.append(batch_img)
    epoch_annots.append(batch_annots)
    epoch_coords.append(batch_coords)


  epoch_img = torch.from_numpy(np.array(epoch_img)).float()
  epoch_annots = torch.from_numpy(np.array(epoch_annots)).float()
  epoch_coords = torch.from_numpy(np.array(epoch_coords)).float()
  return epoch_img, epoch_annots, epoch_coords

向右滑動查看完整代碼

這個函數可以一次性返回所有的樣本。

05定義損失函數并訓練

由于網絡輸出的結果是 N 個二維坐標,因此直接使用 torch.nn.MSELoss() 作為損失函數。

def eye_track_train():
  img, annot, coord = EpochDataLoader(TRAIN_DATASET_PATH, batch_size=TRAIN_BATCH_SIZE)
  batch_num = img.size()[0]
  model = EyeTrackModel().to(device).train()
  loss = torch.nn.MSELoss()
  optim = torch.optim.SGD(model.parameters(), lr=LEARN_STEP)
  writer = SummaryWriter(LOG_SAVE_PATH)


  trained_batch_num = 0
  for epoch in range(TRAIN_EPOCH):
    for batch in range(batch_num):
      batch_img = img[batch].to(device)
      batch_annot = annot[batch].to(device)
      batch_coords = coord[batch].to(device)
      # infer and calculate loss
      outputs = model((batch_img, batch_annot))
      result_loss = loss(outputs, batch_coords)
      # reset grad and calculate grad then optim model
      optim.zero_grad()
      result_loss.backward()
      optim.step()
      # save loss and print info
      trained_batch_num += 1
      writer.add_scalar("loss", result_loss.item(), trained_batch_num)
      print("[INFO]: trained epoch num | trained batch num | loss "
         , epoch + 1, trained_batch_num, result_loss.item())
    if epoch % 100 == 0:
      torch.save(model, "../model/ET-" + str(epoch) + ".pt")
  # save model
  torch.save(model, "../model/ET-last.pt")
  writer.close()
  print("[SUCCEED!] model saved!")

向右滑動查看完整代碼

訓練過程中每 100 輪都會保存一次模型,訓練結束后也會進行保存。

06通過導出為 ONNX 模型

通過 torch.onnx.export() 我們便可以很方便導出 onnx 模型。

def export_onnx(model_path, if_fp16=False):
  """
  :param model_path: 模型的路徑
:param if_fp16: 是否要將模型壓縮為 FP16 格式
:return: 模型輸出路徑
  """
  model = torch.load(model_path, map_location=torch.device('cpu')).eval()
  print(model)
  model_path = model_path.split(".")[0]
  dummy_input_img = torch.randn(1, 3, 32, 128, device='cpu')
  dummy_input_position = torch.randn(1, 7, device='cpu')
  torch.onnx.export(model, [dummy_input_img, dummy_input_position], model_path + ".onnx", export_params=True)
  model = mo.convert_model(model_path + ".onnx", compress_to_fp16=if_fp16) # if_fp16=False, output = FP32
  serialize(model, model_path + ".xml")
  print(EyeTrackModel(), "
[FINISHED] CONVERT DONE!")
  return model_path + ".xml"

向右滑動查看完整代碼

07使用 OpenVINO 的 NNCF 工具進行 int8 量化

Neural Network Compression Framework (NNCF) provides a new post-training quantization API available in Python that is aimed at reusing the code for model training or validation that is usually available with the model in the source framework, for example, PyTorch* or TensroFlow*. The API is cross-framework and currently supports models representing in the following frameworks: PyTorch, TensorFlow 2.x, ONNX, and OpenVINO.

Post-training Quantization with NNCF (new) — OpenVINO documentation[1]

通過 OpenVINO 的官方文檔我們可以知道:Post-training Quantization with NNCF分為兩個子模塊:

Basic quantization

Quantization with accuracy control

def basic_quantization(input_model_path):
  # prepare required data
  data = data_source(path=DATASET_ROOT_PATH)
  nncf_calibration_dataset = nncf.Dataset(data, transform_fn)
  # set the parameter of how to quantize
  subset_size = 1000
  preset = nncf.QuantizationPreset.MIXED
  # load model
  ov_model = Core().read_model(input_model_path)
  # perform quantize
  quantized_model = nncf.quantize(ov_model, nncf_calibration_dataset, preset=preset, subset_size=subset_size)
  # save model
  output_model_path = input_model_path.split(".")[0] + "_BASIC_INT8.xml"
  serialize(quantized_model, output_model_path)




def accuracy_quantization(input_model_path, max_drop):
  # prepare required data
  calibration_source = data_source(path=DATASET_ROOT_PATH, with_annot=False)
  validation_source = data_source(path=DATASET_ROOT_PATH, with_annot=True)
  calibration_dataset = nncf.Dataset(calibration_source, transform_fn)
  validation_dataset = nncf.Dataset(validation_source, transform_fn_with_annot)
  # load model
  xml_model = Core().read_model(input_model_path)
  # perform quantize
  quantized_model = nncf.quantize_with_accuracy_control(xml_model,
                             calibration_dataset=calibration_dataset,
                             validation_dataset=validation_dataset,
                             validation_fn=validate,
                             max_drop=max_drop)
  # save model
  output_model_path = xml_model_path.split(".")[0] + "_ACC_INT8.xml"
  serialize(quantized_model, output_model_path)




def export_onnx(model_path, if_fp16=False):
  """
  :param model_path: the path that will be converted
  :param if_fp16: if the output onnx model compressed to fp16
  :return: output xml model path
  """
  model = torch.load(model_path, map_location=torch.device('cpu')).eval()
  print(model)
  model_path = model_path.split(".")[0]
  dummy_input_img = torch.randn(1, 3, 32, 128, device='cpu')
  dummy_input_position = torch.randn(1, 7, device='cpu')
  torch.onnx.export(model, [dummy_input_img, dummy_input_position], model_path + ".onnx", export_params=True)
  model = mo.convert_model(model_path + ".onnx", compress_to_fp16=if_fp16) # if_fp16=False, output = FP32
  serialize(model, model_path + ".xml")
  print(EyeTrackModel(), "
[FINISHED] CONVERT DONE!")
  return model_path + ".xml"

向右滑動查看完整代碼

這里需要注意的是 nncf.Dataset (calibration_source, transform_fn) 這一部分,calibration_source 所返回的必須是一個可迭代對象,每次迭代返回的是一個訓練樣本 [1, C, H, W],transform_fn 則是對這個訓練樣本作轉換(比如改變通道數,交換 H, W)這里的操作是進行歸一化,并轉換為 numpy。

08量化后的性能提升

測試的硬件平臺 12700H。

這種小模型通過 OpenVINO NNCF 方法量化后可以獲得很明顯的性能提升:

benchmark_app -m ET-last_ACC_INT8.xml -d CPU -api async
[ INFO ] Execution Devices:['CPU'] [ INFO ] Count: 226480 iterations [ INFO ] Duration: 60006.66 ms [ INFO ] Latency: [ INFO ] Median: 3.98 ms [ INFO ] Average: 4.18 ms [ INFO ] Min: 2.74 ms [ INFO ] Max: 38.98 ms [ INFO ] Throughput: 3774.25 FPS benchmark_app -m ET-last_INT8.xml -d CPU -api async
[ INFO ] Execution Devices:['CPU'] [ INFO ] Count: 513088 iterations [ INFO ] Duration: 60002.85 ms [ INFO ] Latency: [ INFO ] Median: 1.46 ms [ INFO ] Average: 1.76 ms [ INFO ] Min: 0.82 ms [ INFO ] Max: 61.07 ms [ INFO ] Throughput: 8551.06 FPS

向右滑動查看

09在 AIxBoard愛克斯板開發者套件上進行部署

由于 AlxBoard 上已經安裝好了 Python,因此只需要再安裝 OpenVINO 即可。

下載英特爾發行版 OpenVINO 工具套件 (intel.cn)[2]

然后在項目的根目錄執行 python eye_track.py 即可查看到網絡的推理結果,如下圖所示。

b26aed88-53ab-11ee-a25d-92fbcf53809c.png

性能概覽:

b2ae24ea-53ab-11ee-a25d-92fbcf53809c.png

在iGPU上的運行性能

b2def318-53ab-11ee-a25d-92fbcf53809c.png

在CPU上運行的性能

總結

OpenVINO 提供了一個方便快捷的開發方式,通過幾個核心的API便可實現模型轉換和模型量化。

AIxBoard 基于 x86 架構提供了一個高通用、高性能的部署平臺,體積小巧,非常適合項目的最終部署。

自訓練 Pytorch 模型在通過 OpenVINO 的模型優化工具優化后,使用 OpenVINO Runtime 進行推理,對于如上文所示的小模型可以獲得巨大的性能提升,并且推理過程簡單清晰。在開發板上推理僅需幾個核心函數便可實現基于自訓練 Pytorch 模型的推理。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    18432

    瀏覽量

    222894
  • 英特爾
    +關注

    關注

    60

    文章

    9495

    瀏覽量

    169169
  • 開發板
    +關注

    關注

    25

    文章

    4511

    瀏覽量

    94500
  • 開發套件
    +關注

    關注

    2

    文章

    126

    瀏覽量

    24168
  • OpenVINO
    +關注

    關注

    0

    文章

    61

    瀏覽量

    95

原文標題:基于 OpenVINO? 在英特爾開發套件上實現眼部追蹤 | 開發者實戰

文章出處:【微信號:英特爾物聯網,微信公眾號:英特爾物聯網】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    【Intel Edison試用體驗】+Intel Edison開發套件資料?

    本帖最后由 anger0925 于 2016-7-1 08:17 編輯 Intel Edison Arduino開發套件資料: 1,英特爾? Edison開發套件中文官網,http
    發表于 07-01 08:16

    英特爾物聯網創客競賽專貼】有任何問題都可以在這里提

    鼓勵業余愛好者、企業開發人員和高校師生了解英特爾? 物聯網開發套件并基于套件開發物聯網解決方案。發燒友此次承辦深圳的IoT Roadshow
    發表于 09-09 10:01

    蘋果放棄未來iPhone使用英特爾5G基帶芯片 精選資料推薦

    騰訊科技訊,7 月 5 日據國外媒體報道,英特爾未來不會再向蘋果的 iPhone 智能手機提供基帶芯片了。英特爾剛剛確認,公司已經停止開發部分原本計劃使用在蘋果 iPhone 的 5
    發表于 07-23 06:20

    介紹英特爾?分布式OpenVINO?工具包

    性能。 英特爾?OpenlandOpen?管理軟件包包括英特爾?深度學習部署工具包(英特爾?DLDT)。適用于Linux *的OpenVINO?工具包的
    發表于 07-26 06:45

    怎么安裝適用于Linux *的OpenVINO?工具包的英特爾?發布版?

    怎么安裝適用于Linux *的OpenVINO?工具包的英特爾?發布版?
    發表于 09-23 08:33

    OpenVINO工具套件是否可以商業化使用?

    參閱 英特爾? OpenVINO?分銷許可第 2.1 節(2021 年 5 月版本)。 無法了解英特爾? 發行版 OpenVINO? 工具套件
    發表于 08-15 08:19

    如何使用交叉編譯方法為Raspbian 32位操作系統構建OpenVINO工具套件的開源分發

    _dist/setupvars.sh 編譯示例代碼 cd ~/openvino_dist/samples/cpp ./build_samples.sh 要驗證該工具套件英特爾? 神經電腦棒 2和 ARM* 插件
    發表于 08-15 06:28

    從Docker映像為Raspbian OpenVINO工具套件的安裝過程

    英特爾? Distribution工具OpenVINO?可快速部署模擬人類視覺的應用和解決方案。該工具包在基于卷積神經網絡 (CNN) 的英特爾?硬件擴展了計算機視覺 (CV) 工
    發表于 08-15 06:59

    安裝OpenVINO工具套件英特爾Distribution時出現錯誤的原因?

    安裝OpenVINO?工具套件英特爾 Distribution時,出現錯誤: Python 3.10.0.ECHO is off. Unsupported Python version.
    發表于 08-15 08:14

    英特爾酷睿2雙核處理器SL9380和英特爾3100芯片組開發套件

    英特爾 酷睿2 雙核處理器 SL9380 和英特爾 3100 芯片組開發套件為各種嵌入式和通信基礎設施應用提供優越的平臺,特別是要求高性能、高可靠性和低功耗的小型嵌入式平臺應用,例如:
    發表于 12-07 14:07 ?23次下載
    <b class='flag-5'>英特爾</b>酷睿2雙核處理器SL9380和<b class='flag-5'>英特爾</b>3100芯片組<b class='flag-5'>開發套件</b>

    英特爾BOOT Loader開發套件-高級嵌入式開發基礎

    從技術角度概括介紹用于快速開發和部署啟動加載器的英特爾 Boot Loader 開發套件(英特爾 BLDK),該套件基于
    發表于 12-07 14:57 ?59次下載
    <b class='flag-5'>英特爾</b>BOOT Loader<b class='flag-5'>開發套件</b>-高級嵌入式<b class='flag-5'>開發</b>基礎

    英特爾的945GME高速芯片組開發套件

    英特爾的945GME高速芯片組開發套件
    發表于 10-30 11:57 ?3次下載

    使用英特爾物聯網商業開發套件改變世界

    使用英特爾?物聯網商業開發套件改變世界。
    的頭像 發表于 05-31 10:06 ?1625次閱讀

    基于英特爾開發套件的AI字幕生成器設計

    市面上有很多自然語言處理模型,本文旨在幫助開發者快速將 OpenAI* 的熱門 NLP 模型 Whisper 部署至英特爾 開發套件愛克斯開發板上,由于
    的頭像 發表于 09-27 16:59 ?545次閱讀
    基于<b class='flag-5'>英特爾</b><b class='flag-5'>開發套件</b>的AI字幕生成器設計

    基于英特爾哪吒開發套件平臺來快速部署OpenVINO Java實戰

    OpenVINO 工具套件基于OneAPI開發,可以加快高性能計算機視覺和深度學習應用開發速度的工具套件,適用于從邊緣到云的各種
    的頭像 發表于 03-21 18:24 ?878次閱讀
    基于<b class='flag-5'>英特爾</b>哪吒<b class='flag-5'>開發</b>者<b class='flag-5'>套件</b>平臺來快速部署<b class='flag-5'>OpenVINO</b> Java實戰
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>