Ли Тянь, Шерри Ву, Ифэй Чжэн в рамках курсового проекта Stanford CS224W.

В этом руководстве представлены два метода обнаружения поддельных новостей в социальной сети, такой как Twitter. Оба метода делают прогнозы, используя структуру социальной сети, через которую проходит новость. Пошаговую реализацию можно найти в Блокноте Google Colab.

Оглавление

  1. "Введение"
  2. Набор данных
    2.1. Описание
    2.2. Предварительная обработка
  3. Реализации
    3.1. Реализация GCN
    3.2. Внедрение ГНН-ДП
  4. "Полученные результаты"
  5. Обсуждение
    5.1. Практические выводы
    5.2. Выбор дизайна

1. Введение

Фейковые новости в Интернете — это новая социальная и политическая проблема. Распространение недостоверной информации может легко проходить через существующую онлайн-социальную сеть. Чтобы решить эту проблему, традиционные подходы, которые зависят от людей, проверяющих факты или НЛП, могут не соответствовать их обобщению или вычислительным возможностям.

С появлением Graph Neural Network (GNN) та же самая сеть, которая способствовала распространению фейковых новостей, может быть использована для его остановки. То есть, что, если социальная сеть может сохранять информацию о характере новостей, которые через нее распространяются?

Внутри графа социальной сети мы рассматриваем пользователей Твиттера и новости как узлы, а моделируем поведение (повторное) твиттинга как ребра. Находясь на пересечении Graph ML и NLP, наш метод GCN распространяет текстовые вложения узлов и объединяет их для создания классификации. В качестве альтернативы, заимствуя идеи из сверточной нейронной сети (CNN), наши методы GNN-DP итеративно агрегируют прогнозы по подграфам для получения окончательной метки.

Ниже представлена ​​визуализация применения нашей модели GCN для тестирования (то есть невидимых) данных. Как мы видим, наши методы позволяют эффективно отличать сети, связанные с реальными новостями, от поддельных!

2. Набор данных

Мы использовали набор данных Twitter Fake News Propagation Graph, доступный через GitHub [1], доступный через одноименную статью [2]. Этот набор данных также интегрирован как часть пакета PyG как UPFD [3] или набор данных для обнаружения поддельных новостей с учетом предпочтений пользователя.

2.1. Описание

Набор данных UPFD содержит как настоящие, так и поддельные новостные сети в Твиттере, а данные получены через организации по проверке фактов, такие как Politifact и Gossip Cop. В этом уроке мы будем использовать данные Politifact: этот набор данных содержит N = 314 графиков, 157 из которых связаны с фейковыми новостями. На более детальном уровне у нас есть:

  • Граф: Каждый граф представляет собой древовидную социальную сеть.
  • Узел: корневой узел представляет новость, а конечные узлы представляют пользователей Twitter, которые ретвитнули новость в корне.
  • Край: каждый край представляет поведение ретвита, пользователь ретвитит новости прямо или косвенно (т.е. от другого пользователя).

2.2. Предварительная обработка

Поскольку эти данные хорошо реализованы в пакете PyG, их загрузка и предварительная обработка не вызывают затруднений. Есть два основных аспекта, о которых нам нужно позаботиться. Во-первых, мы собираемся преобразовать ориентированный граф социальной сети в неориентированный. Во-вторых, мы загрузим функции узла: для каждого пользователя и новостного узла мы объединим атрибут их профиля (10-мерный) и кодировку их прошлых твитов через BERT (768-мерный).

from torch_geometric.datasets import UPFD

def load_data(split, feature = None):
  """
  Load train, validation, and test data from the UPFD dataset in PyG. Concact node
  features *profile* and *bert*, which are Twitter user's profile attributes and 
  historical tweets encoded through BERT respectively. toDense transformation is applied
  to return adjacency matrix.

  -------------------------------------
  split: 'train', 'val', or 'test' for retrieving the respective portion of UPFD.
  feature: 'content' or None for which features to retrieve
  -------------------------------------
  Return: PyG dataset object.
  """
  max_nodes = 500 # for convert to dense adj matrix, instead of edge_index
  
  if feature ==  'content':
    return UPFD('/tmp/test', "politifact", feature, split, transform= T.ToDense(max_nodes), pre_transform= ToUndirected())
  else:
    data_profile =  UPFD('/tmp/test', "politifact", "profile", split, transform= T.ToDense(max_nodes), pre_transform= ToUndirected())
    data_bert =  UPFD('/tmp/test', "politifact", "bert", split,  transform=T.ToDense(max_nodes), pre_transform=ToUndirected())
    data_profile.data.x = torch.cat((data_profile.data.x, data_bert.data.x),dim =1)
    return data_profile

