blazeface学习笔记
完整的應該是一個人臉識別項目,人臉識別,大言不慚的說,我之前其實也做過,比如用dlib來做人臉識別,就是用opencv那一套來實現,說句實在話,速度非常慢,即便是在intel CPU上,一秒也就兩三幀,確實是太慢了
我其實也用過其他方案,比如前幾年,下載虹軟的免費的庫,進行試用,效果確實驚人,給我印象最深刻的,倒不是識別準確度有多高,而是速度真的飛快,
我也試過MTCNN,這個只要網上搜索人臉檢測,基本都是搜到這個結果,我也嘗試過,我不知道別人是如何夸獎這個庫的,我試用的體會就是,經常誤識別,就是本來就不是個人臉,卻非要識別成一個人臉,通常認為,可以提高閾值,進行過濾,可是我的體會是,有些明明不是人臉的地方,其confidence卻非常高,而有些明明是人臉的地方,卻又漏減,我不知道為啥別人還到處推薦.
人臉檢測,用我這外行的話,應該是分為四個步驟
1.人臉檢測,不僅要檢測出人臉,而且要檢測出關鍵點,
?2.根據檢測到的關鍵點進行人臉對齊,也就是alignment,也就是仿射變換,那是不是可以不對齊呢?按說也可以,但研究發現,人臉對齊后,人臉識別的難度就大大降低了
3.把對齊后的人臉送到神經網絡中去計算,得到一個128維的向量
4.把這個向量,跟其他人臉的向量進行對比,如果比較接近,那就認為是同一個人
除了上面提到的幾個庫,我還用過商湯的人臉識別庫,在imx6(Cortex-A9)的芯片上,其檢測速度可以達到12FPS,還是相當出色的,不過我記得其加載速度比較慢,加載可能要半分鐘,不過好在只需啟動的時候加載一次。
當然,無論是商湯的庫,還是虹軟的庫,都是閉源的,而且還需要Licence,如果Licence過期就無法使用了;
目前開源的人臉識別庫,比較優秀的,有arcface,跟虹軟重名,比較可靠的實現,可以參考
https://github.com/deepinsight/insightface/tree/master/recognition/arcface_paddle
或者
https://github.com/onnx/models/tree/main/vision/body_analysis/arcface
當然我也寫了一點點筆記,
基于onnx的人臉識別_zhqh100的博客-CSDN博客
下面說回人臉檢測,之前在YouTube上看到過Google宣傳的FaceMesh的功能,印象深刻
不僅速度很快,而且結果穩定,只不過其沒有開放訓練的源碼,我在網上搜到了一個Pytorch版本的實現,
https://github.com/zmurez/MediaPipePyTorch.git
這個是一個演示,復現了上面的功能,以及速度,我看單幀平均速度為22ms,在Intel I7上。
不過可惜該項目中沒有訓練代碼,只有推理demo代碼。
然后我又找到了一個項目,是
https://github.com/zineos/blazeface.git
其中包含推理代碼和訓練代碼,
該工程是從另一個工程改過來的,拿到手有點迷茫,就是直接運行會報錯,我fork之后稍微改了一下,我的工程是
https://github.com/moneypi/blazeface
還有一點是這個訓練數據,在百度網盤上的鏈接失效了,我就重新從Google上下載下來,重新傳了一份,
鏈接:https://pan.baidu.com/s/1ao-XwW6i8VXsSvh_fSelgQ?pwd=u7ii
提取碼:u7ii
--來自百度網盤超級會員V1的分享
打印出的網絡結構如下:
Blaze((conv1): Sequential((0): Conv2d(3, 24, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True))(conv2): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=24, bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))))(conv3): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=24, bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))))(conv4): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(2, 2), padding=(2, 2), groups=24, bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 48, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(shortcut): Sequential((0): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(1): Conv2d(24, 48, kernel_size=(1, 1), stride=(1, 1))(2): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(3): ReLU(inplace=True)))(conv5): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(48, 48, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=48, bias=False)(1): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(48, 48, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))))(conv6): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(48, 48, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=48, bias=False)(1): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(48, 48, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))))(conv7): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(48, 48, kernel_size=(5, 5), stride=(2, 2), padding=(2, 2), groups=48, bias=False)(1): BatchNorm2d(48, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(48, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(1): ReLU(inplace=True)(2): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): ReLU(inplace=True))(shortcut): Sequential((0): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(1): Conv2d(48, 96, kernel_size=(1, 1), stride=(1, 1))(2): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(3): ReLU(inplace=True)))(conv8): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(96, 96, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=96, bias=False)(1): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(1): ReLU(inplace=True)(2): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): ReLU(inplace=True)))(conv9): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(96, 96, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=96, bias=False)(1): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(1): ReLU(inplace=True)(2): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): ReLU(inplace=True)))(conv10): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(96, 96, kernel_size=(5, 5), stride=(2, 2), padding=(2, 2), groups=96, bias=False)(1): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(1): ReLU(inplace=True)(2): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): ReLU(inplace=True))(shortcut): Sequential((0): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(1): Conv2d(96, 96, kernel_size=(1, 1), stride=(1, 1))(2): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(3): ReLU(inplace=True)))(conv11): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(96, 96, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=96, bias=False)(1): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(1): ReLU(inplace=True)(2): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): ReLU(inplace=True)))(conv12): BlazeBlock((actvation): ReLU(inplace=True)(conv): Sequential((0): Sequential((0): Conv2d(96, 96, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), groups=96, bias=False)(1): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(1): ReLU(inplace=True)(2): Sequential((0): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2), bias=False)(1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU(inplace=True)(3): Conv2d(24, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): ReLU(inplace=True)))(loc): Sequential((0): Sequential((0): Conv2d(96, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=96)(1): ReLU(inplace=True)(2): Conv2d(96, 8, kernel_size=(1, 1), stride=(1, 1)))(1): Sequential((0): Conv2d(96, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=96)(1): ReLU(inplace=True)(2): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1))))(conf): Sequential((0): Sequential((0): Conv2d(96, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=96)(1): ReLU(inplace=True)(2): Conv2d(96, 4, kernel_size=(1, 1), stride=(1, 1)))(1): Sequential((0): Conv2d(96, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=96)(1): ReLU(inplace=True)(2): Conv2d(96, 12, kernel_size=(1, 1), stride=(1, 1))))(landm): Sequential((0): Sequential((0): Conv2d(96, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=96)(1): ReLU(inplace=True)(2): Conv2d(96, 20, kernel_size=(1, 1), stride=(1, 1)))(1): Sequential((0): Conv2d(96, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), groups=96)(1): ReLU(inplace=True)(2): Conv2d(96, 60, kernel_size=(1, 1), stride=(1, 1))))
)
inputs的shape為[1, 3, 320, 320],其中backbone有四次下采樣,會把第四次下采樣前和網絡的最后結果保存到detections中,分別為[1, 96, 40, 40]和[1, 96, 20, 20]
這兩個結果會分別送到loc_layers、conf_layers和landm_layers中去計算,得出的尺寸為
loc[0]的shape是[1, 40, 40, 8],loc[1] 的shape是?[1, 20, 20, 24],加一塊,再分成四個坐標,就是bbox_regressions.shape=[1, 5600, 4]
conf[0].shape=[1, 40, 40, 4]
conf[1].shape=[1, 20, 20, 12]
加一塊得到classifications.shape=[1, 5600, 2]
landm[0].shape=torch.Size([1, 40, 40, 20])
landm[1].shape=torch.Size([1, 20, 20, 60])
加一塊得到?ldm_regressions.shape=torch.Size([1, 5600, 10])
回過頭來看anchors,配置文件中'steps': [8, 16],而圖像尺寸為320*320,那么就得出小框為320/8,即40*40個,大框為320/16,即20*20個,
然后'min_sizes': [[8, 11], [14, 19, 26, 38, 64, 149]],,即40*40的框,分別會生成尺寸為8和11的anchor,而20*20的框,就遍歷[14, 19, 26, 38, 64, 149],也就是總共會生成40 * 40 * 2 + 20 * 20 *6=3200+2400=5600個框
所以,綜上,基本證實了,blazeface,就是一個小號的ssd,其沒有FPN的融合,然后,也是基于anchor的實現,所以,如果用anchor-free的方法,網絡還有進一步減小的空間?
損失函數,landmark 和 location 都是使用了?smooth_l1_loss,
loss_c,分類的損失函數為focalloss
按說給各個損失都添加了權重的比重系數,不過我看其代碼中只用到了分類的系數,也就是 loss_c會再乘以6,然后各個損失相加,就是總損失
計算各損失的時候,都是采樣一部分進行計算
我基本沒有做修改(其實修改了batchsize,原工程默認值為256, 我修改為了64,顯卡為GeForce RTX 2060, 6G,沒那么闊),評估精度為:
==================== Results ====================
Easy Val AP: 0.8039773948120692
Medium Val AP: 0.7454040908046184
Hard Val AP: 0.4292227434416538
=================================================
用工程中自帶的模型參數測試,
==================== Results ====================
Easy Val AP: 0.7667513659507036
Medium Val AP: 0.6894514595432863
Hard Val AP: 0.34819400614673535
=================================================
我靠,我沒優化,我訓練的結果居然比他自帶的精度還高一些,Surprise
訓練時間是從2022-03-23 22:43到2022-03-24 04:55,大概6個小時
因為看到訓練的loss曲線波動很大,所以嘗試降低lr,降了一半,看起來loss曲線確實好了一點,但精度卻降低了?
==================== Results ====================
Easy Val AP: 0.7789928144856131
Medium Val AP: 0.7163551912058919
Hard Val AP: 0.3995628884327997
=================================================
所以,暫時還是用原來的學習率,做其他嘗試
我嘗試替換激活函數,看是否能提高準確率,我用nn.Softplus()來替換了原來所有的?nn.ReLU(inplace=True),意識到了一個問題,Softplus這個激活函數沒有inplace這個參數,那么需要的顯存空間會更大,我原本6G的顯存,在Relu的時候,'batch_size': 64,基本跑滿,而替換為Softplus之后,我只好設置為'batch_size': 40,不過好消息是,精度確實提高了,這是目前為止,最高的一個點
==================== Results ====================
Easy Val AP: 0.8155068518500983
Medium Val AP: 0.7586505701251691
Hard Val AP: 0.4390300734203851
=================================================
執行測試,運行的是
python test_widerface.py
獲取上面結果,運行的是
cd widerface_evaluate/
python evaluation.py
下面學習權重量化,先嘗試了一下?quantize_dynamic,發現精度和量化前完全一致,所以查一下到底是哪里的問題,從網上別人的教程,順便跳轉到?quantize_dynamic?的源碼看了一下,其默認只會對如下模塊進行量化:
nn.Linear, nn.LSTM, nn.GRU, nn.LSTMCell, nn.RNNCell, nn.GRUCell
那我們這里基本沒有用到上面的模塊,所以也基本沒啥變化.
然后,我嘗試做了一下模型量化,但水平不行,沒有實現,參考?
一次失敗的Pytorch模型量化嘗試_zhqh100的博客-CSDN博客我的原工程模型是blazeface學習筆記_zhqh100的博客-CSDN博客完整的應該是一個人臉識別項目,人臉識別,大言不慚的說,我之前其實也做過,比如用dlib來做人臉識別,就是用opencv那一套來實現,說句實在話,速度非常慢,即便是在intel CPU上,一秒也就兩三幀,確實是太慢了我其實也用過其他方案,比如前幾年,下載虹軟的免費的庫,進行試用,效果確實驚人,給我印象最深刻的,倒不是識別準確度有多高,而是速度真的飛快,我也試過MTCNN,這個只要網上搜索人臉檢測,基本都是搜到這個結果,我也嘗試過,我https://blog.csdn.net/zhqh100/article/details/123742045
昨天試了一下加FPN,當然這里就是修改模型了,而不是復現論文,我在模型里加了如下幾行
fpn_bak = F.interpolate(detections[1], size=(detections[0].size(2), detections[0].size(3)))
# detections[0] = torch.cat((detections[0], fpn_bak), dim=1)
detections[0] = torch.add(detections[0], fpn_bak)
當然用cat可能也行,但是用cat的花,就需要增加參數量,我盡量還是不增加參數量,訓練完成的精度為:
==================== Results ====================
Easy Val AP: 0.8127231180335884
Medium Val AP: 0.7547545989153277
Hard Val AP: 0.43340084728149164
=================================================
說一下我這里的配置,我目前的batchsize是40,初始學習率是1e-3,激活函數在試量化的時候改回了ReLU,
因為之前使用Softplus的時候,精度提高了很多,所以我再次替換類ReLU激活函數,看是否能提高精度,我在網上看到一篇文章,
激活函數 | Squareplus性能比肩Softplus激活函數速度快6倍(附Pytorch實現)-技術圈本文提出了Squareplus激活函數,這是一個類似softplus的激活函數,但只需要通過簡單的代數運算來實現:加法、乘法和平方根。由于Squarhttps://jishuin.proginn.com/p/763bfbd704d4當然我也不知道他是不是原創,他里面貼了一個pytorch實現的squareplus,我用了之后發現他是一個坑,他代碼寫錯了,少寫一個平方,所以我這里貼一下我改之后的實現
class Squareplus(nn.Module):def __init__(self, b=0.2):super(Squareplus, self).__init__()self.b = bdef forward(self, x):x = 0.5 * (x + torch.sqrt(torch.square(x)+self.b))return x
然后精度還是有提高的
==================== Results ====================
Easy Val AP: 0.8200590574413846
Medium Val AP: 0.7649220162383361
Hard Val AP: 0.4490872484483122
=================================================
這個精度已經超過了上面的最高精度
稍微說一下,就是我這里用自己實現的Squareplus函數,訓練顯存又大了一點,所以batchsize又從40改為了30,然后推理速度的話,用ReLU的時候,推理速度大概是不到4ms,當然這里不說后處理,后處理也要2.4ms左右,然后用Squareplus的時候,推理速度大概算6ms了,所以慢很多
我總是感覺ReLU的激活函數太過粗暴,我希望能找到一個平滑的,能參數自適應的激活函數,看是否能得出更好的效果,而squareplus就是一個單調遞增的,平滑的函數,我修改為了自適應版本,如下:
class Squareplus(nn.Module):def __init__(self):super(Squareplus, self).__init__()self.b = torch.nn.Parameter(torch.tensor([1., 1., 1e-8]))def forward(self, x):x = 0.5 * (self.b[0] * x + self.b[1] * torch.sqrt(torch.square(x)+torch.square(self.b[2])))return x
因為squareplus的公式為
那如果b=0的時候,其實SquarePlus就跟ReLU完全相等,我最開始的時候,是想上面代碼中直接用self.b[2] = 0.應該也能訓練,但實際情況是如果self.b[2]=0.的時候,loss直接就NaN,inf了,所以我給了一個接近0的值,那實際效果來看,精度確實提升了一點點:
==================== Results ====================
Easy Val AP: 0.8227621694850481
Medium Val AP: 0.7662798102976387
Hard Val AP: 0.4513160808024386
=================================================
這個比上面所有的精度都高,但也不算驚人吧,但比較顯著的是,推理速度慢了很多,升到了差不多8ms,
我預測時候,把所有的self.b打印出來了,如下:
[0.8454, 0.3644, 0.1367]
[ 0.8873, 0.7530, -0.1533]
[0.7036, 0.6800, 0.2724]
[ 0.4455, 1.2127, -0.0125]
[0.9210, 0.5843, 0.1486]
[0.9819, 0.7223, 0.4142]
[ 1.0522, 0.6184, -0.2266]
[ 0.8519, 0.4931, -0.3491]
[0.8119, 0.8772, 0.6076]
[ 0.8358, 0.4341, -0.3027]
[ 0.7915, 0.9259, -0.6816]
[ 0.6944, 0.8840, -0.6110]
[0.9455, 0.5593, 0.4089]
[0.8080, 0.8872, 0.4731]
[0.7749, 0.7353, 0.7412]
[ 1.0064, 0.6360, -0.3702]
[1.3030, 0.3886, 0.2978]
[1.2454, 0.5487, 0.1881]
[0.6192, 1.0405, 0.6971]
[0.7321, 0.9983, 0.5140]
[0.6235, 1.0673, 0.8745]
[1.1215, 0.7250, 0.2422]
[ 1.2247, 0.7770, -0.0237]
[0.5734, 1.0426, 0.8500]
[0.8035, 1.0243, 0.4659]
[ 0.5823, 1.1394, -1.0904]
[ 1.8497, 0.8324, -0.1130]
[ 1.9515, 1.0291, -0.0616]
[ 0.5608, 1.0035, -0.5520]
[ 0.7945, 0.8310, -0.3079]
[0.7418, 0.9905, 0.5818]
[ 0.9830, 0.4994, -0.2175]
[1.0192, 0.6735, 0.4724]
[ 0.8990, 0.6039, -0.0406]
[ 0.5347, 1.1900, -0.3618]
[0.8685, 0.9823, 0.1829]
[0.7512, 0.9619, 0.5523]
[ 1.1577, 0.7502, -0.2851]
[0.9508, 0.7332, 0.0213]
[0.6115, 1.0775, 0.5334]
[0.8370, 1.0327, 0.4429]
[0.8130, 1.0963, 0.8485]
[ 1.8354, 0.8548, -0.1749]
[ 1.4897, 0.7104, -0.0795]
[1.1626, 1.1678, 0.0058]
[ 0.9293, 0.8205, -0.1558]
[1.2170, 1.4804, 0.0718]
[ 1.7995, 0.9660, -0.0163]
[ 1.3056, 1.1443, -0.0841]
[1.6489, 1.1632, 0.1204])
感覺還蠻有意思的
總結
以上是生活随笔為你收集整理的blazeface学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LaneATT调试笔记
- 下一篇: 一次失败的Pytorch模型量化尝试