Хакер - Роботизируем SMM. Как научить нейросеть предсказывать успешность постов в соцсети

Хакер - Роботизируем SMM. Как научить нейросеть предсказывать успешность постов в соцсети

hacker_frei

https://t.me/hacker_frei

Алексей Карпович

Содержание статьи

  • Собираем базу данных для обучения нейронной сети
  • Keras
  • Синтезируем и обучаем нейронную сеть
  • Внедряем нейронную сеть на Python в проект на С++
  • Выводы

У меня есть своя группа «Вконтакте», и мне стало интересно, можно ли спрогнозировать, будет публикация успешной или нет. Я решил написать программу, которая бы автоматически брала текст поста, проверяла его с помощью нейронной сети и публиковала только в том случае, если вероятность получить одобрение аудитории достаточно высока. Разрабатывать мы будем на Qt5 и используем Python и Keras для обучения нейросети.

Для начала в проекте на Qt в файле .pro подключим библиотеку network, добавив строку QT += network. Чтобы разместить пост на стене группы, выполняем код:

QString cit = "Hello!";
QUrl apiUrl;
QString str = "https://api.vkontakte.ru/method/wall.post?owner_id=-78329950&message=" + cit + "&from_group=1&access_token=abcdef&v=5.73";
apiUrl.setUrl(str);
QByteArray requestString = "";

QNetworkRequest request(apiUrl);
request.setRawHeader("Content-Type", "application/octet-stream");

QNetworkAccessManager manager_vk;
connect(&manager_vk, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotV(QNetworkReply*)));
manager_vk.post(request, requestString);

Как видишь, мы отправляем запрос POST с адресом в переменной str. Используем метод VK API wall.post, чтобы разместить пост на стене группы. Параметр owner_id должен быть равен номеру группы, но записан со знаком минус; параметр message содержит текст поста; from_group — указатель, что пост будет размещен от имени сообщества, он равен единице; access_token — токен доступа.

Ты мог заметить, что для обработки запроса мы подключили слот slotV. Он может выглядеть так:

void MainWindow::slotV(QNetworkReply* r)
{
    qDebug() << QString::fromUtf8(r->readAll());
}

В консоли ты увидишь результат запроса: ошибку, если что-то пойдет не так, или сообщение с номером опубликованного поста.

 


Собираем базу данных для обучения нейронной сети

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

Чтобы извлечь каждый пост, отправляем запрос GET:

QString str = "https://api.vk.com/method/wall.getById?posts=-78329950_" + QString::number(cnt) + "&v=5.84&access_token=abcdef";

Мы используем метод VK API wall.getById: извлекаем пост со стены группы по его номеру.

Параметр posts содержит уникальный идентификатор поста (здесь — -78329950_123), который состоит из идентификатора группы со знаком минус и порядкового номера поста, разделенных знаком _. Порядковый номер поста содержится в переменной cnt. Параметр access_token — это токен доступа к группе.

Отправим этот запрос столько раз, сколько постов нам нужно извлечь, изменяя переменную cnt в соответствии с порядковым номером поста. Получим код HTML, который будет содержать текст поста, количество лайков и другую информацию. Распарсим каждый ответ, чтобы извлечь из него текст и количество лайков. Сохраним в текстовый файл данные, которые мы получили.

    номер поста #1
    текст поста #1
    количество лайков #1
    номер поста #2
    текст поста #2
    количество лайков #2
    ...
    номер поста #n
    текст поста #n
    количество лайков #n

Теперь, когда все посты записаны в файл, мы готовы синтезировать нейронную сеть и обучать ее.

 


Keras

Нам понадобится Keras — библиотека для работы с нейронными сетями.

INFO

Есть замечательная книга — «Глубокое обучение на Python» Франсуа Шолле. По ней ты можешь освоить теорию, ознакомиться с примерами решения задач от самых простых до весьма сложных, таких как сверточные сети и генерация изображений.

Для начала выполним ряд стандартных действий и установим Python:

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install python-pip python-dev python-setuptools

Затем установим пакеты научных вычислений для Python:

$ sudo apt-get install build-essential cmake git unzip pkg-config libopenblas-dev liblapack-dev
$ sudo apt-get install python-numpy python-scipy python-matplotlib python-yaml
$ sudo apt-get install libhdf5-serial-dev python-h5py

Поставим TensorFlow:

$ sudo pip install tensorflow