3. Реализации

3.1. Реализация GCN

GCN — одна из самых надежных и классических графовых нейронных сетей, которые кажутся подходящими для нашей задачи. В нашей реализации мы разработали структуру, как показано выше. С указанными пользователем входными данными мы создаем определенное количество сверточных слоев с пакетной нормализацией, ReLU и Dropout между двумя последовательными слоями. В самом конце мы применяем глобальный пул для всех узлов, чтобы получить встраивание на уровне графа. Это вложение преобразуется линейным слоем и log-softmax для метки.

Закодируйте это!

Поскольку данные, доступные в UPFD, довольно ограничены по размеру по сравнению с реальным миром, мы не хотим, чтобы это было ограничением для будущих вариантов использования нашей модели. Поэтому мы сделали нашу GCN адаптируемой к потенциально более крупным и сложным графикам.

Наша модель GCN использует словарь аргументов для инициализации и обучения. Помимо обычных, таких как размеры, пользователи могут указать входные аргументы, такие как `num_layers` и `dropout`. В предоставленном нами блокноте Colab вы можете увидеть, что мы тренировались с двумя слоями GCN и без отсева, в первую очередь потому, что наши игрушечные графики относительно неглубокие. Это можно легко настроить для более глубоких и крупных графиков.

Ниже приведен фрагмент того, как определить наш класс GCN, и, пожалуйста, обратитесь к разделу обучения в нашей совместной работе для получения дополнительной информации об инициализации, обучении и оценке модели GCN. Оригинальную опубликованную реализацию можно найти в репозитории автора [4].

class GCN(torch.nn.Module):
  def __init__(self, args):
    """
    Initialize a simple GCN with specific parameters. 
    
    By default, this GCN has 2 convolutional layers and 1 linear layer. 
    It also has 1 layer of batch normalization between the two conv-layers.
    
    If num_layers is provided by user, then this function initializes
    corresponding number of convolutional layers, with batch normalization
    in between. Num_layers must be >= 2.

    -------------------------------------
    self: GCN object
    args["num_features"]: dimension of the input
    args["hidden_dim"]: dimension of the hidden layer(s)
    args["num_classes"]: dimension of the output (i.e. number of classes)
    args["dropout"]: percentage of neurons being zeroed, can be None
    args["num_layers"]: number of convolutional layers, must be >= 2

    """

    assert args.num_layers >= 2, "num_layers must be >= 2."

    super(GCN, self).__init__()  

    # Initialize parameters
    self.num_layers = args.num_layers
    self.dropout = args.dropout   

    # Initialize the first convolutional layer
    self.convs = torch.nn.ModuleList([GCNConv(args.num_features, args.hidden_dim)])

    # Initialize batch normalization layer
    self.bns = torch.nn.ModuleList()

    # Initialize batch normalization layer(s) and the rest of the convolutional layer(s)
    for _ in range(self.num_layers - 1):

      # Initialize the batch normalization layer
      self.bns.extend([torch.nn.BatchNorm1d(args.hidden_dim)])  

      # Initialize the second convolutional layer  
      self.convs.extend([GCNConv(args.hidden_dim, args.hidden_dim)])
    
    # Initialize the final linear layer
    self.lin0 = Linear(args.hidden_dim, args.num_classes)

  def forward(self, data):
    """
    One forward pass with GCN.

    -------------------------------------
    data: PyG Dataset data object, with properties like x, edge_index, batch, etc.

    -------------------------------------
    Return: prediction at the end of one epoch.
    """

    # get features and adjacency matrix
    # -- the batch propery associate nodes within one graph together, it takes 
    #    the form of [1,...,1,2,...2,...,n,...,n] with n being the number of
    #    independent graphs in the entire dataset
    out, edge_index, batch = data.x, data.edge_index, data.batch

    # apply one layer of GNN at a time
    for i in range(self.num_layers - 1):

      # convolutional layer
      out = self.convs[i](out, edge_index)

      # batch normalization
      out = self.bns[i](out)

      # non-linear activation with Re-Lu
      out = F.relu(out)

      # drop out if requested
      if self.dropout > 0:
        out = F.dropout(out, training=self.training)
    
    # the last convolutional layer
    out = self.convs[i+1](out, edge_index)

    # apply graph level pooling per batch (each bath is one indenpendent graph)
    # -- embeddings of each batch/graph with k nodes (1 news node, k-1 user nodes)
    #    are pooled with the mean method to generate a batch/graph level embedding
    #    for lebel prediction
    out = gmp(out, batch)

    # the final linear layer
    out = self.lin0(out)

    # soft max for final prediction
    out = F.log_softmax(out, dim=-1)

    return out

