Если вы хотите подписаться на этот блог - откройте блокнот Google Colab [TigerGraph с Pytorch.ipynb - Colaboratory (google.com)]
Вступление:
В этом блоге мы рассмотрим демонстрацию использования Pytorch с выводом графика для прогнозирования того, понравится ли фильм пользователю. Данные собираются из базы данных TigerGraph с помощью PyTigergraph (пакет Python). Данные собираются с помощью вызова REST по пользовательскому запросу. Результат вызова поступает в записную книжку в формате JSON. Используя Pandas, мы можем преобразовать эти данные в фрейм данных. После преобразования данных мы готовим данные для базовой модели машинного обучения с помощью фреймворка Pytorch.
В этом блоге вы узнаете, как создать решение MyGraph с помощью TigerGraph, как извлекать данные с помощью GSQL, а также как построить модель машинного обучения с использованием инфраструктуры Pytorch. Давайте начнем!
Обсуждаемые разделы:
Часть I. Создание (бесплатного) решения TigerGraph на https://tgcloud.io/
Часть II: Настройка ноутбука
Часть III: Предварительная обработка данных
Часть IV: Настройка Pytorch Framework
Часть V: обучающий набор и набор для тестирования
Часть VI: Построение модели
Часть VII: Оптимизация модели
Часть VIII: Оценка модели
Часть I. Создание (бесплатного) решения TigerGraph на https://tgcloud.io/
Во-первых, вам нужно создать бесплатное решение по адресу https://tgcloud.io /. Это облачная платформа, на которой мы будем размещать нашу базу данных графиков. Перейдите на https://tgcloud.io/ и создайте учетную запись, если вы еще этого не сделали. Вы можете зарегистрироваться в Google, LinkedIn или по электронной почте.
После того, как вы зарегистрировались или вошли в систему, перейдите на вкладку «Мои решения» на левой боковой панели, затем нажмите синюю кнопку «Создать решение» в правом верхнем углу.
Для начала вам понадобится экземпляр облака TigerGraph с Recommendation Engine (Movie Recommendation) v3.1.1
Starter Kit. Не выбирайте пустой, потому что у вас не будет данных или модели.
Как только вы нажмете «Далее», мы увидим настройки экземпляра, как показано ниже. Просто оставьте настройку по умолчанию.
Что касается настроек решения, вы можете изменить имя решения, а также начальный пароль. В общем, мы рекомендуем установить пароль «тигрограф».
Просто «Отправить», прежде чем двигаться дальше.
После того, как вы подготовили коробку с упомянутым выше стартовым комплектом, откройте GraphStudio.
В верхнем левом углу вы увидите Global View
, и вы увидите что-то вроде этого, прежде чем двигаться дальше:
Щелкните по нему и выберите MyGraph
. Как только вы выберете MyGraph
, глобальный вид исчезнет, и он будет выглядеть аналогично этому.
Перейдите на вкладку Load Data
. Вы увидите схему с person-(rate)-movie
вместе с некоторыми файлами данных, указывающими на вершину и ребра. Нажмите кнопку воспроизведения, чтобы начать процесс загрузки.
После завершения загрузки данных у вас будет:
Идеально. Теперь у вас Graph UP, и ваши данные ЗАГРУЖЕНЫ. Давайте двигаться дальше.
Часть II: Настройка ноутбука
Шаг I. Нам понадобятся следующие пакеты, установленные на вашем Google Colab. PyTigerGraph - это коннектор, который мы будем использовать для взаимодействия с TigerGraph.
#we install these packages in the google colab !pip install pyTigerGraph !pip install pandas !pip install flat-table !pip install LibTorch !pip install -q sklearn !pip install torch
Затем нам нужно импортировать и реализовать эти пакеты, которые мы установили ранее.
#since we install these packages previously, then we can import and use these packages now import matplotlib.pyplot as plt import pyTigerGraph as tg import pandas as pd import numpy as np import torch as pt import flat_table from __future__ import absolute_import, division, print_function, unicode_literals from sklearn.model_selection import train_test_split from sklearn.datasets import load_iris
Шаг II: настройка подключения сервера к ноутбуку
Теперь давайте настроим коробку с соответствующими настройками. Когда вы подготовили свой ящик, вы дали ему Уникальный URL. Вставьте этот URL в параметр host
. Другой параметр, который вам нужно будет изменить, - это password
. Как правило, пароль по умолчанию - tigergraph
. Замените пароль тем паролем, который вы ввели в процессе подготовки. Запускаем ячейку. Мы распечатаем токен, чтобы убедиться, что соединение работает.
На моем личном хосте это будет выглядеть так:
#connect the google colab to the tigergraph icloud platform ##If it's in my personal case, I will have my host as below conn = tg.TigerGraphConnection(host="https://401a53c7e81d45fdae57fb8ddccf3812.i.tgcloud.io/", graphname = "MyGraph", gsqlVersion="3.0.5", username="tigergraph", password="tigergraph", useCert=True) secret = conn.createSecret() token = conn.getToken(secret, setToken=True) print(token)
Давайте проверим токен!
(‘7u8bgj84v8pt00i761r0d8t12tbcp8gk’, 1629604111, ‘2021–08–22 03:48:31’)
Вы подключены! Давайте воспользуемся подключением, чтобы увидеть, какие конечные точки существуют на коробке.
results = conn.getEndpoints() print(results)
Вы увидите что-то вроде этого:
{‘DELETE /graph/{graph_name}/delete_by_type/vertices/{vertex_type}/’: {‘parameters’: {‘ack’: {‘default’: ‘all’, ‘max_count’: 1…
Нам нужно будет создать новый запрос и установить его на бокс. Мы будем использовать график под названием MyGraph
. Мы примем пользовательский параметр, который рассматривается как вершина, и получим все оценки, которые пользователь дал фильмам.
## feature extraction from gsql with features of userID, movieID, userRating, movie title, genre conn.gsql(‘’’ USE GRAPH MyGraph CREATE QUERY userData(VERTEX<person> p) FOR GRAPH MyGraph { // Feature Extraction of person: movieID, movieTitle, userRating, term, termRating // Sample Param = 271 SumAccum<float> @rating; BagAccum<VERTEX> @user; src = {p}; //From the User S1 = SELECT tgt FROM src:s -(rate:e)-> movie:tgt //Grab all the movies that they rated ACCUM tgt.@rating += e.rating, tgt.@user += p; //Also add a local varible of that users rating PRINT S1[S1.@user as user, S1.title as movieTitle, S1.@rating as userRating, S1.genres as genre]; } INSTALL QUERY userData ‘’’, options=[])
Примечание. Поскольку размеры всех идентификаторов пользователей слишком велики для извлечения, мы сосредоточимся на одном идентификаторе пользователя, которым является «118205», и будем рассматривать его как демонстрационный пример.
Не стесняйтесь экспериментировать с другим идентификатором пользователя, а также с реализацией модели машины факторизации.
Часть III: Предварительная обработка данных
Теперь запрос установлен. Ноутбук подключен. Назовем созданную нами конечную точку для получения данных о человеке 118205
preInstalledResult = conn.runInstalledQuery(“userData”, {“p”:”118205"}) parsR = (preInstalledResult) print(parsR) # full return of REST call
Тогда у нас есть информация о человеке 118205
:
[{‘S1’: [{‘v_id’: ‘2163’, ‘v_type’: ‘movie’, ‘attributes’: {‘user’: [‘118205’], ‘movieTitle’: ‘Attack of the Killer Tomatoes! (1978)’, ‘userRating’: 2, ‘genre’: ‘Comedy|Horror’}}…
Далее нам нужно преобразовать структуру данных JSON.
df = pd.DataFrame(parsR[0][“S1”]) # Grab only the data we are returningdf # take a look at the data format
Тогда у нас есть:
Нормализуем данные в столбце атрибутов.
# Normalize Data # regarded as a preprocessing step df_t1 = flat_table.normalize(df) df_t1[‘attributes.userRating’] = df_t1[‘attributes.userRating’]/5 # divinding by 5 to get a decimal rating which will be used in model df_t1 # Output DataFrame
Тогда у нас есть:
Давайте немного очистим столбцы данных, переименовав их.
# Rename Columns df_t2 = df_t1.rename(columns={ ‘attributes.user’:’userID’, ‘v_id’:’ID’, ‘v_type’:’Type’, ‘attributes.movieID’:’movieID’, ‘attributes.movieTitle’:’movieTitle’, ‘attributes.userRating’:’userRating’, ‘attributes.genre’:’genre’ }) df_t2 # Output DataFrame
Тогда у нас есть:
Затем давайте разберем жанры на отдельные ряды.
# Exploding the genre types to seperate rows data = {‘userID’: [], ‘ID’: [],’Type’: [], ‘movieTitle’: [],’genre’: [],’userRating’: []} for i in df_t2.index: genres = df_t2[“genre”][i].split(“|”) for e in genres: data[‘userID’].append(df_t2[‘userID’][i]) data[“ID”].append(df_t2[“ID”][i]) data[“Type”].append(df_t2[“Type”][i]) data[“movieTitle”].append(df_t2[“movieTitle”][i]) data[“genre”].append(e) data[“userRating”].append(df_t2[“userRating”][i]) df_t2 = pd.DataFrame(data, columns = [‘userID’,’ID’,’Type’,’movieTitle’,’genre’, ‘userRating’]) print(df_t2)
Тогда у нас есть:
Идеально. Теперь давайте перейдем к жанрам и превратим их в столбцы.
# Pivoting the genres into coulmn headers df_t3 = df_t2.pivot(index=’ID’, columns=’genre’, values=’userRating’) df_t3 = pd.DataFrame(df_t3, columns = [‘Action’, ‘Adventure’, ‘Animation’, ‘Children’, ‘Comedy’, ‘Crime’, ‘Documentary’, ‘Drama’, ‘Fantasy’, ‘Film-Noir’, ‘Horror’, ‘IMAX’, ‘Musical’, ‘Mystery’, ‘Romance’, ‘Sci-Fi’, ‘Thriller’, ‘War’, ‘Western’]) df_t3 = df_t3.fillna(0) df_t3 # Output DataFrame
Тогда у нас есть:
Давайте объединим фреймы данных и посмотрим, что у нас получится.
# Put dataframes together df_t4 = pd.merge(df_t2, df_t3, how=’outer’, on=[‘ID’]) df_t5 = df_t4.drop(columns=[‘genre’]) df_t6 = df_t5.drop_duplicates(subset =”ID”) df_t6 # Output DataFrame
Тогда у нас есть датафрейм, который выглядит так:
Давайте извлечем функции только с идентификатором пользователя, идентификатором фильма и рейтингом пользователя.
## extract only userID, movieID and userRating ## there are 19590 observations for user “118205” df_features = df_t2[[‘userID’, ‘ID’, ‘userRating’]] df_features
Тогда у нас есть:
Часть IV: Настройка Pytorch Framework
Давайте настроим фреймворк Pytorch
##installing torchivision and importing torch !pip install torchvision import torch import torchvision
Тогда у нас есть:
Часть V: обучающий набор и набор для тестирования
Давайте разделим набор данных на обучающий набор и набор для тестирования соответственно. 80% для обучающей выборки и 20% для тестовой.
#splitting into 80% for the training set and the 20% for the testing set train_size = int(0.8 * len(df_features)) test_size = len(df_features) — train_size train_dataset, test_dataset = torch.utils.data.random_split(df_features, [train_size, test_size])
Давайте посмотрим на количество наблюдений в обучающей и тестовой выборках соответственно.
## numbers of observation in training set train_size
Тогда у нас есть:
15672
Что касается количества наблюдений в тестовой выборке:
## numbers of observation in testing set test_size
Тогда у нас есть:
3918
Давайте превратим набор для обучения и тестирования в фрейм данных
## import train_test_split from sklearn from sklearn.model_selection import train_test_split train, test = train_test_split(df_features, test_size=0.2)
Взгляните как на обучающий набор, так и на набор для тестирования
## training set train
Тогда у нас есть:
Посмотрим на набор для тестирования
## testing set test
Тогда у нас есть:
Чтобы реализовать DictVectorizer, нам нужно преобразовать «userID» и «ID» (movieID) как категориальный идентификатор.
## convert userid and movieID as categorical identifier for DictVectorizer for both training set and testing set respectively train[“ID”]=train[“ID”].apply(lambda x:”c”+str(x)) train[“userID”]=train[“userID”].apply(lambda x:”u”+str(x)) test[“ID”]=test[“ID”].apply(lambda x:”c”+str(x)) test[“userID”]=test[“userID”].apply(lambda x:”u”+str(x))
Тогда у нас есть:
Давайте посмотрим, как обучающий набор, так и набор тестов соответственно.
## check out training set train
Тогда у нас есть:
Что касается набора для тестирования:
## check out testing set test
Тогда у нас есть:
Чтобы рассматривать их как векторы признаков, нам нужно отбросить «userRating» для каждого обучающего набора и набора тестирования соответственно.
## only consider numbers of ID and numbers of movieID for feature vector train_no_rating=train.drop([‘userRating’],axis=1) test_no_rating=test.drop([‘userRating’],axis=1) alldf=pd.concat([train_no_rating,test_no_rating]) data_num=alldf.shape print(“alldf shape”,alldf.shape)
Тогда у нас есть:
alldf shape (19590, 2)
Давайте воспользуемся функциями векторизатора для создания столбцов на основе функций
##feature vectorizer to create columns based on the features vector=DictVectorizer() vector.fit_transform(alldf.to_dict(orient=’record’)) del alldf
Тогда у нас есть:
/usr/local/lib/python3.7/dist-packages/pandas/core/frame.py:1490: FutureWarning: Using short name for ‘orient’ is deprecated. Only the options: (‘dict’, list, ‘series’, ‘split’, ‘records’, ‘index’) will be used in a future version. Use one of the above to silence this warning. FutureWarning,
Далее нам нужно преобразовать векторы в массив
## transformation into array x_train=vector.transform(train.to_dict(orient=’record’)).toarray() x_test=vector.transform(test.to_dict(orient=’record’)).toarray() print(“x_train shape”,x_train.shape) print(“x_test shape”,x_test.shape)
Тогда у нас есть:
/usr/local/lib/python3.7/dist-packages/pandas/core/frame.py:1490: FutureWarning: Using short name for 'orient' is deprecated. Only the options: ('dict', list, 'series', 'split', 'records', 'index') will be used in a future version. Use one of the above to silence this warning. FutureWarning, x_train shape (15672, 11818) x_test shape (3918, 11818)
Нам нужно изменить форму как набора для тестирования, так и набора для обучения.
## reshape for both testing set and training set y_train=train[‘userRating’].values.reshape(-1,1) y_test=test[‘userRating’].values.reshape(-1,1) print(“y_train shape”,y_train.shape) print(“y_test shape”,y_test.shape)
Тогда у нас есть:
y_train shape (15672, 1) y_test shape (3918, 1)
Часть VI: Построение модели
Настроить параметры:
## set xparameter and yparameter for the x-axis of x_train shape and y-axis for y_train shape respectively xparameter, yparameter =x_train.shape
Реализуем модель машины факторизации.
## Implement Fatorization machine model class FM_model(pt.nn.Module): def __init__(self, yparameter, k): super(FM_model,self).__init__() self.yparameter = yparameter #feature num self.k = k #factor num self.linear=pt.nn.Linear(self.yparameter, 1, bias=True) #linear part self.v=pt.nn.Parameter(pt.rand(self.k,self.yparameter)) #interaction part def fm_layer(self,x): #linear part linear_part=self.linear(pt.tensor(x).float()) #interaction part inter_part1=pt.mm(pt.tensor(x).float(),self.v.t()) inter_part2=pt.mm(pt.pow(pt.tensor(x).float(),2),pt.pow(self.v,2).t()) pair_interactions=pt.sum(pt.sub(pt.pow(inter_part1,2),inter_part2),dim=1) output=linear_part.transpose(1,0)+0.5*pair_interactions return output def forward(self, x): output=self.fm_layer(x) return output
Давайте установим число множителей как 10, можете смело изменять числа множителей, как и другие параметры, и поиграйте!
#numbers of factor k=10 fm=FM_model(yparameter,k) fm
Тогда у нас есть:
FM_model( (linear): Linear(in_features=11818, out_features=1, bias=True) )
Часть VI: Оптимизация модели
Внедрение оптимизатора SGD
##Using the SGD optimizaer as the optimization ##result in the training loss optimizer=pt.optim.SGD(fm.parameters(),lr=0.01) #set learning rate as 0.01,free feel to change and play around for i in range(20): optimizer.zero_grad() output=fm(x_train) output=output.transpose(1,0) #square difference loss_func= pt.nn.MSELoss() mse_loss=loss_func(output,pt.tensor(y_train).float()) l2_regularization=pt.tensor(0).float() #l2 regularization for param in fm.parameters(): l2_regularization+=pt.norm(param,2) loss=mse_loss+l2_regularization loss.backward() optimizer.step() #update
Напечатаем результат
## print loss print(loss)
Тогда имеем результат в проигрыше:
tensor(197.8685, grad_fn=<AddBackward0>)
Часть VIII: Оценка модели
Давайте оценим модель на основе оценки RMSE
## evaluation model based on the RMSE def rmse(pred_rate,real_rate): #implement root mean square error as evaluation loss_func=pt.nn.MSELoss() mse_loss=loss_func(pred_rate,pt.tensor(real_rate).float()) rmse_loss=pt.sqrt(mse_loss) return rmse_loss
Напечатаем результат
#print result pred=fm(x_test) pred=pred.transpose(1,0) rmse_loss=rmse(pred,y_test) print(“test_loss”,rmse_loss) print(y_test[0:5],” “,pred[0:5])
Тогда у нас есть:
test_loss tensor(2.3499, grad_fn=<SqrtBackward>) [[0.5] [0.6] [0.4] [0.7] [0.6]] tensor([[2.8638], [2.8216], [3.6933], [3.2920], [2.3876]], grad_fn=<SliceBackward>)
В целом, у нас есть оценка RMSE 2,3499 для идентификатора пользователя «118250».
Поздравляю! мы сделали! Если вам нравится этот контент, дайте мне знать в аплодисменты, и я добавлю больше подобных блогов в будущем. Не стесняйтесь обращаться ко мне через форум сообщества TigerGraph или чат разработчиков! - [TigerGraph (discord.com)]