Вы когда-нибудь хотели, чтобы кто-то за вас решил, что приготовить на обед из имеющихся продуктов? Чтобы этот кто-то собрал готовое блюдо, словно конструктор, из имеющихся пазлов: морковь, сельдерей, курица, грибы, помидоры, картофель. Кто бы это мог быть? Или даже что? Ответ прост — это нейросеть!
В этой статье мы не просто поговорим о том, как создать свою нейросеть, как ее натренировать, как протестировать и подготовить к использованию. Мы обучим ее с нуля на наборе рецептов со множеством продуктов, проверим ее работу и запустим на облачном сервере от Timeweb Cloud.
cloud
Перед тем как сделать нейросеть, необходимо разобраться, как она работает — каково ее внутреннее устройство и как выглядит ее архитектура.
Продолжая язык метафор, вы могли бы представить опытного кулинара, который за долгие годы практики научился лишь по виду ингредиентов определять блюдо, которое из них возможно приготовить.
Мозг кулинара, будучи органической нейросетью, имеет такую синаптическую развесовку, которая позволяет логически соединять выходные данные с входными. На вход — список продуктов, на выход — готовое блюдо.
Точно так же работает цифровая нейросеть, запущенная на компьютере: на входе — данные (ингредиенты), а на выходе — результат (описание блюда).
Если рассматривать нейросеть с точки зрения математики, то это набор слоев, где каждый слой учится находить закономерности. Чем больше данных и слоев, тем умнее нейросеть.
Базовая архитектура нейросети (источник: Unisender)
Разумеется, существует множество нейросетевых архитектур — у каждой свои особенности и нюансы. Однако в рамках этой статьи мы рассмотрим лишь три основных и наиболее популярных:
В нашем генераторе рецептов мы будем использовать архитектуру рекуррентных нейросетей LSTM, ведь нам необходимо очень точно обрабатывать текст — последовательность слов, от которой зависит конечный смысл.
Узнать еще больше об основах работы с нейросетями можно в отдельной статье от Timeweb Cloud — в ней подробно рассмотрены примеры нейросетей, написанных на языке программирования Python.
Перед непосредственным созданием нейросети сперва необходимо подготовить все необходимые инструменты и настроить окружение, в котором будет функционировать нейросеть.
Точно так же, как повар сначала раскладывает ножи, кастрюли и специи, мы подготовим все необходимое перед началом «готовки» искусственного интеллекта.
Язык программирования Python — де-факто стандарт для написания нейросетей. Идеальное решение с простым синтаксисом и богатым функционалом. И библиотек в нем предостаточно! Особенно для нейросетей:
Для лучшего понимания разницы между двумя описанными библиотеками (TensorFlow и PyTorch) можно представить их общие характеристики в формате таблицы:
TensorFlow |
PyTorch |
|
Синтаксис |
формальный |
гибкий |
Популярность |
корпоративная среда |
научная среда |
Визуализация |
да (через TensorBoard) |
нет (по умолчанию) |
Уровень контроля |
низкий |
высокий |
Поддержка |
от Google |
от Facebook |
Все скрипты, демонстрируемые в этом руководстве, запускались с помощью интерпретатора Python версии 3.10.12.
Обучение нейросети может требовать значительных вычислительных ресурсов — особенно при работе с большими объемами данных и сложными архитектурами.
Именно поэтому для обучения моделей используются облачные серверы, позволяющие выполнять тренировку в изолированной среде с нужной конфигурацией.
Timeweb Cloud предоставляет возможность быстро развернуть облачный сервер с необходимыми параметрами. Это особенно удобно для разработки и тестирования нейросетей, а также для последующего размещения приложений на базе ИИ.
Для создания сервера сперва необходимо авторизоваться в панели управления Timeweb Cloud, после чего можно перейти во вкладку Облачные серверы и нажать на кнопку Создать.
Откроется страница с конфигуратором облачного сервера. В рамках этого руководства подойдет операционная система Ubuntu 22.04 с минимальными параметрами (2 CPU, 4 GB RAM) — этого более чем достаточно для обучения нейросети.
Теперь можно выполнить установку Python:
sudo apt install python3-pip
И установить основные библиотеки для работы с нейросетями:
pip install tensorflow pandas
Некоторым пользователям может оказаться полезным инструмент для интерактивных вычислений, в котором пользователь может создавать документы с исходным кодом, текстом на Markdown, формулами LaTeX, визуализациями и результатами выполнения — Jupyter Notebook. Почитать о его установке и использовании можно в отдельной статье от Timeweb Cloud.
После предварительной подготовки можно перейти к созданию простой, но точной нейросети, которая по списку ингредиентов будет предлагать подходящие блюда — не просто распознавать шаблоны, а находить связи между наборами продуктов и готовыми рецептами. Это хороший и легкий старт для тех, кто хочет на практике разобраться в устройстве ИИ-систем.
Для обучения нейросети прежде всего нужны данные — с помощью них она поймет, как находить закономерности.
Несмотря на то что в Интернете есть множество готовых наборов данных (например, зарубежный датасет с рецептами и списком ингредиентов), в этом руководстве мы создадим свой собственный тестовый датасет на 100 строк — этого достаточно для задач распознавания начального уровня.
Рецепты и ингредиенты будут простыми — мы создаем не серьезный проект, а лишь разбираемся в устройстве нейросетей.
Сперва необходимо создать CSV-файл recipes.csv
, содержащий список пар «ингредиенты: рецепт»:
"ingredients","recipe"
"курица, лук, чеснок"," Жаркое из курицы, лука и чеснока"
"курица, карри, сливки","Тушеная курица с карри и сливками"
"масло, зелень, картофель","Тушеный картофель с маслом и зеленью"
"перец, морковь, булгур","Суп на основе перца, моркови и булгура"
"гречка, лук, грибы","Тушеное из гречки, лука и грибов"
"сыр, хлеб, колбаса","Бутерброд с сыром и колбасой"
"рис, помидоры, огурцы","Салат из риса с помидорами и огурцами"
"говядина, картофель, морковь","Тушеная говядина с картофелем и морковью"
"яйца, молоко, мука","Блины из яиц, молока и муки"
"кабачки, чеснок, сметана","Запеченные кабачки с чесноком и сметаной"
"баклажаны, помидоры, сыр","Гратен из баклажанов, помидоров и сыра"
"творог, сахар, ваниль","Творожная запеканка с сахаром и ванилью"
"йогурт, ягоды, мюсли","Парфе из йогурта с ягодами и мюсли"
"кукуруза, фасоль, перец","Сальса из кукурузы, фасоли и перца"
"картофель, сыр, бекон","Запеченный картофель с сыром и беконом"
"говядина, перец, лук","Жаркое из говядины с перцем и луком"
"курица, брокколи, соевый соус","Курица с брокколи в соевом соусе"
"рис, шпинат, сыр","Рис с шпинатом и сыром"
"овсянка, банан, мед","Овсянка с бананом и медом"
"свекла, морковь, яблоко","Витаминный салат из свеклы, моркови и яблока"
"тесто, мясо, лук","Пельмени с мясом и луком"
"говядина, соус барбекю, лук","Говядина в соусе барбекю с луком"
"паста, томатный соус, базилик","Паста с томатным соусом и базиликом"
"рыба, лимон, зелень","Запеченная рыба с лимоном и зеленью"
"мясо индейки, тыква, специи","Тушеная индейка с тыквой и специями"
"сметана, огурцы, укроп","Огурцы в сметане с укропом"
...
Все строки показывать не имеет смысла. Главное — понятна суть. Разумеется, рецепты можно усложнить, сделав более правдоподобными — подходящими под названия реальных блюд.
Важно понимать следующее: ingredients — строка с перечнем продуктов через запятую, recipe — название блюда.
Подготовив данные, можно перейти к самому интересному — к обучению нейросети. Для этого создадим отдельный файл train_model.py
, который будет содержать код на языке Python:
# импортируем компоненты библиотек, необходимые для обучения нейросети
import pandas as pd
import tensorflow as tf
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
import pickle
import json
# Шаг 1. Загрузка данных
data = pd.read_csv('recipes.csv') # чтение файла с рецептами во внутренний объект библиотеки pandas
data.dropna(inplace=True) # исключение возможных пустых строк (inplace=True применяет изменения к объекту data, без возврата нового объекта)
# Шаг 2. Приведение текста к нижнему регистру
# ВАЖНО: модель не различает «Чеснок» и «чеснок», поэтому необходимо привести все текстовые данные к одному виду
data['ingredients'] = data['ingredients'].str.lower() # приведение к нижнему регистру строки с ингредиентами
data['recipe'] = data['recipe'].str.lower() # приведение к нижнему регистру названий блюд
# Шаг 3. Токенизация ингредиентов
# ВАЖНО: текстовые данные необходимо преобразовать в токены, являющиеся числовым форматом для нейросетей
tokenizer = Tokenizer() # создание токенизатора
tokenizer.fit_on_texts(data['ingredients']) # построение словаря, в котором каждому уникальному слову (токену) присваивается свой целочисленный индекс
x_data = pad_sequences(tokenizer.texts_to_sequences(data['ingredients']), maxlen=10) # преобразование строк с ингредиентами в последовательность целых чисел (индексов слов) согласно построенному словарю. Например, строка «картофель масло соль» может стать [12, 5, 8], если «картофель» получил индекс 12, «масло» — 5, «соль» — 8.
# ВАЖНО: параметр «maxlen» отвечает за ограничение максимальной длины входной последовательности. Если необходимо добавить в датасет рецепты, у которых больше 10 ингредиентов, то этот параметр необходимо увеличить
# Шаг 4. Кодирование рецептов
# ВАЖНО: каждому рецепту также нужен свой номер для того, чтобы модель могла различать, что «жаркое» и «бутерброд» – это не одно и тоже
unique_recipes = sorted(set(data['recipe'])) # сбор и сортировка уникальных значений рецептов (set позволяет убрать дубли)
recipe_to_index = {text: idx for idx, text in enumerate(unique_recipes)} # создание словаря, где названиям соответствуют индексы
index_to_recipe = {idx: text for text, idx in recipe_to_index.items()} # создание обратного словарь, где индексам соответствуют названия
y_data = [recipe_to_index[text] for text in data['recipe']] # преобразуем рецепты в индексы на основе созданных словарей
assert len(x_data) == len(y_data), "Ошибка: X и Y имеют разную длину!" # проверка пустых строк для избежания рассинхронизации входов и выходов
# Шаг 5. Установка размеров словарей
vocab_size = len(tokenizer.word_index) + 1 # количество уникальных ингредиентов
output_vocab_size = len(recipe_to_index) # количество уникальных рецептов
# Шаг 6. Сбор модели
# ВАЖНО: за счет архитектуры LSTM (особая память для текста) модель сперва встраивает слова в векторы, а после запоминает последовательность и предсказывает рецепт на выходе
model = tf.keras.Sequential([
tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=64), # превращение чисел в вектора
tf.keras.layers.LSTM(128), # поиск связей в векторах
tf.keras.layers.Dense(128, activation='relu'), # предсказание одного из известных рецептов
tf.keras.layers.Dense(output_vocab_size, activation='softmax')
])
# Шаг 7. Компиляция и запуск обучения
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy']) # компиляция модели с активированной функцией потерь, оптимизатором и метрикой для расчета точности предсказаний
model.fit(x_data, tf.convert_to_tensor(y_data), epochs=20) # запуск обучения модели на 20 эпох (полные проходы по всему обучающему набору данных)
# Шаг 8. Сохранение результатов
model.save('recipe_model.keras') # сохранение обученной модели в файл recipe_model.keras
# сохранение токенизатора в файл tokenizer.pkl. Он нужен, чтобы новые тексты обрабатывались точно так же, как при обучении
with open('tokenizer.pkl', 'wb') as f:
pickle.dump(tokenizer, f)
# сохранение словаря индексов index_to_recipe в файл index_to_recipe.json. Он нужен, чтобы числовые предсказания можно было перевести обратно в названия рецептов
with open('index_to_recipe.json', 'w', encoding='utf-8') as f:
json.dump(index_to_recipe, f, ensure_ascii=False)
Теперь, когда модель обучена и сохранена, можно перейти к следующему этапу — научить ее отвечать на запросы пользователя и генерировать рецепты готовых блюд.
Для этого необходимо создать отдельный скрипт generate.py
, в обязанности которого будет входить:
Полный код исходного файла generate.py
выглядит следующим образом:
# импортируем компоненты библиотек, необходимые для работы нейросети
import tensorflow as tf
from tensorflow.keras.preprocessing.sequence import pad_sequences
import pickle
import json
# Шаг 1. Загрузка модели и данных
model = tf.keras.models.load_model('recipe_model.keras') # загрузка обученной модель из файла recipe_model.keras
# открытие файла tokenizer.pkl в бинарном режиме с десериализацией объекта tokenizer, который необходим для преобразования новые текстовые данных (списки ингредиентов) в числовые последовательности
with open('tokenizer.pkl', 'rb') as f:
tokenizer = pickle.load(f)
# открытие файла index_to_recipe.json, в котором хранится словарь рецептов, который необходим для получения текстового названия рецепта
with open('index_to_recipe.json', 'r', encoding='utf-8') as f:
index_to_recipe = json.load(f)
# Шаг 2. Подготовка ингредиентов
# генерация рецепта на основе пользовательского ввода
def generate_recipe(ingredients_text, top_k=3):
ingredients = [i.strip() for i in ingredients_text.lower().split(",")] # приведение ввода к нижнему регистру
ingredients.sort() # сортировка ввода
cleaned_text = ", ".join(ingredients) # преобразование ввода в формат через запятую
seq = tokenizer.texts_to_sequences([cleaned_text]) # токенизация ввода
padded = pad_sequences(seq, maxlen=10) # дополнение токенизированного ввода до длины 10
# Шаг 3. Предсказание рецепта
pred = model.predict(padded)[0] # получение предсказания от модели
top_k_indices = pred.argsort()[-top_k:][::-1] # поиск индексов топ-K самых больших вероятностей
results = [(index_to_recipe.get(str(i)), round(pred[i] * 100, 2)) for i in top_k_indices] # преобразование индексов в названия рецептов и проценты
return results
# Шаг 4. Ручной запуск скрипта
if __name__ == "__main__":
ingredients = input("Введите ингредиенты через запятую: ")
results = generate_recipe(ingredients)
print("\nЛучшие варианты рецептов:")
for name, score in results:
print(f"- {name} ({score}%)")
Сервер готов, модель обучена, а скрипт генерации успешно работает — самое время проверить, как написанная нейросеть справляется со своей главной задачей.
Тестирование в данном случае не требует сложных методик — наша цель не получить 99,9% точности, а убедиться в том, что модель логично и стабильно работает на датасете в 100 строк.
Теперь можно зайти на сервер с установленным Python (и библиотеками tensorflow и pandas) и создать директорию проекта:
mkdir PythonProject
После чего переходим в созданный каталог:
cd PythonProject
Далее необходимо разместить на удаленном сервере три файла, подготовленных ранее: recipes.csv
, train_model.py
, generate.py
.
Есть два способа это сделать:
После этого можно запустить скрипт train_model.py
для обучения нейросети:
python3 train_model.py
Если все настроено правильно, то в консоли появится прогресс обучения по эпохам.
Тут стоит обратить внимание на важный момент: при запуске обучения на сервере без графического процессора (без GPU, но с CPU) библиотека TensorFlow выводит предупреждающие сообщения в консольный терминал.
Они никак не влияют на итоговый результат обучения и носят исключительно информационный характер.
По завершении обучения в папке проекта появится 3 файла:
recipe_model.keras
— обученная модель.tokenizer.pki
— словарь токенов.index_to_recipe.json
— словарь индексов.Теперь можно проверить работу модели на практике:
python3 generate.py
Нет предела совершенству! Любую созданную модель можно продолжить развивать — выполнять дообучение, улучшать архитектуру, корректировать данные.
А еще можно превратить готовую нейросеть в полноценный сервис:
Разумеется, подобные улучшения требуют более глубоких знаний в области машинного обучения, которые находятся за пределами этого вводного руководства.
Подготовили для вас выгодные тарифы на облачные серверы
В этом коротком руководстве был пройден весь путь создания нейросети — от разбора основ до обучения простой модели с запуском в облаке Timeweb Cloud.
Разработанная реализация помогает разобраться в основных машинного обучения, становясь основой для дальнейшего развития, описанного в предыдущем разделе.
Как видно, нейросети — не магия, а инструмент. Если приложить достаточное количество усилий, то собрать собственную ИИ-систему не так уже сложно.