3.2. GNN с реализацией DiffPool

Обучение иерархическому представлению графа с дифференцируемым объединением (DP) — еще одна мощная модель для прогнозирования класса на уровне графа. По сравнению со структурой GCN, которая по своей сути плоская, структура GNN-DP генерирует прогнозы иерархически.

В частности, GNNDP состоит из двух параллельно обучаемых GNN:

• GNN A обрабатывает вложения узлов

• GNN B сопоставляет узлы с набором кластеров.

Уровень дифференциального пула применяется для обработки вложений узлов из GNN A в соответствии с назначением кластера из B для получения обновленных вложений узлов и матрицы смежности.

Полная структура GNN-DP шаг за шагом проиллюстрирована ниже:

Закодируйте это!

Наш режим GNN-DP сначала создает настраиваемый модуль GNN (состоящий из слоев GraphSage и Batchnorm) для параллельных GNN. Затем мы создали модули дифференциального пула, которые вызывают предварительно определенные GNN для обработки внедрения узла и назначения кластера. Мы решили дважды выполнить дифференциальное объединение и последовательно уменьшить размер кластера с 500 до 100 и 20 (по 20% за раз), прежде чем сделать окончательный прогноз softmax со средним объединением и линейным преобразованием. Скорость сокращения кластера и количество используемых слоев диффузионного пула являются выбором дизайна, и мы выбираем комбинацию, которая лучше всего работает с данными UPFD.

Ниже приведен фрагмент того, как определить наш класс GNN-DP, и, пожалуйста, обратитесь к разделу обучения в нашей совместной работе для получения дополнительной информации об инициализации, обучении и оценке модели. Оригинальную опубликованную реализацию можно найти в репозитории автора [4].

class GCNDP(torch.nn.Module):
  def __init__(self, input_dim, hidden_dim, output_dim):
    """
    Initialize a Graph Convolutional Network with Differential Pooling (GCNDP) with specific parameters. 
  
    The embedding matrix and the assignment matrix of eacg graph are computed by two separate customized GNN models respectively.
    In the 2 DIFFPOOL layer architecture, the number of clusters is set as 20% of the number of nodes before applying DIFFPOOL. 
    As a result, with max_node=500, we reduce the nodes to 100 then 20.
    A final GNN layer is applied to compute the embedding matrix before mean aggregation for each graph.

    The final output is 2 class prediction softmax logits after applying relu activation and an affine layer.
    -------------------------------------
    self: GCNDP object
    input_dim: dimension of the input
    hidden_dim: dimension of the hidden layer(s)
    output_dim: dimension of the output (i.e. number of classes)
    """
    super(GCNDP,self).__init__()
    max_nodes = 500

    num_nodes = ceil(0.2 * max_nodes)
    #note below that gnn1_pool has lin=True for cluster assignment, but gnn1_embed has lin=False
    self.gnn1_pool = GNN(input_dim, hidden_dim, num_nodes, lin=True)
    self.gnn1_embed = GNN(input_dim, hidden_dim, hidden_dim, lin=False)
    
    num_nodes = ceil(0.2 * num_nodes)
    self.gnn2_pool = GNN(hidden_dim *2, hidden_dim, num_nodes, lin=True)
    self.gnn2_embed = GNN(hidden_dim *2, hidden_dim, hidden_dim, lin=False)

    self.gnn3_embed = GNN(2 * hidden_dim, hidden_dim, hidden_dim, lin=False)

    self.lin1 = torch.nn.Linear(2 * hidden_dim, hidden_dim)
    self.lin2 = torch.nn.Linear(hidden_dim, output_dim)
    
  def forward(self, x, adj, mask):
    #first diff pool: s for assignment, x for embedding; train both GNNs simultaneuously
    #note below that gnn1_pool has lin=True for cluster assignment, but gnn1_embed has lin=False
    s = self.gnn1_pool(x, adj, mask)
    x = self.gnn1_embed(x, adj, mask)
    x, adj, l1, e1 = dense_diff_pool(x, adj, s, mask) #out, out_adj, link_loss, ent_loss; out is cluster embedding of size B x C x Feature_dimension

    #2nd diff pool, with reduced assignment size [num_nodes = ceil(0.25 * num_nodes)]
    s = self.gnn2_pool(x, adj)
    x = self.gnn2_embed(x, adj)
    x, adj, l2, e2 = dense_diff_pool(x, adj, s)

    #update embedding again, without calculating new assignemnt
    x = self.gnn3_embed(x, adj)

    #calculate new assignemnt with a linear layer
    x = x.mean(dim=1)
    x = F.relu(self.lin1(x))
    x = self.lin2(x)

    return F.softmax(x, dim=-1), l1 + l2, e1 + e2

