ප්රස්තාරයඅවධානය ජාල v2 (GATV2)

මෙයGATV2 ක්රියාකරුගේ PyTorch ක්රියාත්මක කිරීමකි ප්රස්ථාර අවධානය යොමු කරන ජාලයන් කෙතරම් අවධානයෙන් සිටිනවාද? .

GATV2s GATහා සමාන ප්රස්තාර දත්ත මත ක්රියා කරයි. ප්රස්ථාරයක් නෝඩ් සහ දාර සම්බන්ධ කරන නෝඩ් වලින් සමන්විත වේ. උදාහරණයක් ලෙස, කෝරා දත්ත කට්ටලයේ නෝඩ් පර්යේෂණ පත්රිකා වන අතර දාර යනු පත්රිකා සම්බන්ධ කරන උපුටා දැක්වීම් වේ.

GATV2ක්රියාකරු සම්මත GAT හිස්ථිතික අවධානය යොමු කිරීමේ ගැටළුව විසඳයි. ස්ථිතික අවධානය යනු යතුරු නෝඩ් වෙත අවධානය යොමු කිරීම ඕනෑම විමසුම් නෝඩයක් සඳහා එකම ශ්රේණියක් (ඇණවුමක්) ඇති විටය. ගැට් විමසුම node එකක් මතම ඊට අදාල සිට ප්රධාන node එකක් මතම ඊට අදාල අවධානය ගණනය

ඕනෑමවිමසුම් නෝඩයක් සඳහා , යතුරු වල අවධානය ශ්රේණිය () මත පමණක් රඳා පවතින බව සලකන්න . එබැවින් සියලු විමසුම් සඳහා යතුරු වල අවධානය යොමු කිරීම එකම (ස්ථිතික) පවතී.

GATV2අවධානය යොමු කිරීමේ යාන්ත්රණය වෙනස් කිරීමෙන් ගතික අවධානයට ඉඩ දෙයි,

කෘතිමශබ්ද කෝෂ බැලීමේ දත්ත කට්ටලයක් සමඟ සමහර ප්රස්ථාර ගැටළු වලට GATs ස්ථිතික අවධානය යොමු කිරීමේ යාන්ත්රණය අසමත් වන බව පත්රිකාව පෙන්වයි. එය සම්පූර්ණ සම්බන්ධිත ද්විපාර්ශවීය ප්රස්ථාරයක් වන අතර එහිදී එක් නෝඩ් කට්ටලයක් (විමසුම් නෝඩ්) එයට සම්බන්ධ යතුරක් ඇති අතර අනෙක් නෝඩ් කට්ටලයට යතුරක් සහ ඒ හා සම්බන්ධ වටිනාකමක් ඇත. ඉලක්කය වන්නේ විමසුම් නෝඩ් වල අගයන් පුරෝකථනය කිරීමයි. GAT නිසා එහි සීමිත ස්ථිතික අවධානය මෙම කාර්යය සඳහා අසමත්.

කෝරා දත්ත කට්ටලයේ ස්ථර දෙකක GATV2 පුහුණු කිරීම සඳහා පුහුණු කේතය මෙන්න.

View Run

59import torch
60from torch import nn
61
62from labml_helpers.module import Module

ප්රස්තාරයඅවධානය v2 ස්ථරය

මෙයතනි ප්රස්ථාර අවධානය v2 ස්ථරයකි. GATV2 එවැනි ස්ථර කිහිපයකින් සෑදී ඇත. ආදාන සහ ප්රතිදානයන් ලෙස කොතැනද , එය අවශ්ය වේ .

