www.machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Создание рекомендаций Wine с использованием универсального кодировщика предложений

Дата публикации Aug 22, 2019


Изучение НЛП

Natural Language Processing (NLP) очаровала меня с тех пор, как я впервые прочитал о тесте Тьюринга во время изучения риторической теории и технических коммуникаций в колледже. Сложности и тонкости нашего общения всегда казались таким определяющим фактором в том, что делает нас отличным и умным видом, поэтому обучение машине для понимания языка превращает общение из чего-то, что может быть таким неоднозначным, убедительным и одухотворенным, в нечто, что кажется механический, упорядоченный и предсказуемый. Как только я начал программировать, вскоре мое любопытство заставило меня лучше понять, как мы можем использовать машинное обучение, чтобы получить новое понимание естественного языка и получить нюансы, которые мы могли упустить. Например, недавно была опубликована статья, в которой обсуждалось, как НЛП использовался для новых открытий в материаловедении.

Одним из инструментов НЛП, с которым я играл, являетсяУниверсальный кодировщик предложений(USE) размещен наTensorflow-хаб, USE - это предварительно обученная модель, которая кодирует текст в 512-мерный вектор. Он оптимизирован для текста длиной больше слова и обучается различным источникам данных. Есть несколько разных версий USE. Я выбрал модель, которая была обучена с использованием Deep Averaging Network (DAN), так как она меньше ресурсов, чем модель на основе трансформатора. Моим первым проектом с использованием этого инструмента было создание рекомендаций для вина на основе семантического сходства между описаниями вина и моим поисковым запросом. Проект размещен наwww.robotsdodream.com

Авто-сомелье позволяет пользователю вводить запрос и генерировать три винных рекомендации.

Данные

Данные вина, закодированные моделью, получены изобзор винанабор данных найден наkaggle.com.Он содержит около 130 000 строк данных и включает в себя такие столбцы, как страна, описание, название, сорт, винодельня, цена и рейтинг. После того, как я поместил данные в фрейм данных, я отбросил строки, которые содержали повторяющиеся описания, и строки, которые имели нулевую цену. Я также ограничил данные винными сортами, у которых было более 200 отзывов.

#import dependancies
import numpy as np
import pandas as pd
import
tensorflow as tf
import tensorflow_hub as tfhub
import
sqlite3
from
sqlite3 import Error
import io#create a connection to the sqlite database.
conn = sqlite3.connect('db\wine_data.sqlite', detect_types = sqlite3.PARSE_DECELTYPES)
c = conn.cursor()#read the table in the database.
wine_df = pd.read_sql('Select * from wine_data', conn)#Drop the duplicate descriptions.
wine_df = wine_df.drop_duplicates('description')#drop null prices.
wine_df = wine_df.dropna(subset=['price'])#filter the dataframe to include only varieties with more than 200 reviews.
wine_df = wine_df.groupby('variety').filter(lambda x: len(x) > 200)

Сокращение данных за счет исключения сортов с менее чем 200 отзывами оставило у меня 54 сорта вина. Погуглив оставшиеся сорта, я смог добавить столбец «Цвет», чтобы пользователь мог ограничить свой поиск желаемым цветом вина.

#create a column named color.
wine_df["color"] = ""#used to update the database with the wine color. Manually updated each wine variety.
c.execute("update wine_data set color = 'red' where variety = 'Aglianico' ")#commit the update to the database so it saves.
conn.commit()#remove all the records without a color.
wine_df = pd.read_sql("select country, description,rating,price,province,title,variety, winery, color from wine_data where color in ('red', 'white', 'other')", conn)
wine_df.to_sql('wine_data', conn, if_exists = "replace")

После очистки данных у меня осталось 100 228 строк.


Настройка универсального кодировщика предложений

Модель на основе DAN составляет около 800 МБ, поэтому я чувствовал, что важно разместить ее локально. Используя библиотеку ОС, я установил, где модель кэшируется и мог вызывать ее из локального каталога, а не загружать ее каждый раз.

import os#create the directory in which to cache the tensorflow universal sentence encoder.
os.environ["TFHUB_CACHE_DIR"] = 'C:/Users/Admin/Downloads'
download = tfhub.Module("https://tfhub.dev/google/universal-sentence-encoder/2")

После загрузки модели в указанном каталоге появится файл с именем1fb57c3ffe1a38479233ee9853ddd7a8ac8a8c47.

Создание функций

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

def embed_useT():
with tf.Graph().as_default():
text_input = tf.compat.v1.placeholder(dtype = tf.string, shape=[None])
embed = tfhub.Module('C:/Users/Admin/Downloads/1fb57c3ffe1a38479233ee9853ddd7a8ac8a8c47')
em_txt = embed(text_input)
session = tf.compat.v1.train.MonitoredSession()
return lambda x:session.run(em_txt, feed_dict={text_input:list(x)})#run the model.
embed_fn = embed_useT()#encode the wine descriptions.
result = embed_fn(wine_df.description)

Кодирование всех описаний поглощает системные ресурсы и занимает два или более гигабайт оперативной памяти. Чтобы сэкономить на системной памяти, я сохранил массив numpy в своей базе данных SQLite. Вызов массива из базы данных вместо кодирования на лету позволил мне запустить приложение на виртуальной машине, используя два гигабайта оперативной памяти. Кодируя их на лету, я использовал машину, по крайней мере, с 4 гигабайтами оперативной памяти, и даже этого иногда было недостаточно. Сохранение массива в базе данных легко благодаря решению, которое я нашел в stackoverflow:

