شبكات المخططات الإلتفافية III

$$\gdef \sam #1 {\mathrm{softargmax}(#1)}$$ $$\gdef \vect #1 {\boldsymbol{#1}} $$ $$\gdef \matr #1 {\boldsymbol{#1}} $$ $$\gdef \E {\mathbb{E}} $$ $$\gdef \V {\mathbb{V}} $$ $$\gdef \R {\mathbb{R}} $$ $$\gdef \N {\mathbb{N}} $$ $$\gdef \relu #1 {\texttt{ReLU}(#1)} $$ $$\gdef \D {\,\mathrm{d}} $$ $$\gdef \deriv #1 #2 {\frac{\D #1}{\D #2}}$$ $$\gdef \pd #1 #2 {\frac{\partial #1}{\partial #2}}$$ $$\gdef \set #1 {\left\lbrace #1 \right\rbrace} $$ % My colours $$\gdef \aqua #1 {\textcolor{8dd3c7}{#1}} $$ $$\gdef \yellow #1 {\textcolor{ffffb3}{#1}} $$ $$\gdef \lavender #1 {\textcolor{bebada}{#1}} $$ $$\gdef \red #1 {\textcolor{fb8072}{#1}} $$ $$\gdef \blue #1 {\textcolor{80b1d3}{#1}} $$ $$\gdef \orange #1 {\textcolor{fdb462}{#1}} $$ $$\gdef \green #1 {\textcolor{b3de69}{#1}} $$ $$\gdef \pink #1 {\textcolor{fccde5}{#1}} $$ $$\gdef \vgrey #1 {\textcolor{d9d9d9}{#1}} $$ $$\gdef \violet #1 {\textcolor{bc80bd}{#1}} $$ $$\gdef \unka #1 {\textcolor{ccebc5}{#1}} $$ $$\gdef \unkb #1 {\textcolor{ffed6f}{#1}} $$ % Vectors $$\gdef \vx {\pink{\vect{x }}} $$ $$\gdef \vy {\blue{\vect{y }}} $$ $$\gdef \vb {\vect{b}} $$ $$\gdef \vz {\orange{\vect{z }}} $$ $$\gdef \vtheta {\vect{\theta }} $$ $$\gdef \vh {\green{\vect{h }}} $$ $$\gdef \vq {\aqua{\vect{q }}} $$ $$\gdef \vk {\yellow{\vect{k }}} $$ $$\gdef \vv {\green{\vect{v }}} $$ $$\gdef \vytilde {\violet{\tilde{\vect{y}}}} $$ $$\gdef \vyhat {\red{\hat{\vect{y}}}} $$ $$\gdef \vycheck {\blue{\check{\vect{y}}}} $$ $$\gdef \vzcheck {\blue{\check{\vect{z}}}} $$ $$\gdef \vztilde {\green{\tilde{\vect{z}}}} $$ $$\gdef \vmu {\green{\vect{\mu}}} $$ $$\gdef \vu {\orange{\vect{u}}} $$ % Matrices $$\gdef \mW {\matr{W}} $$ $$\gdef \mA {\matr{A}} $$ $$\gdef \mX {\pink{\matr{X}}} $$ $$\gdef \mY {\blue{\matr{Y}}} $$ $$\gdef \mQ {\aqua{\matr{Q }}} $$ $$\gdef \mK {\yellow{\matr{K }}} $$ $$\gdef \mV {\lavender{\matr{V }}} $$ $$\gdef \mH {\green{\matr{H }}} $$ % Coloured math $$\gdef \cx {\pink{x}} $$ $$\gdef \ctheta {\orange{\theta}} $$ $$\gdef \cz {\orange{z}} $$ $$\gdef \Enc {\lavender{\text{Enc}}} $$ $$\gdef \Dec {\aqua{\text{Dec}}}$$
🎙️ Alfredo Canziani

مدخل إلى شبكة المخططات الإلتفافية (GCN)

خلاصة: الاهتمام الذاتي

  • في الاهتمام الذاتي ، لدينا مجموعة من المدخلات $lbrace\boldsymbol{x}_{i}\rbrace^{t}_{i=1}$. على عكس التسلسل ، ليس له ترتيب.
  • المتجه المخفي $boldsymbol{h}$ يُعطى بالتوليفة الخطية للمتجهات في المجموعة.
  • يمكننا التعبير عن هذا كـ $boldsymbol{X}\boldsymbol{a}$ باستخدام ضرب متجه المصفوفة، حيث يحتوي $boldsymbol{a}$ على معاملات تقيس متجه الإدخال $boldsymbol{x}_{i}$.