И саму библиотеку Keras:

$ sudo pip install keras

Можно установить Keras и из репозитория на GitHub. В этом случае ты получишь доступ к папке keras/examples с примерами сценариев.

$ git clone https://github.com/fchollet/keras
$ cd keras
$ sudo python setup.py install

Чтобы проверить, что все установилось, попробуй запустить сценарий Keras.

python examples/mnist_cnn.py

Для выполнения этого примера может потребоваться несколько минут.

 


Синтезируем и обучаем нейронную сеть

Основу своей нейронной сети я выбрал из библиотек Keras — нейронная сеть предсказывает, какой отзыв получит рецензия на фильм: положительный или отрицательный. В нашем случае сеть будет определять, получит пост лайки или нет. Начнем с подключения всех необходимых библиотек и модулей.

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from keras.preprocessing.text import Tokenizer

from keras.preprocessing import sequence
from keras.models import Sequential, load_model
from keras.layers import Dense, Dropout, Activation
from keras.layers import Embedding
from keras.layers import Conv1D, GlobalMaxPooling1D

import numpy as np
import pickle

Объявим два массива: string_list и mark_list. В первом будут храниться тексты постов, а во втором ноль, если у соответствующего поста не было лайков, и единица, если были. Прочитаем все посты из созданного ранее файла базы данных.

string_list = []
mark_list = []
handle = open("vkbase.txt", "r")
for i in range(20000):
    s = handle.readline()
    s = handle.readline()
    string_list.append(s)
    s = handle.readline()
    l = int(s)
    if l > 0:
        mark_list.append(1)
    else:
        mark_list.append(0)

Создадим и подготовим токенайзер:

tokenizer = Tokenizer(num_words=15000)
tokenizer.fit_on_texts(string_list)

Токенайзер создает таблицу, в которой каждому слову из нашего массива постов присваивается уникальное число. Максимальное число в моем случае — 15000.

Сохраним таблицу токенайзера в файл, чтобы пользоваться ей в дальнейшем:

with open('tokenizer.pickle', 'wb') as hand:
    pickle.dump(tokenizer, hand, protocol=pickle.HIGHEST_PROTOCOL)

А теперь преобразуем наш массив постов в массив чисел в соответствии с таблицей токенайзера:

sequences = tokenizer.texts_to_sequences(string_list)

Тут я бы хотел отметить, что мы прочитали не все посты из файла, а только те, которые нам понадобятся для обучения нейронной сети. Давай прочитаем оставшиеся 3000 постов, которые будут использоваться для проверки работоспособности нашей нейросети, и также преобразуем их в массивы чисел.

string_list_test = []
mark_list_test = []

for i in range(3000):
    s = handle.readline()
    s = handle.readline()
    string_list_test.append(s)
    s = handle.readline()
    l = int(s)
    if l > 0:
        mark_list_test.append(1)
    else:
        mark_list_test.append(0)

sequences_test = tokenizer.texts_to_sequences(string_list_test)

Далее наши массивы надо привести к формату, удобному для понимания нейронной сетью. Это значит, что число слов в каждом посте должно быть одинаковым. Зададим его равным 400. Если в каком-нибудь посте будет меньше слов, то оставшиеся числа заполнятся нулями:

x_train = sequence.pad_sequences(sequences, maxlen=400)
x_test = sequence.pad_sequences(sequences_test, maxlen=400)

На данный момент все подготовительные мероприятия завершены, и мы можем синтезировать нейронную сеть.

print('Build model...')
model = Sequential()

# We start off with an efficient embedding layer which maps
# our vocab indices into embedding_dims dimensions
model.add(Embedding(20000,
                    50,
                    input_length=400))
model.add(Dropout(0.2))

# We add a Convolution1D, which will learn filters
# word group filters of size filter_length:
model.add(Conv1D(250,
                3,
                padding='valid',
                activation='relu',
                strides=1))
# We use max pooling:
model.add(GlobalMaxPooling1D())

# We add a vanilla hidden layer:
model.add(Dense(250))
model.add(Dropout(0.2))
model.add(Activation('relu'))

# We project onto a single unit output layer, and squash it with a sigmoid:
model.add(Dense(1))
model.add(Activation('sigmoid'))

Этот код я полностью взял из примера и заменил лишь размерности данных.

Давай скомпилируем нашу нейронную сеть.