def adapt_array(arr):
'''
http://stackoverflow.com/a/31312102/190597 (SoulNibbler)
'''
out = io.BytesIO()
np.save(out, arr)
out.seek(0)
return sqlite3.Binary(out.read())

def convert_array(text):
out = io.BytesIO(text)
out.seek(0)
return np.load(out)

# Converts np.array to TEXT when inserting.
sqlite3.register_adapter(np.ndarray, adapt_array)# Converts TEXT to np.array when selecting,
sqlite3.register_converter("array", convert_array)c.execute("create table embeddings (arr array)")conn.commit()c.execute("insert into embeddings (arr) values (?)", (result, ))conn.commit()#return the array
c.execute("select * from embeddings")
data = c.fetchone()[0]

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

def recommend_engine(query, color, embedding_table = result):    wine_df = pd.read_sql('Select * from wine_data', db.session.bind)    embedding = embed_fn([query])#Calculate similarity with all reviews
similarity_score = np.dot(embedding, embedding_table.T) recommendations = wine_df.copy()
recommendations['recommendation'] = similarity_score.T
recommendations = recommendations.sort_values('recommendation', ascending=False)#filter through the dataframe to find the corresponding wine color records.
if (color == 'red'):
recommendations = recommendations.loc[(recommendations.color =='red')]
recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
, 'rating','color']]
elif(color == "white"):
recommendations = recommendations.loc[(recommendations.color =='white')]
recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
, 'rating','color']]
elif(color == "other"):
recommendations = recommendations.loc[(recommendations.color =='other')]
recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
, 'rating','color']]
else:
recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
, 'rating','color']]

return recommendations.head(3).T

Проверьте функцию:

query = "fruity, rich, easy to drink, sweet"
color = 'red'recommendation = recommend_engine(query, color)
print(query)recommendation.head(3).T

Было весело исследовать все данные вина и придумать какой-то легкий способ генерировать рекомендации на основе поискового запроса. Я планирую продолжить изучение Universal Sentence Encoder и подумать о новых проектах, чтобы испытать себя и улучшить свой код. Проверьте остальную часть кода проекта на моем github здесь:

bendgame / WineRecommend

Вы не можете выполнить это действие в данный момент. Вы вошли в другую вкладку или окно. Вы вышли на другой вкладке или ...

github.com


Собираем все вместе

import numpy as np
import pandas as pd
import
tensorflow as tf
import tensorflow_hub as tfhub
import
sqlite3
from
sqlite3 import Error
import ioconn = sqlite3.connect('db\wine_data.sqlite', detect_types = sqlite3.PARSE_DECELTYPES)
c = conn.cursor()#read the table in the database.
wine_df = pd.read_sql('Select * from wine_data', conn)#Drop the duplicate descriptions.
wine_df = wine_df.drop_duplicates('description')#drop null prices.
wine_df = wine_df.dropna(subset=['price'])#filter the dataframe to include only varieties with more than 200 reviews.
wine_df = wine_df.groupby('variety').filter(lambda x: len(x) > 200)#create a column named color.
wine_df["color"] = ""#used to update the database with the wine color. Manually updated each wine variety.
c.execute("update wine_data set color = 'red' where variety = 'Aglianico' ")#commit the update to the database so it saves.
conn.commit()#remove all the records without a color.
wine_df = pd.read_sql("select country, description,rating,price,province,title,variety, winery, color from wine_data where color in ('red', 'white', 'other')", conn)
wine_df.to_sql('wine_data', conn, if_exists = "replace")import os#create the directory in which to cache the tensorflow universal sentence encoder.
os.environ["TFHUB_CACHE_DIR"] = 'C:/Users/Admin/Downloads'
download = tfhub.Module("https://tfhub.dev/google/universal-sentence-encoder/2")def embed_useT():
with tf.Graph().as_default():
text_input = tf.compat.v1.placeholder(dtype = tf.string, shape=[None])
embed = tfhub.Module('C:/Users/Admin/Downloads/1fb57c3ffe1a38479233ee9853ddd7a8ac8a8c47')
em_txt = embed(text_input)
session = tf.compat.v1.train.MonitoredSession()
return lambda x:session.run(em_txt, feed_dict={text_input:list(x)})#run the model.
embed_fn = embed_useT()#encode the wine descriptions.
result = embed_fn(wine_df.description)def recommend_engine(query, color, embedding_table = result): wine_df = pd.read_sql('Select * from wine_data', db.session.bind) embedding = embed_fn([query])#Calculate similarity with all reviews
similarity_score = np.dot(embedding, embedding_table.T)recommendations = wine_df.copy()
recommendations['recommendation'] = similarity_score.T
recommendations = recommendations.sort_values('recommendation', ascending=False)#filter through the dataframe to find the corresponding wine color records.
if (color == 'red'):
recommendations = recommendations.loc[(recommendations.color =='red')]
recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
, 'rating','color']]
elif(color == "white"):
recommendations = recommendations.loc[(recommendations.color =='white')]
recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
, 'rating','color']]
elif(color == "other"):
recommendations = recommendations.loc[(recommendations.color =='other')]
recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
, 'rating','color']]
else:
recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
, 'rating','color']]

return recommendations.head(3).Tquery = "fruity, rich, easy to drink, sweet"
color = 'red'recommendation = recommend_engine(query, color)
print(query)recommendation.head(3).T

Оригинальная статья

Footer decor

© www.machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map