تأشير


Fig. 1: Graph Convolutional Network

في الشكل 1 ، يتكون الرأس ‪$‬v‪$‬ من متجهين:الإدخال $boldsymbol{x}$ وتمثيله المخفي $boldsymbol{h}$. لدينا أيضًا رؤوس متعددة $v_ {j}$، والتي تتكون من $boldsymbol{x}_j$ و $boldsymbol{h}_j$. في هذا المخطط ، ترتبط الرؤوس بحواف موجهة.

نمثل هذه الحواف الموجهة مع المتجه المجاور $boldsymbol{a}$، حيث يأخذ كل عنصر $alpha_{j}$ القيمة $1$ إذا كان هناك حافة موجهة من $v_{j}$ إلى $v$.

\[\alpha_{j} \stackrel{\tiny \downarrow}{=} 1 \Leftrightarrow v_{j} \rightarrow v \tag{Eq. 1}\]

تُعرَّف الدرجة $d$ (عدد الحواف الواردة) على أنها معيار متجه التقارب هذا، * مثال * $\Vert\boldsymbol{a}\Vert_{1}$ ، الذي يمثل عدد الآحاد في المتجه $boldsymbol{a}$.

\[d = \Vert\boldsymbol{a}\Vert_{1} \tag{Eq. 2}\]

المتجه المخفي $boldsymbol{h}$ يعطى بالتعبير التالي:

\[\boldsymbol{h}=f(\boldsymbol{U}\boldsymbol{x} + \boldsymbol{V}\boldsymbol{X}\boldsymbol{a}d^{-1}) \tag{Eq. 3}\]

حيث أن $f(\cdot)$ هي دالة غير خطية مثل السيجمويد $\sigma(\cdot)$، والظل الهُذْلولي $\tanh(\cdot)$.

تأخذ العبارة $boldsymbol{U}\boldsymbol{x}$ في الحسبان الرأس $v$ نفسه، من خلال تطبيق الدوران $boldsymbol{U}$ على الإدخال $v$.

تذكر أنه في حالة الانتباه الذاتي ، يتم حساب المتجه المخفي $boldsymbol{h}$ بواسطة $boldsymbol{X}\boldsymbol{a}$، مما يعني أن الأعمدة الموجودة في $boldsymbol{X}$ تم تحجيمها بواسطة العوامل في $boldsymbol{a}$. في سياق GCN ، هذا يعني أنه إذا كان لدينا حواف واردة متعددة ، * أي * حواف متعددة في المتجه المجاور $\boldsymbol{a}$ فإن $\boldsymbol{X}\boldsymbol{a}$ يصبح أكبر. من ناحية أخرى ، إذا كان لدينا ميزة واردة واحدة فقط ، فإن هذه القيمة تصبح أصغر. لمعالجة هذه المشكلة المتعلقة بتناسب القيمة مع عدد الحواف الواردة ، نقوم بقسمتها على عدد الحواف الواردة $ d $. ثم نطبق الدوران $boldsymbol{V}$ على$\boldsymbol{X}\boldsymbol{a}d^{-1}$ .

يمكننا تمثيل هذا التمثيل المخفي $boldsymbol{h}$ لمجموعة المدخلات بالكامل $boldsymbol{x}$ باستخدام تدوين المصفوفة التالي:

\[\{\boldsymbol{x}_{i}\}^{t}_{i=1}\rightsquigarrow \boldsymbol{H}=f(\boldsymbol{UX}+ \boldsymbol{VXAD}^{-1}) \tag{Eq. 4}\]

حيث $vect{D} = \text{diag}(d_{i})$.

البوابات المتبقية GCN النظرية والكود

الشبكة الإلتفافية لمخطط البوابات المتبقية هي نوع ينتمي لعائلة GCN و يمكن تمثيلها كما هو موضح في الشكل 2:


Fig. 2: Residual Gated Graph Convolutional Network

كما هو الحال مع GCN القياسي ، يتكون الرأس $v$ من متجهين: الإدخال $\boldsymbol{x}$ وتمثيله المخفي $boldsymbol{h}$. ومع ذلك، في هذه الحالة، تحتوي الحواف أيضًا على تمثيل للميزة، حيث يمثل $boldsymbol{e_{j}^{x}}$ تمثيل حافة الإدخال ويمثل $boldsymbol{e_{j}^{h}}$ تمثيل الحافة المخفية.

