作者|李秋鍵
責編
| 寇雪芹
頭圖
| 下載於
視覺中國
引言
近幾年來深度學習的發展越來越火熱,其中最為典型的就是半監督學習的新研究進展GCN。由Kipf和Welling提出的GCN被證明是一種有效的圖半監督學習框架應用,如社會、醫療、商業和交通網路分析,其中典型的物件是在少數有標記資料的幫助下對無標記資料進行分類圖中的樣本。
圖卷積網路(GCN)已被證明是一種有效的基於圖的半卷積網路框架監督學習應用。GCN的核心操作塊是卷積層透過融合節點屬性和關係,使網路能夠構造節點嵌入節點之間。不同的特性或特性的相互作用本身就具有不同的影響卷積的層。
然而,關於特徵重要性影響的研究非常有限在GCN-related社群。在這項工作中,我們試圖增加捲積層的GCNS透過建模特徵的潛在互動作用,統計注意特徵的重要性,即補充標準GCNS和只需要簡單的計算與統計而不是沉重的培訓。
為此,我們將每個卷積層的特徵輸入作為一個單獨的multi-分層異構圖,並提出了圖統計自注意(GSSA)方法學習特徵重要性的層次結構。更具體地說,我們建議在通道自注意(CSA),以捕獲特徵通道之間的依賴關係,和基於均值的自我注意(MSA)來重新加權特徵之間的相似性。瞄準每個圖形卷積層,GSSA可以以“即插即用”的方式應用於廣泛的GCN變體。
據我們所知,這是最佳化GCNs特性的第一個實現重要的視角。大量的實驗表明,GSSA可以促進現有的流行在半監督節點分類任務中,基線是非常重要的。
系統概述
本系統主要使用的是openpose提取特徵,然後對特徵使用GCN演算法進行分類,以檢驗GCN的模型效果。
1。執行環境
由於需要使用到openpose工具,故需要配置以下環境。分別是:
python環境及相關庫(opencv、numpy、pytorch等)環境、CUDA搭建GPU環境、C++環境、swig編譯環境、以及ffmpeg環境和openpose環境;
2。openpose概述:
openpose是依賴於卷積神經網路和監督學習實現人體姿態評估演算法,其主要的優點在於適用於多人二維且較為精準和迅速的識別開源。
整個系統的搭建主要是依賴於openpose的姿態識別環境。Openpose的呼叫在這裡透過呼叫其中設定好的主函式即可,其中包括模型載入程式、呼叫程式以及Estimator評估等等。
3。GCN簡述:
圖卷積方法主要有兩大流派:基於頻譜的方法和基於空間的方法。
基於頻譜的方法主要有Spectral CNN (第一代 GCN)、第二代GCN、ChebyNet、 CayleyNet、一階 ChebyNet等。在行為識別領域,ChebyNet 及一階近似被廣泛應用。基於空間的方法主要有訊息傳遞與聚合、圖取樣與聚合、圖結構序列化、關注卷積方式、基於注意力機制、關注感知域的方法。
隨著GCN方法的發展,其方法主要分為兩大類:基於頻譜的方法 (spectral-based)和基於空間的方法 (spatial-based)。基於頻譜的圖卷積網路是將圖訊號與頻譜訊號進行轉換和分析,然後再恢復圖訊號所在的空域,從而完成圖訊號的降噪與特徵提取。以“降低複雜度”為主線,將常用於影象的卷積神經網路應用到圖資料上。
基於頻譜的圖卷積透過新增自我連線單位矩陣、歸一化鄰接矩陣 A 的方式解決了基於空間的圖卷積忽略節點自身特徵、鄰接矩陣過於龐大的兩個問題。但由於基於頻譜的圖卷積方法存在靈活性不高、普適性不強、執行效率較低等問題,基於空間的圖卷積方法利用鄰域聚合的思想降低了複雜度,增強了泛化能力,提高了執行效率,是行為識別領域在圖結構資料上進行分析的基本思想。
資料預處理
1。openpose影象資料生成
在配置好openpose環境以後,使用cut。py中的程式碼可以讀取fall。mp4的影片,並生成資料集儲存在datasets資料夾下,然後我們再手動分好類,分別為shuaidao和common這兩個動作。其中資料夾資料如下:
圖1 common資料夾資料圖片
圖2 shuaidao資料夾資料圖片
分割的步驟就是讀取mp4影片檔案,利用迴圈分影片幀,然後手動分好資料集。其中分割部分的程式碼為cut。py,程式碼如下:
1
e = TfPoseEstimator(get_graph_path(‘mobilenet_thin’), target_size=(432, 368))
2
cap=cv2。VideoCapture(
“fall。mp4”
)
3
num=0
4
while True:
5
num+=1
6
ret,frame = cap。read()
7
image = frame
8
cv2。imwrite(
“datasets/”
+str(num)+
“。jpg”
,image)
9
cv2。imshow(
“1”
, image)
10
cv2。waitKey(1)
2。2 特徵提取
在分割好資料集後分別對各自的類別圖片提取特徵,將特徵分別儲存在shuaidao。txt和common。txt檔案中。但是考慮到有的時候並不是可以完整地提取到特徵,對特徵缺少的部分,使用均值替換。其中特徵提取的程式碼為feature。py檔案,得到的txt資料如下可見:
圖3 特徵提取結果顯示
關鍵程式碼如下:
1
e = TfPoseEstimator(get_graph_path(
‘mobilenet_thin’), target_size=(432, 368))
2
f0=open(
“shuaidao。txt”
,
“w”
)
3
f1=open(
“common。txt”
,
“w”
)
4
for
file
in
os。listdir(
“datasets/shuaidao”
):
5
print(file)
6
image = cv2。imread(
“datasets/shuaidao/”
+file)
7
cv2。imshow(
“test”
,image)
8
cv2。waitKey(
1
)
9
humans = e。inference(image, upsample_size=
4。0
)
10
try:
11
a = str(humans[])。
split
(
“BodyPart:”
)
12
b = []
13
id = []
14
position = []
15
features=[,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]
16
for
i
in
a:
17
try:
18
position。append(
19
float(str(i。
split
(
“ score”
)[])。
split
(
“-”
)[
1
]。
replace
(
“(”
,
“”
)。
replace
(
“)”
,
“”
)。
split
(
“, ”
)[])
20
)
21
position。append(
22
float(str(i。
split
(
“ score”
)[])。
split
(
“-”
)[
1
]。
replace
(
“(”
,
“”
)。
replace
(
“)”
,
“”
)。
split
(
“, ”
)[
1
])
23
)
24
except:
25
pass
26
try:
27
id。append(
28
float(str(i。
split
(
“ score”
)[])。
split
(
“-”
)[]),
29
)
30
except:
31
pass
32
for
t
in
range(
len
(id)):
33
features[
int
(
2
*id[t])]=position[
2
*t]
34
features[
int
(
2
* id[t]+
1
)] =position[
2
*t+
1
]
35
avg_feat=
round
(sum(features)/
len
(features),
3
)
36
for
i
in
range(
len
(features)):
37
if
features[i]==:
38
features[i]=avg_feat
39
f0。write(str(features)+
“\n”
)
40
print(features)
41
except:
42
pass
43
f0。close()
GCN圖卷積神經網路
圖神經網路常常用在對圖模型的識別和訓練上,這裡我們透過修改使得他可以用於訓練姿態識別的資料。
1。讀取特徵資料:
在第二步中將獲取到的姿態特徵儲存成了txt檔案中,現在分別對他們進行讀入資料,程式碼如下:
1
#讀取特徵資料
2
x=[]
3
y=[]
4
f=open(
“shuaidao。txt”
)
5
text
=f。read()
6
text
=
text
。split(
“\n”
)
7
for
t
in
text
:
8
try
:
9
t=t。replace(
“]”
,
“”
)
10
temp=t。replace(
“[”
,
“”
)。split(
“,”
)
11
temp=[float(i)
for
i
in
temp]
12
x。append(temp)
13
y。append(
1
)
14
except:
15
pass
16
f=open(
“common。txt”
)
17
text
=f。read()
18
text
=
text
。split(
“\n”
)
19
for
t
in
text
:
20
try
:
21
t=t。replace(
“]”
,
“”
)
22
temp=t。replace(
“[”
,
“”
)。split(
“,”
)
23
temp=[float(i)
for
i
in
temp]
24
x。append(temp)
25
y。append()
26
except:
27
pass
2。建立圖資料:
建立函式為create_graph,透過dgl庫建立圖,圖的節點數為輸入資料的長度:
1
def
creat_graph
()
:
2
g = dgl。DGLGraph()
3
g。add_nodes(len(x))
4
return
g
3。建立圖網路中的message方法和reduce方法:
基於節點的GCN利用訊息傳播(messagepropagation)來交換相鄰節點之間的資訊。這一過程可以在圖的較大相鄰範圍內提取特徵,其作用類似於卷積網路中的卷積層和池化層。由於該過程中不會有節點消失,因此基於節點的GCN擴充套件了感受野,並避免了局部位置資訊出現損失。程式碼如下:
1
# 主要定義message方法和reduce方法
2
def
gcn_message
(edges)
:
3
return
{
‘msg’
: edges。src[
‘h’
]}
4
def
gcn_reduce
(nodes)
:
5
return
{
‘h’
: torch。sum(nodes。mailbox[
‘msg’
], dim=
1
)}
4。建立GCN層
以圖為物件的基礎上,建立圖網路觸發資訊和節點特徵設定功能:
1
# 定義GCNLayer模組
2
class
GCNLayer
(
nn
。
Module
):
3
def
__init__
(
self
, in_feats, out_feats)
:
4
super
(GCNLayer,
self
)。__init_
_
()
5
self
。linear = nn。Linear(in_feats, out_feats)
6
def
forward
(
self
, g, inputs)
:
7
# g 為圖物件;inputs 為節點特徵矩陣
8
# 設定圖的節點特徵
9
g。ndata[
‘h’
] = inputs
10
# 觸發邊的資訊傳遞觸發節點的聚合函式
11
g。send_and_recv(g。edges(), gcn_message, gcn_reduce)
12
# 取得節點向量
13
h = g。ndata。pop(
‘h’
)
14
# 線性變換
15
return
self
。linear(h)
5。網路層搭建
設定一二層為GCN,啟用函式使用relu啟用函式。
1
class
GCN
(
nn
。
Module
):
2
def
__init__
(
self
, in_feats, hidden_size, num_classes)
:
3
super
(GCN,
self
)。__init_
_
()
4
self
。gcn1 = GCNLayer(in_feats, hidden_size)
5
self
。gcn2 = GCNLayer(hidden_size, num_classes)
6
def
forward
(
self
, g, inputs)
:
7
h =
self
。gcn1(g, inputs)
8
h = torch。relu(h)
9
h =
self
。gcn2(g, h)
10
return
h
6。模型訓練
建立最佳化器為adam最佳化器,學習率使用0。01。將讀入的特徵資料轉成tensor型別,作為輸入。迭代400次,並計算其中的損失輸出:
1
net = GCN(36, 8, 2)
2
x=np。array(x)
3
inputs = torch。from_numpy(x)
4
inputs = torch。tensor(inputs, dtype=torch。float32)
5
print(type(inputs))
6
labeled_nodes = torch。tensor([0, 2])
7
labels = torch。tensor([0, 1])
# 它們的標籤是不同的
8
optimizer = torch。optim。Adam(net。parameters(), lr=0。01)
9
all_logits = []
10
nx_G = G。to_networkx()。to_undirected()
11
pos = nx。kamada_kawai_layout(nx_G)
12
print(inputs)
13
for epoch in range(400):
14
logits = net(G, inputs)
15
#我們儲存logit以便稍後進行視覺化
16
all_logits。append(logits。detach())
17
logp = F。log_softmax(logits, 1)
18
# 我們只計算標記節點的損失
19
loss = F。nll_loss(logp[labeled_nodes], labels)
20
optimizer。zero_grad()
21
loss。backward()
22
optimizer。step()
23
print(‘Epoch %d | Loss: %。4f’ % (epoch, loss。item()))
最終模型測試精度如下圖可見:
圖4 損失函式實驗圖
圖5 損失函式變換曲線
圖6 參考效果圖