65class GraphAttentionV2Layer(Module):
  • in_features , , node එකක් මතම ඊට අදාල ආදාන ලක්ෂණ සංඛ්යාව
  • out_features , , node එකක් මතම ඊට අදාල ප්රතිදානය විශේෂාංග සංඛ්යාව වේ
  • n_heads , , අවධානය යොමු ප්රධානීන් සංඛ්යාව වේ
  • is_concat බහු-හිස ප්රති results ල සංයුක්ත කළ යුතුද නැතහොත් සාමාන්යය විය යුතුද යන්න
  • dropout අතහැර දැමීමේ සම්භාවිතාව
  • leaky_relu_negative_slope යනු කාන්දු වන රිලූ සක්රිය කිරීම සඳහා negative ණ බෑවුමයි
  • share_weights සකසා ඇත්නම් True , සෑම දාරයකම ප්රභවයට සහ ඉලක්කගත නෝඩයට එකම අනුකෘතිය යොදනු ලැබේ
78    def __init__(self, in_features: int, out_features: int, n_heads: int,
79                 is_concat: bool = True,
80                 dropout: float = 0.6,
81                 leaky_relu_negative_slope: float = 0.2,
82                 share_weights: bool = False):
92        super().__init__()
93
94        self.is_concat = is_concat
95        self.n_heads = n_heads
96        self.share_weights = share_weights

හිසකටමානයන් ගණන ගණනය කරන්න

99        if is_concat:
100            assert out_features % n_heads == 0

අපිබහු හිස් සංකෝචනය කරන්නේ නම්

102            self.n_hidden = out_features // n_heads
103        else:

අපිබහු හිස් සාමාන්යය කරන්නේ නම්

105            self.n_hidden = out_features

ආරම්භකප්රභව පරිවර්තනය සඳහා රේඛීය ස්ථරය; එනම් ස්වයං අවධානයට පෙර ප්රභව නෝඩ් කාවැද්දීම් පරිවර්තනය කිරීම

109        self.linear_l = nn.Linear(in_features, self.n_hidden * n_heads, bias=False)

share_weights නම් True ඉලක්කගත නෝඩ් සඳහා එකම රේඛීය ස්ථරය භාවිතා වේ

111        if share_weights:
112            self.linear_r = self.linear_l
113        else:
114            self.linear_r = nn.Linear(in_features, self.n_hidden * n_heads, bias=False)

අවධානයලකුණු ගණනය කිරීම සඳහා රේඛීය ස්ථරය

116        self.attn = nn.Linear(self.n_hidden, 1, bias=False)

අවධානයලකුණු සඳහා සක්රිය

118        self.activation = nn.LeakyReLU(negative_slope=leaky_relu_negative_slope)

අවධානයගණනය කිරීමට සොෆ්ට්මැක්ස්

120        self.softmax = nn.Softmax(dim=1)

අවධානයසඳහා යෙදිය යුතු ස්තරය

122        self.dropout = nn.Dropout(dropout)
  • h , හැඩයේ ආදාන නෝඩ් කාවැද්දීම් [n_nodes, in_features] වේ.
  • adj_mat යනු හැඩයේ විඝටන අනුකෘතියකි [n_nodes, n_nodes, n_heads] . එක් එක් හිස සඳහා adjacency එක සමාන [n_nodes, n_nodes, 1] බැවින් අපි හැඩය භාවිතා කරමු. සමපාත අනුකෘතිය නෝඩ් අතර දාර (හෝ සම්බන්ධතා) නියෝජනය කරයි. adj_mat[i][j] නෝඩ් සිට නෝඩ් සිට නෝඩ් i දක්වා දාරයක් තිබේ True නම් j .
124    def forward(self, h: torch.Tensor, adj_mat: torch.Tensor):

නෝඩ්ගණන

134        n_nodes = h.shape[0]

එක්එක් හිස සඳහා ආරම්භක පරිවර්තනයන්. අපි රේඛීය පරිවර්තනයන් දෙකක් කර එක් එක් හිස සඳහා එය බෙදන්න.

140        g_l = self.linear_l(h).view(n_nodes, self.n_heads, self.n_hidden)
141        g_r = self.linear_r(h).view(n_nodes, self.n_heads, self.n_hidden)