يتم حساب التمثيل المخفي $boldsymbol{h}$ للقمة $v$ بالمعادلة التالية:

\[\boldsymbol{h}=\boldsymbol{x} + \bigg(\boldsymbol{Ax} + \sum_{v_j→v}{\eta(\boldsymbol{e_{j}})\odot \boldsymbol{Bx_{j}}}\bigg)^{+} \tag{Eq. 5}\]

حيث يمثل $boldsymbol{x}$ تمثيل الإدخال ، يمثل $boldsymbol{Ax}$ دورانًا مطبقًا على الإدخال $boldsymbol{x}$ و يشير $sum_{v_j→v}{\eta(\boldsymbol{e_{j}})\odot \boldsymbol{Bx_{j}}}$ إلى مجموع الجداء العنصري للميزات الواردة التي تم تدويرها. على النقيض من GCN القياسي أعلاه حيث نقوم بتوسيط التمثيلات الواردة ، فإن مصطلح البوابة ضروري لتنفيذ البقايا المبوبة GCN لأنه يسمح لنا بتعديل التمثيلات الواردة بناءً على تمثيلات الحافة.

لاحظ أن التجميع يقع فقط فوق الرؤوس ${v_j}$ التي لها حواف واردة للرأس ${v}$. المصطلح المتبقي (في Residual Gated GCN) يأتي من حقيقة أنه من أجل حساب التمثيل المخفي $boldsymbol{h}$ ، نضيف تمثيل الإدخال $ boldsymbol{x}$. يتم حساب مصطلح البوابة $eta(\boldsymbol{e_{j}})$ كما هو موضح أدناه:

\[\eta(\boldsymbol{e_{j}})=\sigma(\boldsymbol{e_{j}})\bigg(\sum_{v_k→v}\sigma(\boldsymbol{e_{k}})\bigg)^{-1} \tag{Eq. 6}\]

قيمة البوابة $eta(\boldsymbol{e_{j}})$ هي عبارة عن سيجمويد مسواة تم الحصول عليها بقسمة السيجمويد الخاص بتمثيل الحافة الواردة على مجموع السيجمويد لجميع تمثيلات الحواف الواردة. لاحظ أنه من أجل حساب مصطلح البوابة ، نحتاج إلى تمثيل الحافة $boldsymbol{e_{j}}$، والتي يمكن حسابها باستخدام المعادلات أدناه:

\[\boldsymbol{e_{j}} = \boldsymbol{Ce_{j}^{x}} + \boldsymbol{Dx_{j}} + \boldsymbol{Ex} \tag{Eq. 7}\] \[\boldsymbol{e_{j}^{h}}=\boldsymbol{e_{j}^{x}}+(\boldsymbol{e_{j}})^{+} \tag{Eq. 8}\]

يتم الحصول على تمثيل الحافة المخفية $boldsymbol{e_{j}^{h}}$ من خلال جمع تمثيل الحافة الأولية $boldsymbol{e_{j}^{x}}$ أما $texttt{ReLU}(\cdot)$ فيتم تطبيقه على $boldsymbol{e_{j}}$ حيث يتم إعطاء $boldsymbol{e_{j}}$ بدوره من خلال جمع الاستدارة المطبقة على $boldsymbol{e_{j}^{x}}$ ، استدارة مطبقة على تمثيل الإدخال $boldsymbol{x_{j}}$ للرأس $ v_ {j} $ وتم استدارة مطبقة على تمثيل الإدخال $boldsymbol{x}$ للرأس $v$.

  • ملاحظة: من أجل حساب التمثيلات المخفية في اتجاه مجرى النهر (* على سبيل المثال * طبقة التمثيلات المخفية الثانية) ، يمكننا ببساطة استبدال تمثيلات ميزة الإدخال عن طريق تمثيلات ميزة الطبقة الأولى في المعادلات أعلاه. *

تصنيف المخطط وطبقة البوابات المتبقية GCN

في هذا القسم ، نقدم مشكلة تصنيف المخطط وتشفير طبقة البوابات المتبقية GCN. بالإضافة إلى عبارات الاستيراد المعتادة ، نضيف ما يلي:

os.environ['DGLBACKEND'] = 'pytorch'
import dgl
from dgl import DGLGraph
from dgl.data import MiniGCDataset
import networkx as nx