model.compile(loss='binary_crossentropy',
                    optimizer='adam',
                    metrics=['accuracy'])

А теперь напишем код, который запустит тренировку сети и сохранит результат в файл, чтобы он не потерялся.

model.fit(x_train, mark_list, batch_size=32, epochs=15, validation_data=(x_test, mark_list_test))
model.save("vkbase.h5")

Чтобы начать обучение, нужно запустить наш скрипт на исполнение из консоли. В терминале должна появиться бегущая строка.

14784/20000 [=====================>........] - ETA: 8s - loss: 0.5232 - acc: 0.7835

Процесс может занять до десяти минут, придется подождать. У меня точность обучения составила 62%. Это говорит о том, что в данных была найдена закономерность и сеть можно использовать по назначению. Если бы результат составил 50% или меньше, это значило бы, что закономерностей не найдено и нейронная сеть просто угадывает исход с той же вероятностью.

Давай проверим, как работает наша сеть.

network = load_model("vkbase.h5")
strin = ["А ты знаешь, мне сегодня грустно. Люди разучились быть людьми, В этом мире стало слишком пусто... Слов не надо... Просто обними... Наталия Коденцова"]

#loading tokenizer
with open('tokenizer.pickle', 'rb') as handle:
    tokenizer = pickle.load(handle)

seq = tokenizer.texts_to_sequences(strin)
x_seq = sequence.pad_sequences(seq, maxlen=400)

prediction = network.predict(np.array(x_seq), verbose=1)
print(prediction)

Этот скрипт показывает, с какой вероятностью данная цитата получит лайк. Им мы и будем пользоваться в дальнейшем.

 


Внедряем нейронную сеть на Python в проект на С++

Наша нейронная сеть обучена и готова к использованию. Теперь нам надо внедрить ее в проект на С++ на платформе Qt5, который будет постить отобранные посты в ВК.

#include "/usr/include/python2.7/Python.h"

Py_Initialize();

PyObject *moduleMainString = PyString_FromString("__main__");
PyObject *moduleMain = PyImport_Import(moduleMainString);

PyRun_SimpleString(
    "import pickle\n"
    "import numpy as np\n"
    "from keras.preprocessing.text import Tokenizer\n"
    "from keras.preprocessing import sequence\n"
    "from keras.models import Sequential, load_model    \n"
    "def neuron(text):                                 \n"
    "   network = load_model(\"/home/alex/Projects/vkbase/vkbase.h5\")            \n"
    "   strin = [text]\n"
    "   #loading tokenizer                                 \n"
    "   with open(\"/home/alex/Projects/vkbase/tokenizer.pickle\", \"rb\") as handle:    \n"
    "      tokenizer = pickle.load(handle)              \n"
    "   seq = tokenizer.texts_to_sequences(strin)       \n"
    "   x_seq = sequence.pad_sequences(seq, maxlen=400)     \n"
    "   prediction = network.predict(np.array(x_seq), verbose=1) \n"
    "   return prediction                                    \n"
);

Тебе нужно только прописать свои пути к файлам vkbase.h5 и tokenizer.pickle.

Скрипт, который мы внедрили в проект, — функция под названием neuron, которая принимает параметр text и возвращает вероятность в виде числа prediction. Опишем доступ к нашей функции и аргумент, который мы будем в нее отдавать.

PyObject *func = PyObject_GetAttrString(moduleMain, "neuron");
char [] cit = "Hello!";
PyObject *args = PyTuple_Pack(1, PyString_FromString(cit));

Здесь переменная cit — это пост, который надо проверить. Теперь вызовем нашу функцию с постом в качестве аргумента и получим результат.

PyObject *result = PyObject_CallObject(func, args);
double koef = PyFloat_AsDouble(result);

Переменная koef и есть наш результат, вероятность того, что пост получит лайки. Теперь мы можем проверить его: если он больше 0.5, мы можем размещать пост в сети, если меньше — лучше взять другой.

Таким образом мы можем реализовать автопостинг: завести таймер (например, на один час), по его срабатыванию брать пост из банка постов, проверять на пригодность с помощью нейронной сети и публиковать в случае успеха.

Выводы

После внедрения описанного проекта в реальной группе ВК я увидел результат довольно скоро. Количество лайков не сильно изменилось, но количество подписчиков продолжает расти, так что этот проект оказался не только интересным, но и полезным. Надеюсь, не для меня одного

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei




Report Page