අවධානයලකුණු ගණනය කරන්න

එක්එක් හිස සඳහා අපි මේවා ගණනය කරමු . සරලබව සඳහා අපි මඟ හරවා ඇත්තෙමු.

අවධානය ලකුණු (වැදගත්කම) node එකක් මතම ඊට අදාල සිට node එකක් මතම ඊට අදාල අපි එක් එක් හිස සඳහා මෙය ගණනය කරමු.

අවධානය යොමු කිරීමේ යාන්ත්රණය, එය අවධානය ලකුණු ගණනය කරයි. කඩදාසි සාරාංශ , a විසින් අනුගමනය කරන අතර බර දෛශිකයක් සමඟ රේඛීය පරිවර්තනයක් සිදු කරයි

සටහන: අප මෙහි භාවිතා කරන අර්ථ දැක්වීමට සමාන වන කඩදාසි අවලංගු කරයි .

පළමුවඅපි සියලු යුගල සඳහා ගණනය කරමු .

g_l_repeat එක් එක් node එකක් මතම ඊට අදාල කාවැද්දීම නැවත නැවත n_nodes වතාවක් කොහෙද ලැබෙන.

179        g_l_repeat = g_l.repeat(n_nodes, 1, 1)

g_r_repeat_interleave එක් එක් node එකක් මතම ඊට අදාල කාවැද්දීම නැවත නැවත n_nodes වතාවක් කොහෙද ලැබෙන.

184        g_r_repeat_interleave = g_r.repeat_interleave(n_nodes, dim=0)

දැන්අපි ලබා ගැනීම සඳහා ටෙන්සර දෙක එකතු කරමු

192        g_sum = g_l_repeat + g_r_repeat_interleave

ඒනිසා නැවත g_sum[i, j] හැඩගස්වා

194        g_sum = g_sum.view(n_nodes, n_nodes, self.n_heads, self.n_hidden)

ගණනයහැඩයෙන් e යුක්ත වේ [n_nodes, n_nodes, n_heads, 1]

202        e = self.attn(self.activation(g_sum))

ප්රමාණයේඅවසාන මානය ඉවත් කරන්න 1

204        e = e.squeeze(-1)

මෙමadjacency න්යාසය හැඩය [n_nodes, n_nodes, n_heads] හෝ තිබිය යුතුය[n_nodes, n_nodes, 1]

208        assert adj_mat.shape[0] == 1 or adj_mat.shape[0] == n_nodes
209        assert adj_mat.shape[1] == 1 or adj_mat.shape[1] == n_nodes
210        assert adj_mat.shape[2] == 1 or adj_mat.shape[2] == self.n_heads

මැස්සිඅනුකෘතිය මත පදනම් වූ මාස්ක්. සිට දාරයක් නොමැති නම් දක්වා සකසා ඇත.

213        e = e.masked_fill(adj_mat == 0, float('-inf'))

ඉන්පසුඅපි අවධානය යොමු කිරීමේ ලකුණු සාමාන්යකරණය කරමු (හෝ සංගුණක)

සම්බන්ධවූ නෝඩ් කට්ටලය කොහේද?

අපිමෙය කරන්නේ අසම්බන්ධිත යුගල සඳහා සම්බන්ධ නොවූ සැකසීමෙනි.

223        a = self.softmax(e)

අතහැරදැමීමේ විධිමත් කිරීම යොදන්න

226        a = self.dropout(a)

එක්එක් හිස සඳහා අවසාන ප්රතිදානය ගණනය කරන්න

230        attn_res = torch.einsum('ijh,jhf->ihf', a, g_r)

ප්රධානීන්සංයුක්ත කරන්න

233        if self.is_concat:

235            return attn_res.reshape(n_nodes, self.n_heads * self.n_hidden)

ප්රධානීන්ගේමධ්යන්යය ගන්න

237        else:

239            return attn_res.mean(dim=1)