السطر الأول يخبر DGL باستخدام PyTorch كخلفية. توفر مكتبة المخطط العميق ([DGL] (https://www.dgl.ai/)) وظائف متنوعة على المخططات بينما تسمح لنا networkx برؤية المخططات.

في دفتر الملاحظات هذا ، تتمثل المهمة في تصنيف بنية مخطط معينة إلى نوع من أنواع المخططات الثمانية. تنتج مجموعة البيانات التي تم الحصول عليها من dgl.data.MiniGCDataset عددًا من المخططات (num_graphs) مع عقد بين min_num_v و max_num_v. وبالتالي ، فإن جميع المخططات التي تم الحصول عليها لا تحتوي على نفس عدد العقد / الرؤوس.

  • ملاحظة: من أجل التعرف على أساسيات “DGLGraphs” ، يوصى بالاطلاع على البرنامج التعليمي القصير [هنا] (https://docs.dgl.ai/api/python/graph.html). *

بعد إنشاء المخططات ، فإن المهمة التالية هي إضافة بعض الإشارات إلى المجال. يمكن تطبيق الميزات على عقد وحواف “DGLGraph”. يتم تمثيل الميزات كقاموس للأسماء (سلاسل) وموترات (** الحقول **). ndata و edata` هي عبارة عن سكر لغوي للوصول إلى بيانات ميزات جميع العقد والحواف.

يوضح مقتطف الشفرة التالي كيفية إنشاء الميزات. يتم تعيين قيمة مساوية لعدد حواف العارضة لكل عقدة ، بينما يتم تعيين القيمة 1 لكل حافة.

def create_artificial_features(dataset):
    for (graph, _) in dataset:
        graph.ndata['feat'] = graph.in_degrees().view(-1, 1).float()
        graph.edata['feat'] = torch.ones(graph.number_of_edges(), 1)
    return dataset

يتم إنشاء مجموعات بيانات التدريب والاختبار وتعيين الميزات كما هو موضح أدناه:

trainset = MiniGCDataset(350, 10, 20)
testset = MiniGCDataset(100, 10, 20)

trainset = create_artificial_features(trainset)
testset = create_artificial_features(testset)

يحتوي نموذج المخطط من trainset على التمثيل التالي. هنا ، نلاحظ أن المخطط يحتوي على 15 عقدة و 45 حافة وأن كل من العقد والحواف لها تمثيل مميز للشكل “(1)” كما هو متوقع. علاوة على ذلك ، يشير “0” إلى أن هذا المخطط ينتمي إلى الفئة 0.

(DGLGraph(num_nodes=15, num_edges=45,
         ndata_schemes={'feat': Scheme(shape=(1,), dtype=torch.float32)}
         edata_schemes={'feat': Scheme(shape=(1,), dtype=torch.float32)}), 0)

ملاحظة حول رسالة DGL وتقليل الوظائف

في DGL ، يتم التعبير عن * وظائف الرسالة * كـ (وظائف من تحديد المستخدم) Edge UDF. تأخذ Edge UDFs وسيط واحد edges`. يحتوي على ثلاثة أعضاء “src” و “dst” و “data” للوصول إلى ميزات عقدةالمصدر، ميزات عقدة الوجهة، وميزات الحافة على التوالي.

  • وظائف التقليل * هي عقد ‪‬UDF‪‬. تحتوي عقد UDFs على وسيط واحد “عُقد” ، والتي تحتوي على عضوين هما “data” و “mailbox”. تحتوي “data” على ميزات العقدة ويحتوي “mailbox” على جميع ميزات الرسائل الواردة ، مكدسة على طول البعد الثاني (ومن ثم الوسيطة “dim = 1”). ʻupdate_all (message_func، Red_func) `يرسل الرسائل عبر جميع الحواف

[التطبيق البرمجي لطبقة البوابات المتبقية GCN] (https://www.youtube.com/watch؟v=2aKXWqkbpWg&list=PLLHTzKZVU9eaEyErdV26ikyolxOsz6mq&index=25&t=2098s)

يتم تنفيذ طبقة GCN المتبقية ذات البوابات كما هو موضح في مقتطفات التعليمات البرمجية أدناه.

أولاً ، جميع التدويرات لميزات الإدخال $boldsymbol{Ax}$، $\boldsymbol{Bx_{j}}$، $\boldsymbol{Ce_{j}^{x}}$، $\boldsymbol{Dx_{j}}$ و $boldsymbol{Ex}$ يتم حسابهما من خلال تحديد طبقات nn.Linear داخل وظيفة__init__ ثم إعادة توجيه تمثيلات الإدخال h و ʻe عبر الطبقات الخطية داخل وظيفة forward`

class GatedGCN_layer(nn.Module):

    def __init__(self, input_dim, output_dim):
        super().__init__()
        self.A = nn.Linear(input_dim, output_dim)
        self.B = nn.Linear(input_dim, output_dim)
        self.C = nn.Linear(input_dim, output_dim)
        self.D = nn.Linear(input_dim, output_dim)
        self.E = nn.Linear(input_dim, output_dim)
        self.bn_node_h = nn.BatchNorm1d(output_dim)
        self.bn_node_e = nn.BatchNorm1d(output_dim)

ثانيًا ، نحسب تمثيلات الحواف. يتم ذلك داخل وظيفة message_func ، التي تتكرر عبر جميع الحواف وتحسب تمثيلات الحواف. على وجه التحديد ، السطر e_ij = edges.data['Ce'] + edges.src['Dh'] + edges.dst['Eh'] يحسب * (المعادلة 7) * من أعلى. تشحن Bh_j بالوظيفة message_func (وهو $boldsymbol{Bx_{j}}$ من (المعادلة 5)) و ʻe_ij` (المعادلة 7) عبر الحافة إلى صندوق بريد عقدة الوجهة.

def message_func(self, edges):
    Bh_j = edges.src['Bh']
    # e_ij = Ce_ij + Dhi + Ehj
    e_ij = edges.data['Ce'] + edges.src['Dh'] + edges.dst['Eh']
    edges.data['e'] = e_ij
    return {'Bh_j' : Bh_j, 'e_ij' : e_ij}

ثالثًا ، تقوم وظيفة “reduce_func” بتجميع الرسائل المشحونة بواسطة الوظيفة “message_func”. بعد جمع بيانات العقدة ‪’‬Ah‪’‬ وشحن البيانات Bh_j و ʻe_ij من صندوق البريد ، السطر h = Ah_i + torch.sum (sigma_ij * Bh_j، dim = 1) / torch.sum (sigma_ij، dim = 1) `يحسب التمثيل الخفي لكل عقدة كما هو مبين في (المعادلة 5). مع ذلك ، لاحظ أن هذا لا يمثل سوى المصطلح $(boldsymbol{Ax} + \sum_{v_j → v} {\eta(\boldsymbol{e_{j}})\odot \boldsymbol{Bx_{j}}})$ بدون $ texttt{ReLU}(\cdot)$ و الوصلة المتبقية.

def reduce_func(self, nodes):
    Ah_i = nodes.data['Ah']
    Bh_j = nodes.mailbox['Bh_j']
    e = nodes.mailbox['e_ij']
    # sigma_ij = sigmoid(e_ij)
    sigma_ij = torch.sigmoid(e)
    # hi = Ahi + sum_j eta_ij * Bhj
    h = Ah_i + torch.sum(sigma_ij * Bh_j, dim=1) / torch.sum(sigma_ij, dim=1)
    return {'h' : h}

داخل وظيفة forward ، بعد استدعاء g.update_all ، نحصل على نتائج المخطط الإلتفافي h و ʻe ، والتي تمثل المصطلحين $(\boldsymbol{Ax} + \sum_{v_j→v}{\eta(\boldsymbol{e_{j}})\odot \boldsymbol{Bx_{j}}})$ من(المعادلة 5) و $boldsymbol{e_{j}}\$ من (المعادلة 7) على التوالي. بعد ذلك ، نقوم بتسوية "h" و "e" فيما يتعلق بحجم عقد وحواف المخطط على التوالي. ثم يتم تطبيق تسوية الحزم حتى نتمكن من تدريب الشبكة بشكل فعال. أخيرًا ، نطبق $texttt{ReLU}(\cdot)\$ ونضيف الوصلات المتبقية للحصول على التمثيلات المخفية للعقد والحواف ، والتي يتم إرجاعها بعد ذلك بواسطة وظيفة forward`.

def forward(self, g, h, e, snorm_n, snorm_e):

    h_in = h # residual connection
    e_in = e # residual connection

    g.ndata['h']  = h
    g.ndata['Ah'] = self.A(h)
    g.ndata['Bh'] = self.B(h)
    g.ndata['Dh'] = self.D(h)
    g.ndata['Eh'] = self.E(h)
    g.edata['e']  = e
    g.edata['Ce'] = self.C(e)

    g.update_all(self.message_func, self.reduce_func)

    h = g.ndata['h'] # result of graph convolution
    e = g.edata['e'] # result of graph convolution

    h = h * snorm_n # normalize activation w.r.t. graph node size
    e = e * snorm_e # normalize activation w.r.t. graph edge size

    h = self.bn_node_h(h) # batch normalization
    e = self.bn_node_e(e) # batch normalization

    h = torch.relu(h) # non-linear activation
    e = torch.relu(e) # non-linear activation

    h = h_in + h # residual connection
    e = e_in + e # residual connection

    return h, e

بعد ذلك، نحدد وحدة MLP_Layer التي تحتوي على عدة طبقات متصلة بالكامل (FCN). نقوم بإنشاء قائمة من الطبقات المتصلة بالكامل ونقوم بإعادة توجيهها عبر الشبكة.

أخيرًا ، نقوم بتعريف نموذج “GatedGCN” الخاص بنا والذي يتكون من الفئات المحددة مسبقًا: “GatedGCN_layer” و “MLP_layer”. تعريف نموذجنا (“GatedGCN”) موضح أدناه.

 class GatedGCN(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim, L):
        super().__init__()
        self.embedding_h = nn.Linear(input_dim, hidden_dim)
        self.embedding_e = nn.Linear(1, hidden_dim)
        self.GatedGCN_layers = nn.ModuleList([
            GatedGCN_layer(hidden_dim, hidden_dim) for _ in range(L)
        ])
        self.MLP_layer = MLP_layer(hidden_dim, output_dim)
    def forward(self, g, h, e, snorm_n, snorm_e):
        # input embedding
        h = self.embedding_h(h)
        e = self.embedding_e(e)
        # graph convnet layers
        for GGCN_layer in self.GatedGCN_layers:
            h, e = GGCN_layer(g, h, e, snorm_n, snorm_e)
        # MLP classifier
        g.ndata['h'] = h
        y = dgl.mean_nodes(g,'h')
        y = self.MLP_layer(y)
        return y

في المُنشئ الخاص بنا ، نحدد التضمينات لـ ‪’‬e‪’‬ و h ( self.embedding_e و self.embedding_h) ، و self.GatedGCN_layer وهي قائمة (حجمها $L$) لنموذجنا المحدد مسبقًا : “GatedGCN_layer” ، وأخيرًا “self.MLP_layer” والذي تم تعريفه أيضًا من قبل. بعد ذلك ، باستخدام هذه التهيئة ، نحن ببساطة نعيد توجيهها عبر النموذج والمخرج y.

لفهم النموذج بشكل أفضل ، نهيئ كائنًا من النموذج ونطبعه للحصول على تصور أفضل:

# instantiate network
model = GatedGCN(input_dim=1, hidden_dim=100, output_dim=8, L=2)
print(model)

الهيكل الرئيسي للنموذج مبين أدناه:

GatedGCN(
  (embedding_h): Linear(in_features=1, out_features=100, bias=True)
  (embedding_e): Linear(in_features=1, out_features=100, bias=True)
  (GatedGCN_layers): ModuleList(
    (0): GatedGCN_layer(...)
    (1): GatedGCN_layer(... ))
  (MLP_layer): MLP_layer(
    (FC_layers): ModuleList(...))

ليس من المستغرب أن لدينا طبقتان من “GatedGCN_layer” (منذ “L = 2”) متبوعًا بـ “MLP_layer” والذي ينتج أخيرًا مخرجا من 8 قيم.

من الآن فصاعدًا ، نحدد وظيفتي train و evaluate. في وظيفة train ، لدينا الكود العام الذي يأخذ عينات من dataloader. بعد ذلك ، يتم إدخال batch_graphs ،batch_x ،batch_e, batch_snorm_n و batch_snorm_e لتغذية نموذجنا الذي يُرجع batch_scores (بحجم 8). تتم مقارنة الدرجات المتوقعة بالحقيقة الأساسية في وظيفة الخسارة لدينا:loss(batch_scores, batch_labels). بعد ذلك ، نحذف التدرجات (optimizer.zero_grad()) وننفذ الانتشار الخلفي(J.backward()) ونحدّث أوزاننا (optimizer.step()). أخيرًا ، يتم حساب الخسارة الحقبة ودقة التدريب. علاوة على ذلك ، نستخدم رمزًا مشابهًا لوظيفة evaluate الخاصة بنا.

أخيرًا ، نحن مستعدون للتدريب! وجدنا أنه بعد 40 حقبة من التدريب ، تعلم نموذجنا تصنيف الرسوم البيانية بدقة اختبار تبلغ 87 في المائة.


📝 Go Inoue, Muhammad Osama Khan, Muhammad Shujaat Mirza, Muhammad Muneeb Afzal
Abderrahmane Rahiche
28 Apr 2020