{"id":28103245,"url":"https://github.com/mbhuman/rec-service","last_synced_at":"2026-01-23T22:12:02.513Z","repository":{"id":288994774,"uuid":"969772812","full_name":"MBHuman/rec-service","owner":"MBHuman","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-21T01:05:34.000Z","size":642,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-13T20:27:55.577Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MBHuman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-20T22:30:22.000Z","updated_at":"2025-04-21T01:05:37.000Z","dependencies_parsed_at":"2025-04-20T23:38:39.632Z","dependency_job_id":null,"html_url":"https://github.com/MBHuman/rec-service","commit_stats":null,"previous_names":["mbhuman/rec-service"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/MBHuman/rec-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MBHuman%2Frec-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MBHuman%2Frec-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MBHuman%2Frec-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MBHuman%2Frec-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MBHuman","download_url":"https://codeload.github.com/MBHuman/rec-service/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MBHuman%2Frec-service/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28701137,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T17:25:48.045Z","status":"ssl_error","status_checked_at":"2026-01-23T17:25:47.153Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-13T20:27:23.040Z","updated_at":"2026-01-23T22:12:02.507Z","avatar_url":"https://github.com/MBHuman.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Реализовать сервис рекомендаций, использующий подход TagRec\n\nВ [работе](https://ieeexplore.ieee.org/document/10872817) описывается подход TagRec для последовательных рекоммендаций.\n\n## Задача:\n\nБерляндия, 2025 год.\nВ этой высокотехнологичной стране давно уже всё автоматизировано — от поставки борща по подписке до расписания умных тостеров. Однако с развитием цифровой экономики берлянцы столкнулись с неожиданной проблемой: алгоритмы рекомендаций больше не справляются. Люди жалуются: им советуют одно и то же, будто у них нет права на внезапно захотеть что-то новое.\n\nМинистерство Персонализированного Удовлетворения (МПУ) создало проект национального значения — РекомменДУН: сверхумную систему, способную предсказывать интересы берлянцев раньше, чем они сами об этом подумают.\n\nТебя, как одного из лучших инженеров Академии Искусственного Интеллекта Берляндии (АИИБ), привлекли в команду разработчиков РекомменДУН.\nТвоя задача — построить интеллектуальный движок рекомендаций, который станет ядром всей цифровой инфраструктуры страны.\n\nДля этого тебе предстоит выполнить технические пункты, приведённые в критериях оценивания ниже. Если у тебя останется вдохновение (и немного борща), можешь взяться за дополнительные задачи — они не обязательны, но помогут тебе глубже понять, как устроены рекомендательные системы нового поколения.\n\nУспешная реализация проекта означает запуск в национальном масштабе — с интеграцией в каждую микроволновку, холодильник и цифровое кресло в Берляндии.\n\nДобро пожаловать в проект РекомменДУН.\nБерляндия верит в тебя.\n\n\n# Формулировка проблемы последовательных рекоммендаций:\n\n## A. Базовые понятия:\n\n### Определение 1 (Временной двудольный граф):\n\nВременной двудольный граф можно определить как $G = (\\mathcal{U}, \\mathcal{I}, \\mathcal{E}, \\mathcal{X})$, где $\\mathcal{U}$ и $\\mathcal{I}$ — это непересекающиеся множества пользователей и объектов соответственно.  $\\mathcal{E} \\subseteq \\mathcal{U} \\times \\mathcal{I}$ обозначает множество рёбер между пользователями и объектами. Каждое ребро $e \\in \\mathcal{E}$ задаётся в виде тройки $e = (u, i, t)$, где пользователь $u$ взаимодействует с объектом $i$ в момент времени $t$, при этом $u \\in \\mathcal{U}, i \\in \\mathcal{I}, t \\in \\mathbb{Z}^+$ считаются атрибутами рёбер. \n$x_u, x_i \\in \\mathcal{X}$ обозначают признаки узлов для пользователя $u$ и объекта $i$.\n\n## Постановка задачи:\n\nПусть $\\mathcal{I}_u(T)$ обозначает множество объектов, с которыми пользователь $u$ взаимодействовал до момента времени $T$, а $\\mathcal{I} \\setminus \\mathcal{I}_u(T)$ — оставшиеся объекты. \n$\\mathcal{E}_T \\subseteq \\mathcal{E}$ включает все исторические взаимодействия между пользователями $\\mathcal{U}$ и объектами $\\mathcal{I}$ до момента времени $T$.\n\nЗадача рекомендательной системы с непрерывным временем формулируется следующим образом:\n\n### Определение 2 (Рекомендация в непрерывном времени):\n\nДля заданного пользователя $u$ и момента времени $T$, при наличии множества временных меток $\\mathcal{T'} = \\{ t \\mid t \u003e T \\}$ и временного двудольного графа, построенного на основе $\\mathcal{E}_T$, цель состоит в ранжировании объектов из $\\mathcal{I} \\setminus \\mathcal{I}_u(T)$ на каждом $t \\in \\mathcal{T'}$ по вероятности интереса пользователя $u$.\n\nПостановка задачи следует подходу, где подчёркивается важность новизны через рекомендацию новых, ранее невидимых объектов, а не повторение уже известных взаимодействий. Это позволяет избежать избыточности и улучшить пользовательский опыт. Такой подход подчёркивает способность системы выявлять потенциальные интересы пользователей и исследовать ранее не наблюдавшиеся взаимодействия, что способствует более разнообразным и релевантным рекомендациям.\n\n![image](./images/example.png)\n\n## Подход\n\nПодход состоит из двух частей:\n\n* Генератора графовых представлений с учётом времени\n* Контрастного обучения в TagRec\n\n### Генератор графовых представлений с учетом времени (Temporal-aware Graph View Generator)\n\n![generator](./images/generator.png)\n\nПсевдокод алгоритма генератора графовых представлений:\n\n```py\n# Algorithm: Temporal-Aware Graph View Generator\n\ndef temporal_aware_graph_view_generator(G):\n    # G = (U, I, E, X)\n    U, I, E, X = G\n\n    # Temporal-aware Graph Neural Network\n    Hu, Hi = GNN(U, I, E, X)\n\n    # Latent Interests Mining Module\n    A = softmax((W1 @ Hu) @ (W2 @ Hi).T)\n    E_int = {(u, i) for u in U for i in top_k(A[u])}\n\n    # Temporal-aware Edge Dropping Module\n    C = {}\n    for (u, i, t) in E:\n        C[(u, i, t)] = concatenate([Hu[u], Phi(t), Hi[i]])\n\n    p_e = FUNC(C)\n    f_e = gumbel_softmax(p_e)\n    E_drop = AUG_drop(E, f_e)\n\n    # Temporal Information Perturbation Module\n    p_t = FUNC(C)\n    f_t = gumbel_softmax(p_t)\n    E_time = AUG_time(E, f_t)\n\n    # Reconstruct augmented graph\n    G_prime = reconstruct_graph(U, I, E_int, E_drop, E_time, X)\n\n    return G_prime  # (U', I', E', X')\n```\n\nЦель генератора графов — создать аугментированное представление графа путём обучения его эмбеддингов. Он включает четыре ключевых компонента: \n*TA-GNN*, *модуль извлечения скрытых интересов*, *модуль удаления рёбер* и *модуль искажения временной информации*.\n\n1) TA-GNN:\n\n    Обучает представления узлов, учитывая временные характеристики. На каждом слое $l$ эмбеддинги пользователей $u \\in \\mathcal{U}$ обновляются следующим образом:\n\n    $$\n    m_u^{(l)} = \\text{AGG}^{(l)}(\\{h_i^{(l - 1)} + \\Phi^{(l-1)}(t) | (u,i,t) \\in \\mathcal{E}, i \\in \\mathcal{N}_1(u)\\})\n    $$\n\n    $$\n    h_u^{(l)} = \\text{UPDATE}^{(l)}(h_u^{(l-1)}, m_u^{(l)})\n    $$\n\n\n    где $\\Phi(t)$ — временное встраивание, $\\mathcal{N}_1(u)$ — одношаговые соседи.\n\n2) Модуль извлечения скрытых интересов:\n\n    На основе эмбеддингов пользователей $H_u \\in \\mathbb{R}^{|\\mathcal{U}| \\times d}$ и объектов $H_i \\in \\mathbb{R}^{|\\mathcal{I}| \\times d}$ вычисляется матрица внимания:\n\n    $$\n    A = \\text{Softmax}((W_1 H_u)(W_2 H_i)^{T})\n    $$\n\n    Элементы $A_{ui}$ отражают интерес пользователя $u$ к объекту $i$. Для каждого пользователя выбираются top-$k$ объектов с наибольшими значениями $A_{u*}$:\n\n    $$\n    \\text{Top-k}(A_{u*}) = \\{i_1, \\dots, i_k \\mid A_{ui_1} \\geq \\dots \\geq A_{ui_{|\\mathcal{I}|}},\\; i_j \\in \\text{arg sort}(A_{u*})\\}\n    $$\n\n    Аугментированные рёбра формируются как:\n\n    $$\n    \\mathcal{E}_{\\text{int}} = \\{(u, i) \\mid i \\in \\text{Top-k}(A_{u*}) \\;\\text{для всех}\\; u \\in \\mathcal{U}\\}\n    $$\n\n3) Модуль удаления рёбер:\n   \n    Убирает неинформативные рёбра из графа. Для каждого ребра $(u, i, t) \\in \\mathcal{E}$ формируется представление:\n\n    $$\n    p_e = \\text{FUNC}(h_u \\parallel \\Phi(t) \\parallel h_i) \\\\\n    f_e = \\text{GumbelSoftmax}(p_e) \\\\\n    \\mathcal{E}_{\\text{drop}} = \\text{AUG}_{\\text{drop}}(\\mathcal{E}, f_e)\n    $$\n\n    где $f_e$ — вероятности удаления рёбер, $\\parallel$ обозначает конкатенацию.\n\n4) Модуль искажения временной информации:\n\n    Добавляет шум в метки времени взаимодействий:\n\n    $$\n    p_t = \\text{FUNC}(h_u \\parallel \\Phi(t) \\parallel h_i) \\\\\n    f_t = \\text{GumbelSoftmax}(p_t) \\\\\n    \\mathcal{E}_{\\text{time}} = \\text{AUG}_{\\text{time}}(\\mathcal{E}, f_t)\n    $$\n\n    Для выбранного ребра $e = (u, i, t)$ модифицированная временная метка получается:\n\n    $$\n    t' = t + \\mathcal{N}(0, \\lambda \\cdot \\Delta_u(t)^2)\n    $$\n\n    где $\\Delta_u(t)$ — минимальный интервал между действиями пользователя $u$, $\\lambda$ — гиперпараметр. Такое искажение сохраняет семантический порядок взаимодействий и обеспечивает устойчивость модели.\n\n\n\n### Контрастное обучение в TagRec\n\n![contrastive_learning](./images/contrastive_learning.png)\n\nДля обучения используется 3 типа ошибок:\n\n* $\\mathcal{L}_{sim}$ - Similarity Loss\n* $\\mathcal{L}_{cl}$ - Contrastive Loss\n* $\\mathcal{L}_{bpr}$ - Bayesian Personalized Ranking(BPR) Loss\n\n$\\mathcal{L}_{sim}$ сосредоточена на минимизации взаимной информации между представлениями, создаваемыми двумя генераторами видов (view generators).\n\n$\\mathcal{L}_{cl}$ направлена на усиление согласованности между положительными парами $z_i, z_j$ по сравнению с отрицательными.\n\n$\\mathcal{L}_{bpr}$ широко используется в задачах ранжирования для top-N рекомендаций.\n\n### Similarity Loss\n\nДля функции потерь сходства, следуя принципу InfoMin, используются два различных генератора графов, создающих разные представления одного и того же графа, с целью минимизации взаимной информации между ними.\n\nВ процессе извлечения скрытых интересов пользователей, матрица внимания $\\mathbf{A}$ представляет собой аугментационную операцию.  \nДля модуля удаления рёбер и модуля искажения временной информации используются сэмплированные матрицы состояний $\\mathbf{f}_e$ и $\\mathbf{f}_t$ (Из раздела \"Генератор графовых представлений с учетом времени\"), каждая из которых указывает, какое преобразование было применено к соответствующему ребру.\n\nФормула функции потерь сходства задаётся следующим образом:\n\n$$\n\\mathcal{L}_{\\text{sim}} = \\text{sim}(\\mathbf{A}_1, \\mathbf{A}_2) + \\text{sim}(\\mathbf{f}_{e1}, \\mathbf{f}_{e2}) + \\text{sim}(\\mathbf{f}_{t1}, \\mathbf{f}_{t2})\n$$\n\nДля каждой тестовой тройки $(u, i, t)$ модель-кодировщик генерирует эмбеддинги пользователя $u$ и объекта $i$, обозначаемые как $\\mathbf{e}_u$ и $\\mathbf{e}_i$ соответственно. Предсказанный скор (оценка) для рекомендации объекта $i$ пользователю $u$ во времени $t$ определяется следующим образом:\n\n$$\n\\hat{y}_{uit} = \\mathbf{e}_u \\cdot \\mathbf{e}_i\n$$\n\nгде $\\hat{y}_{uit}$ — итоговая предсказанная оценка, отражающая степень релевантности объекта $i$ для пользователя $u$ в момент времени $t$.\n\n\n### Contrastive Loss\n\nДля контрастной функции потерь используется нормализованная температурно-масштабированная кросс-энтропия (NT-XEnt), с применением механизма самодискриминации узлов для генерации положительных и отрицательных пар.\n\nДля узлов-пользователей представления одного и того же узла $u$ в один и тот же момент времени $t$ считаются положительными парами:\n\n$$\n(h'_{ut}, h''_{ut}) \\quad \\text{где} \\; u \\in \\mathcal{U},\\; t \\in \\mathcal{T},\n$$\n\nа представления разных узлов считаются отрицательными:\n\n$$\n(h'_{u_i t_i}, h''_{u_j t_j}) \\quad \\text{где} \\; u_i \\neq u_j,\\; u_i, u_j \\in \\mathcal{U},\\; t_i, t_j \\in \\mathcal{T}.\n$$\n\nКонтрастная функция потерь для пользователей определяется как:\n\n$$\n\\mathcal{L}_{cl}^{\\text{user}} = \n\\sum_{u_i \\in \\mathcal{U}} \\sum_{t_i \\in \\mathcal{T}} \n-\\log \\frac{\n\\exp\\left( \\text{sim}(h'_{u_i t_i}, h''_{u_i t_i}) / \\tau \\right)\n}{\n\\sum_{u_j \\in \\mathcal{U}} \\sum_{t_j \\in \\mathcal{T}} \n\\exp\\left( \\text{sim}(h'_{u_i t_i}, h''_{u_j t_j}) / \\tau \\right)\n}\n$$\n\nгде $\\tau$ — температурный параметр, а $\\text{sim}(\\cdot, \\cdot)$ — косинусное сходство, определяемое как:\n\n$$\n\\text{sim}(h_i, h_j) = \\frac{h_i \\cdot h_j}{\\|h_i\\|_2 \\cdot \\|h_j\\|_2}\n$$\n\nКонтрастная функция потерь для объектов $\\mathcal{L}_{cl}^{\\text{item}}$ вычисляется аналогично.  \nИтоговая контрастная функция потерь записывается как:\n\n$$\n\\mathcal{L}_{cl} = \\mathcal{L}_{cl}^{\\text{user}} + \\mathcal{L}_{cl}^{\\text{item}}\n$$\n\n### Bayesian Personalized Ranking(BPR) Loss\n\nФункция потерь BPR (Bayesian Personalized Ranking) предполагает, что объекты с наблюдаемой неявной обратной связью должны иметь более высокие предсказанные оценки, чем ненаблюдаемые.  \nДля графа $G$ и его аугментированных графов $G_1$ и $G_2$, функция потерь BPR для графа $G$ задаётся как:\n\n$$\n\\ell^{G}_{\\text{bpr}} = \\sum_{(u,i,j,t) \\in \\mathcal{O}_T^G} -\\log \\sigma(\\hat{y}_{uit} - \\hat{y}_{ujt})\n$$\n\nгде $\\mathcal{O}_T^G$ — обучающая выборка, а $\\sigma(\\cdot)$ — сигмоидная функция.\n\nОбучающие тройки формируются следующим образом:\n\n$$\n\\mathcal{O}_T^G = \\left\\{ (u, i, j, t) \\;\\middle|\\; (u, i, t) \\in \\mathcal{E},\\; j \\in \\mathcal{I} \\setminus \\mathcal{I}_u(t) \\right\\}\n$$\nгде $\\mathcal{I}_u(t)$ — множество объектов, с которыми пользователь $u$ взаимодействовал до времени $t$. Объекты $j$ выбираются случайным образом из ненаблюдаемых.\n\nОбщая функция потерь BPR включает:\n$$\n\\mathcal{L}_{\\text{bpr}} = \\ell^{G}_{\\text{bpr}} + \\ell^{G_1}_{\\text{bpr}} + \\ell^{G_2}_{\\text{bpr}}\n$$\n\nПолная функция ошибки TagRec описывается как: $\\mathcal{L} = \\mathcal{L}_{sim} + \\mathcal{L}_{cl} + \\mathcal{L}_{bpr}$\n\n## Критерии оценивания\n\n| №  | Компонент задания                                                                                 | Баллы | Описание                                                                                         |\n|----|-----------------------------------------------------------------------------------------------------|--------|--------------------------------------------------------------------------------------------------|\n| 1  | Реализация генератора графовых представлений с учетом времени                                       | 20     | Корректная реализация TA-GNN, модуля интересов, удаления рёбер и модуля искажения времени.       |\n| 2  | Контрастное обучение (Contrastive + Similarity + BPR Loss)                                          | 20     | Реализация всех трёх типов потерь и корректное обучение модели на этих данных.                  |\n| 3  | Формат входных графов и универсальность (гибкость признаков $\\mathcal{X}$)                          | 15     | Поддержка произвольных признаков узлов, возможность обработки любого графа по формату.          |\n| 4  | Интеграция сценариев применения (минимум два)                                                       | 10     | Примеры интеграции для разных задач (рекомендации товаров, музыки и т.д.)                        |\n| 5  | Механизм автоматического дообучения                                                                 | 10     | Возможность обновления модели без переобучения с нуля при добавлении новых данных.              |\n| 6  | Поддержка нескольких баз данных (PostgreSQL и SQLite)                                               | 10     | Возможность гибкой интеграции с двумя и более базами данных.                                     |\n| 7  | Юнит-тесты, документация и описание модели                                                          | 5      | README, тесты, описание API и архитектуры модели.                                                |\n| 8  | Эксперименты и метрики (Recall@K, NDCG, MRR и т.д.)                                                 | 10     | Отчет по качеству модели, сравнение до и после аугментаций, таблицы/графики.                    |\n| 9  | (Опционально) Веб-интерфейс (рекомендации изображений, лайки/дизлайки и т.д.)                       | 5      | Простой сайт на Streamlit/FastAPI с визуализацией работы модели.                                |\n| 10 | (Опционально) Сервис должен быть полностью написан на Golang              | 5      | Для последующей передачи на поддержку одной из команд и достаточно высокой производительности |\n| 11 | (Опционально) Дополнительные фичи, исследования, масштабирование, логгирование                                   | 5      | Любые улучшения сверх требований: масштабируемость, кэширование, дебаг-метрики и т.д.           |\n\n**Итого: 100 баллов за основные** , 15 баллов опциональные.\n\nДля минимального выполнения задания(на уд.) надо выполнить задачи: 1,2,3,7\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmbhuman%2Frec-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmbhuman%2Frec-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmbhuman%2Frec-service/lists"}