4. Результаты

Для модели GCN мы получили точность теста 0,8371 и показатель F1 0,8286. Для модели GNN с дифференциальным объединением мы получили точность теста 0,7692 и оценку F1 0,7773. Производительность модели GCN немного лучше.

Ниже левый график представляет вложения до обучения, а правый график представляет вложения после обучения. Каждая строка представляет одну новость, которая имеет либо 778 (до обучения), либо 128 (после обучения) признаков. Предобучающие встраивания реальных и фальшивых новостей выглядят одинаково, в то время как постобучающие встраивания различаются между реальными и фальшивыми новостями. Это показывает, что наша модель хорошо разделяет настоящие и фальшивые новости.

Мы также настроили гиперпараметры модели GCN. Мы сосредоточились на скорости обучения, размере пакета и скрытых параметрах. В лучшей модели используется скорость обучения 0,001, размер пакета 64 и скрытое измерение 128.

+-----------------------------------------+---------------+---------+
| Model Parameters                        | Test Accuracy | Test F1 |
+---------------+------------+------------+               |         |
| Learning Rate | Batch Size | Hidden Dim |               |         |
+---------------+------------+------------+---------------+---------+
| 0.01          | 128        | 128        | 0.8281        | 0.8273  |
+---------------+------------+------------+---------------+---------+
| 0.001         | 128        | 128        | 0.8286        | 0.8387  |
+---------------+------------+------------+---------------+---------+
| 0.001         | 64         | 128        | 0.8371        | 0.8386  |
+---------------+------------+------------+---------------+---------+
| 0.001         | 64         | 64         | 0.8326        | 0.8230  |
+---------------+------------+------------+---------------+---------+

5. Обсуждение

5.1. Практические последствия

Наш проект показывает, что модели GNN обладают высоким потенциалом для быстрого и правильного выявления фейковых новостей, находящихся в социальной сети. Это может быть полезным дополнением к традиционным методам, таким как проверка фактов людьми или массовые модели НЛП.

Эта дискуссия актуальна для нас как никогда. С появлением таких технологий, как GPT-4, поскольку они открывают совершенно новый уровень искусственного интеллекта, генерация информации (которая не совсем точна или сфабрикована с большим количеством нюансов) может быть автоматизирована и выполняться в больших масштабах. Отчасти это может поставить под угрозу усилия по прекращению распространения фейковых новостей. Модели GNN могут сыграть в этом свою роль, используя социальные сети и ориентируясь на них, где дезинформация приносит наибольший вред.

5.2. Выбор дизайна

Проверка фактов для новостей — непростая задача, поэтому, хотя наши модели показывают многообещающие результаты с помощью GNN, мы хотели бы отметить некоторые варианты дизайна, которые мы сделали на этом пути.

Во-первых, если бы у нас было больше времени, мы бы углубились в тонкую настройку структуры построенных нами графовых нейронных сетей, а также в гиперпараметры.

Во-вторых, GNN-DP может оказаться излишним для такой задачи, как наша. Дифференциальное объединение — или иерархическое объединение в целом — очень выразительный метод и может дать действительно хорошие результаты, но некоторые из наших графиков относительно малы, неглубоки или не имеют четких локальных границ соседства. Тем не менее, с большими сетями распространения новостей в реальной жизни, GNN-DP все еще может быть хорошим выбором.

И последнее, но не менее важное: мы смоделировали наши ориентированные графы в неориентированные во время моделирования. Хотя модели GNN все же смогли извлечь из этого уроки, в будущих работах также можно рассмотреть более «нишевые» модели с высокой производительностью на ориентированных графах.

6. Приложение

[1] https://github.com/safe-graph/GNN-FakeNews

[2] Доу, Ю., Шу, К., Ся, К., Ю, П. С., и Сунь, Л. (2021, июль). Обнаружение поддельных новостей с учетом предпочтений пользователя. В Материалы 44-й Международной конференции ACM SIGIR по исследованиям и разработкам в области информационного поиска (стр. 2051–2055).

[3] https://pytorch-geometric.readthedocs.io/en/latest/_modules/torch_geometric/datasets/upfd.html

[4] https://github.com/safe-graph/GNN-FakeNews/tree/main/gnn_model