Spaces:
Sleeping
Sleeping
Andrey Shulga
commited on
Commit
·
c8745de
0
Parent(s):
initial commit
Browse files- .gitignore +10 -0
- .python-version +1 -0
- README.md +34 -0
- container_setup/Dockerfile +72 -0
- container_setup/attach.sh +0 -0
- container_setup/build.sh +8 -0
- container_setup/credentials +9 -0
- container_setup/launch_container.sh +18 -0
- main.py +6 -0
- notebooks/ML2_2025_nlp_ops1.ipynb +167 -0
- pyproject.toml +15 -0
- uv.lock +0 -0
.gitignore
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python-generated files
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[oc]
|
| 4 |
+
build/
|
| 5 |
+
dist/
|
| 6 |
+
wheels/
|
| 7 |
+
*.egg-info
|
| 8 |
+
|
| 9 |
+
# Virtual environments
|
| 10 |
+
.venv
|
.python-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
3.13
|
README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Upload a file or csvs with messages/comments
|
| 3 |
+
|
| 4 |
+
My service cleans repetative messages(for example bot are mixed in here)
|
| 5 |
+
|
| 6 |
+
анализатор комментариев которые показывают ссылки на разные но описательные комментарии(сгружаете все комменты с продукта)
|
| 7 |
+
что должен делать:
|
| 8 |
+
- фильтровать ботов
|
| 9 |
+
- фильтровать спам/nsfw/не информативные оскорбления (Кластеризация по LSH, отмести ботов)
|
| 10 |
+
- фильтрация нерелевантных комментариев и сообщений
|
| 11 |
+
- показывать топ РАЗНЫХ по содержанию и по сентименту комментариев
|
| 12 |
+
- суммаризатор мнений
|
| 13 |
+
|
| 14 |
+
идеи для сервиса по анализу комментариев:
|
| 15 |
+
- скор полезности комментария/сообщения
|
| 16 |
+
- скор полезности по лайкам на маркетплейсах (контрастивно учим пары продукт-комментарии)
|
| 17 |
+
|
| 18 |
+
пример:
|
| 19 |
+
- добавить парсер озона чтобы лучше понимать отзывы про продукт? (платно)
|
| 20 |
+
|
| 21 |
+
На вход ест csv?
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
идеи:
|
| 26 |
+
- детектор галлюцинаций
|
| 27 |
+
- извлечение мнений из комментариев
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
uv venv
|
| 33 |
+
|
| 34 |
+
chmod +x container_setup/build container_setup/launch_container
|
container_setup/Dockerfile
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.12-slim
|
| 2 |
+
|
| 3 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 4 |
+
ENV PYTHONUNBUFFERED=1
|
| 5 |
+
|
| 6 |
+
RUN apt-get update && \
|
| 7 |
+
apt-get install -y --no-install-recommends \
|
| 8 |
+
fish \
|
| 9 |
+
git \
|
| 10 |
+
curl \
|
| 11 |
+
vim \
|
| 12 |
+
bash \
|
| 13 |
+
ffmpeg \
|
| 14 |
+
tmux \
|
| 15 |
+
unzip \
|
| 16 |
+
build-essential \
|
| 17 |
+
python3-dev \
|
| 18 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 19 |
+
|
| 20 |
+
# pkg-config \
|
| 21 |
+
# cmake \
|
| 22 |
+
|
| 23 |
+
# cargo \
|
| 24 |
+
# RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \
|
| 25 |
+
# source $HOME/.cargo/env && \
|
| 26 |
+
# rustup default stable
|
| 27 |
+
|
| 28 |
+
# RUN rustup install stable && rustup default stable
|
| 29 |
+
|
| 30 |
+
# RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \
|
| 31 |
+
# source $HOME/.cargo/env && \
|
| 32 |
+
# rustup default stable
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# Declare build arguments before using them
|
| 36 |
+
ARG USER_ID=1000
|
| 37 |
+
ARG GROUP_ID=1000
|
| 38 |
+
|
| 39 |
+
# Create a group and user with the specified UID and GID
|
| 40 |
+
RUN addgroup --gid $GROUP_ID appgroup && \
|
| 41 |
+
adduser --uid $USER_ID --gid $GROUP_ID --shell /bin/bash --disabled-password --gecos "" appuser
|
| 42 |
+
|
| 43 |
+
# Install sudo
|
| 44 |
+
RUN apt-get update && apt-get install -y sudo
|
| 45 |
+
|
| 46 |
+
# Grant sudo privileges to appuser without a password
|
| 47 |
+
RUN echo "appuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
| 48 |
+
|
| 49 |
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
| 50 |
+
|
| 51 |
+
# Switch to the new user
|
| 52 |
+
USER appuser
|
| 53 |
+
|
| 54 |
+
SHELL ["/usr/bin/fish", "-c"]
|
| 55 |
+
|
| 56 |
+
WORKDIR /app
|
| 57 |
+
# Create the virtual environment in a directory not affected by the mount
|
| 58 |
+
# Copy requirements.txt and install dependencies
|
| 59 |
+
# COPY --chown=appuser:appgroup requirements.txt ./
|
| 60 |
+
# RUN uv venv && uv pip install --upgrade pip && \
|
| 61 |
+
# uv pip install -r requirements.txt
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
# Copy the entire project into the container
|
| 65 |
+
COPY --chown=appuser:appgroup pyproject.toml ./
|
| 66 |
+
COPY --chown=appuser:appgroup uv.lock ./
|
| 67 |
+
|
| 68 |
+
RUN uv sync
|
| 69 |
+
|
| 70 |
+
EXPOSE 8000
|
| 71 |
+
|
| 72 |
+
# CMD is now managed by docker-compose to run the Fish shell
|
container_setup/attach.sh
ADDED
|
File without changes
|
container_setup/build.sh
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#! /bin/bash
|
| 2 |
+
|
| 3 |
+
source container_setup/credentials
|
| 4 |
+
|
| 5 |
+
docker build -f container_setup/Dockerfile -t ${DOCKER_NAME} . \
|
| 6 |
+
--build-arg DOCKER_NAME=${DOCKER_NAME} \
|
| 7 |
+
--build-arg USER_ID=${DOCKER_USER_ID} \
|
| 8 |
+
--build-arg GROUP_ID=${DOCKER_GROUP_ID}
|
container_setup/credentials
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#! /bin/bash
|
| 2 |
+
|
| 3 |
+
DOCKER_NAME="opinionanalyzer"
|
| 4 |
+
CONTAINER_NAME=$USER"-opinionanalyzer"
|
| 5 |
+
SRC="OpinionAnalyzer" # folder to propulse in docker container
|
| 6 |
+
DOCKER_USER_ID=$(id -u) # to get these values type "id" in shell termilal
|
| 7 |
+
DOCKER_GROUP_ID=$(id -g)
|
| 8 |
+
CONTAINER_PORT=8001 # used in launch_container file
|
| 9 |
+
INNER_PORT=8001
|
container_setup/launch_container.sh
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#! /bin/bash
|
| 2 |
+
source container_setup/credentials
|
| 3 |
+
|
| 4 |
+
docker run \
|
| 5 |
+
-d \
|
| 6 |
+
--shm-size=8g \
|
| 7 |
+
--memory=32g \
|
| 8 |
+
--cpuset-cpus=96-107 \
|
| 9 |
+
--user ${DOCKER_USER_ID}:${DOCKER_GROUP_ID} \
|
| 10 |
+
--name ${CONTAINER_NAME} \
|
| 11 |
+
--rm \
|
| 12 |
+
-it \
|
| 13 |
+
--init \
|
| 14 |
+
--gpus '"device=4"' \
|
| 15 |
+
-v /home/${USER}/${SRC}:/app \
|
| 16 |
+
-p ${INNER_PORT}:${CONTAINER_PORT} \
|
| 17 |
+
${DOCKER_NAME} \
|
| 18 |
+
bash
|
main.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
def main():
|
| 2 |
+
print("Hello from opinionanalyzer!")
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
if __name__ == "__main__":
|
| 6 |
+
main()
|
notebooks/ML2_2025_nlp_ops1.ipynb
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# __Девопсная домашка по трансформерам__\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"## __Описание__\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"\n",
|
| 12 |
+
"\n",
|
| 13 |
+
"Ваш главный квест на эту домашку - сделать свой простой сервис на трансформерах. Вот прям целый сервис: начиная с данных и заканчивая графическим интерфейсом где-то в интернете. Ваш сервис может решать либо одну из предложенных ниже задач, либо любую другую (что-то более дорогое лично вам).\n",
|
| 14 |
+
"\n",
|
| 15 |
+
"__Стандартная задача: классификатор статей.__ Нужно построить сервис который принимает название статьи и её abstract, и выдаёт наиболее вероятную тематику статьи: скажем, физика, биология или computer science. В интерфейсе должно быть можно ввести отдельно abstract, отдельно название -- и увидеть топ-95%* тематик, отсортированных по убыванию вероятности. Если abstract не ввели, нужно классифицировать статью только по названию. Ниже вас ждут инструкции и данные именно для этой задачи.\n",
|
| 16 |
+
"\n",
|
| 17 |
+
"<details><summary><u> Что значит Топ-95%?</u></summary>\n",
|
| 18 |
+
" Нужно выдавать темы по убыванию вероятности, пока их суммарная вероятность не превысит 95%. В зависимости от предсказанной вероятности, это может быть одна или более тем. Например, если модель предсказала вероятности [4%, 20%, 60%, 2%, 14%], нужно вывести 3 топ-3 класса. Если один из классов имеет вероятность 96%, достаточно вывести один этот класс.\n",
|
| 19 |
+
"</details>\n",
|
| 20 |
+
"\n",
|
| 21 |
+
"Альтернативно, вы можете отважиться сделать что-то своё, на данных из интернета или своих собственных. В вашей задаче обязательно должно быть _оправданное_ использование трансформеров. Использовать ML чтобы переводить часовые пояса - плохой план.\n",
|
| 22 |
+
"\n",
|
| 23 |
+
"Achtung: трансформеры круты, но не всемогущи. Далеко не любую задачу можно решить ощутимо лучше рандома. Для калибровки, вот несколько примеров решаемых задач (всё кликабельно):\n",
|
| 24 |
+
"\n",
|
| 25 |
+
"\n",
|
| 26 |
+
"<details><summary> - <b>[medium]</b> <u>Сгенерировать youtube-комментарии по _ссылке_ на видео</u></summary>\n",
|
| 27 |
+
" Всё просто, юзер постит ссылку на видео - вы его комментируете. Можно заранее обусловиться что видео только на английском или на русском. Нужно сочинить _несколько_ комментариев. Kudos если вместе с основным комментарием вы порождаете юзернеймы и-или ответы на него.\n",
|
| 28 |
+
" \n",
|
| 29 |
+
" Датасет для файнтюна можно [взять с kaggle](https://www.kaggle.com/tanmay111/youtube-comments-sentiment-analysis/data?select=UScomments.csv) или [собрать самостоятельно](https://towardsdatascience.com/how-to-build-your-own-dataset-of-youtube-comments-39a1e57aade).\n",
|
| 30 |
+
" \n",
|
| 31 |
+
" В качестве основной модели можно использовать [GPT-2 large](https://huggingface.co/gpt2-large). Вот как её файнтюнить: https://tinyurl.com/gpt2-finetune-colab . Если хотите больше - можно взять что-то из творчества https://huggingface.co/EleutherAI . Например, вот [тут](https://tinyurl.com/gpt-j-8bit) есть пример как файнтюнить GPT-J-6B (в 8 раз больше gpt2-large). Однако, этим стоит заниматься уже после того, как у вас заработал базовый сценарий с GPT2-large или даже base.\n",
|
| 32 |
+
" \n",
|
| 33 |
+
" В итоговом сервисе ��ожно дать пользователю вариировать параметры генерации: температура или top-p, если сэмплинг; beam size и length penalty, если beam search; сколько комментариев сгенерировать, etc. Отдельный респект если ваш код будет выводить комментарий по одному слову, прямо в процессе генерёжки - чтобы пользователь не ждал пока вы настругаете абзац целиком.\n",
|
| 34 |
+
"</details>\n",
|
| 35 |
+
"\n",
|
| 36 |
+
"<details><summary> - <b>[medium]</b> <u>Предсказать зарплату по профилю (симулятор Дудя).</u></summary>\n",
|
| 37 |
+
" Note: <details> <summary>Причём тут Дудь?</summary> <img src=https://www.meme-arsenal.com/memes/6dd85f126bbab4f9774ced71ffadbcb3.jpg> </details>\n",
|
| 38 |
+
" \n",
|
| 39 |
+
" Главная сложность задачи - достать хорошие данные. Если хороших данных не случилось - можно и трешовые :) Задание всё-таки про технологии а не про продукт. Для начала можно взять подмножество фичей [отсюда](https://www.kaggle.com/c/job-salary-prediction/data), которые вы можете восстановить из профиля linkedin - название профессии и компании. Название компании лучше заменить на фичи из открытых источников: сфера деятельности, размер, етц.\n",
|
| 40 |
+
" \n",
|
| 41 |
+
" А дальше файнтюним на этом BERT / T5 и радуемся. Ну или хотя бы смеёмся.\n",
|
| 42 |
+
"</details>\n",
|
| 43 |
+
"\n",
|
| 44 |
+
"\n",
|
| 45 |
+
"<details><summary> - <b>[hard]</b> <u>Мнения с географической окраской.</u></summary>\n",
|
| 46 |
+
" \n",
|
| 47 |
+
" Сервис который принимает на вход тему (хэштег или ключевую фразу) и рисует карту мира, где в каждом регионе показано, с какой эмоциональной окраской о ней высказываются в социальных сетях. В качестве социальной сети можно взять VK/twitter, в случая VK ожидается детализация не по странам, а по городам стран бывшего СССР.\n",
|
| 48 |
+
" \n",
|
| 49 |
+
" В минимальном варианте достаточно определять тональность твита в режиме \"позитивно-негативно\", зафайнтюнив условный BERT/T5 на одном из десятков {vk/twitter} sentiment classification датасетах. Географическую привязку можно получить из профиля пользователя. А дальше осталось собрать данные по странам и регионам.\n",
|
| 50 |
+
"\n",
|
| 51 |
+
"</details>\n",
|
| 52 |
+
"\n",
|
| 53 |
+
"\n",
|
| 54 |
+
"<details><summary> - <b>[very hard]</b> <u>Найти статью википедии по фото предмета статьи</u></summary>\n",
|
| 55 |
+
"\n",
|
| 56 |
+
" Чтобы можно было сфотать какую-нибудь неведомую чешуйню на телефон и получить сумму человеческих знаний о ней в форме вики-статьи.\n",
|
| 57 |
+
" \n",
|
| 58 |
+
" В качестве функции потерь можно использовать contrastive loss. Этот лосс неплохо описан в статье [CLIP](https://arxiv.org/abs/2103.00020). Вместо обучения с нуля предлагается взять, собственно, CLIP (text transformer + image transformer) отсюда: https://huggingface.co/docs/transformers/model_doc/clip. Модель будет сопоставлять каждой статьи и \n",
|
| 59 |
+
" \n",
|
| 60 |
+
" Данные для этого квеста можно собрать через API википедии: вики-статьи о предметах обычно содержит фото этого объекта и, собственно, текст статьи. Советуем собрать как минимум 10^4 пар картинка-статья. Картинки советуем дополнительно аугментировать как минимум стандартными картиночными аугами, как максимум - поиском похожих картинок в интернете / imagenet-е по тому же CLIP image encoder-у, но с исходными весами.\n",
|
| 61 |
+
" \n",
|
| 62 |
+
" На время отладки интерфейса рекомендуем ограничить��я небольшим списком статьей: условно, кошечки, собачки, птички, гаечные ключи, машины. Как станет понятно что оно работает \"на кошках\", можно расширить этот список до \"всех статей таких-то категорий\". Эмбединги статей лучше предпосчитать в файл. Если долго их перебирать - можно (но необязательно) воспользоваться быстрым поиском соседей, e.g. [faiss](https://github.com/facebookresearch/faiss) HNSW.\n",
|
| 63 |
+
"</details>\n",
|
| 64 |
+
"\n",
|
| 65 |
+
"\n",
|
| 66 |
+
"## __Как научить классификатор статей?__\n",
|
| 67 |
+
"\n",
|
| 68 |
+
"Данные для классификации статей можно скачать, например, [отсюда](https://www.kaggle.com/neelshah18/arxivdataset/). В этих данных есть заголовок и abstract статьи, а ещё поле __\"tag\"__: тематика статьи [по таксономии arxiv.org](https://arxiv.org/category_taxonomy). Вы можете расширить выборку, добавив в неё статьи за 2019-н.в. годы. Для этого можно [использовать arxiv API](https://github.com/lukasschwab/arxiv.py), самостоятельно распарсить arxiv с помощью [beautifulsoup](https://pypi.org/project/beautifulsoup4/), или поискать другие датасеты на kaggle, huggingface, etc.\n",
|
| 69 |
+
"\n",
|
| 70 |
+
"Когда данные собраны (и аккуратно нарезаны на train/test), можно что-нибудь и обучить. Мы советуем использовать для этого библиотеку `transformers`. Советуем, но не заставляем: если хочется, можно взять [fairseq roberta](https://github.com/pytorch/fairseq/blob/main/examples/roberta), [google t5](https://github.com/google-research/text-to-text-transfer-transformer) или даже написать всё с нуля.\n",
|
| 71 |
+
"\n",
|
| 72 |
+
"Мы разбирали transformers на [семинаре](https://lk.yandexdataschool.ru/courses/2025-spring/7.1332-machine-learning-2/classes/13138/), за любой дополнительной информацией - смотрите [документации HF](https://huggingface.co/docs).\n",
|
| 73 |
+
"\n",
|
| 74 |
+
"Начать лучше с простой модели, такой как [`distilbert-base-cased`](https://huggingface.co/distilbert-base-cased). Когда вы будете понимать, какие значения accuracy ожидать от базовой модели, можно поискать что-то получше. Два очевидных направления улучшения: (1) сильнее модель T5 или deberta v3, или (2) близкие данные, например взять модель которую предобучили на том же arxiv. И то и другое удобно [искать здесь](https://huggingface.co/models).\n",
|
| 75 |
+
"\n",
|
| 76 |
+
"## __Научили, и что теперь?__\n",
|
| 77 |
+
"\n",
|
| 78 |
+
"А теперь нужно сделать так, чтобы ваша обученная модель отвечала на запросы в интернете. Как и на прошлом этапе, вы можете сделать это кучей разных способов: от простого [streamlit](https://streamlit.io/) / [gradio](https://gradio.app/), минуя [TorchServe](https://pytorch.org/serve/) с [Triton/TensorRT](https://developer.nvidia.com/nvidia-triton-inference-server), и заканчивая экспортом модели в javascript с помощью [TensorFlow.js](https://www.tensorflow.org/js/tutorials) / [ONNX.js](https://github.com/elliotwaite/pytorch-to-javascript-with-onnx-js).\n",
|
| 79 |
+
"\n",
|
| 80 |
+
"На [семинаре](https://lk.yandexdataschool.ru/courses/2025-spring/7.1332-machine-learning-2/classes/13138/) мы разбирали основные вещи про то как работает streamlit и как сделать простое приложение с его помощью.\n",
|
| 81 |
+
"\n",
|
| 82 |
+
"Общая идея streamlit: вы [описываете](https://docs.streamlit.io/library/get-started/create-an-app) внешний вид приложения на питоне с помощью примитивов (кнопки, поля, любой html) -- а потом этот код выполняется на сервере и обслуживает каждого пользователя в отдельном процессе.\n",
|
| 83 |
+
"\n",
|
| 84 |
+
"__Для отладки__ можно запустить приложение локально, открыв консоль рядом с app.py:\n",
|
| 85 |
+
"* `pip install streamlit`\n",
|
| 86 |
+
"* `streamlit run app.py --server.port 8080`\n",
|
| 87 |
+
"* открыть в браузере localhost:8080, если он не открылся автоматически\n",
|
| 88 |
+
"\n",
|
| 89 |
+
"\n",
|
| 90 |
+
"## __Deployment time!__\n",
|
| 91 |
+
"\n",
|
| 92 |
+
"В этот раз вам нужно не просто написать код, __но и поднять ваше приложение с доступом из интернета__. И да, вы угадали, это можно сделать несколькими способами: [HuggingFace spaces](https://huggingface.co/spaces) (данный способ разбирали на [семинаре](https://lk.yandexdataschool.ru/courses/2025-spring/7.1332-machine-learning-2/classes/13138/)), [Streamlit Cloud](https://streamlit.io/cloud), а ещё вы можете купить или арендовать свой собственный сервер и захоститься там.\n",
|
| 93 |
+
"\n",
|
| 94 |
+
"Проще всего захостить на HF spaces, для этого вам нужно [зарегистрироваться](https://huggingface.co/join) и найти [меню создания нового приложения](https://huggingface.co/new-space). Название и лицензию можно выбрать на своё усмотрение, главное чтобы Space SDK был Streamlit, а доступ - public.\n",
|
| 95 |
+
"\n",
|
| 96 |
+
"Как создали - можно редактировать ваше приложение прямо на сайте, для этого откройте приложение и перейдите в Files and versions, и там в правом углу добавьте нужные файлы.\n",
|
| 97 |
+
"\n",
|
| 98 |
+
"На минималках вам потребуется 2 файла:\n",
|
| 99 |
+
"- `app.py`, о котором мы говорили выше\n",
|
| 100 |
+
"- `requirements.txt`, где вы укажете нужные вам библиотеки\n",
|
| 101 |
+
"\n",
|
| 102 |
+
"Вы можете разместить там же веса вашей обученной модели, любые необходимые данные, дополнительные файлы, ...\n",
|
| 103 |
+
"\n",
|
| 104 |
+
"После каждого изменения файлов, ваше приложение соберётся (обычно 1-5 минут) и будет доступно уже во вкладке App. Ну или не соберётся и покажет вам, где оно сломалось. И вуаля, теперь у вас есть ссылка, которую можно показать ~друзьям~ ассистентам курса и кому угодно в интернете.\n",
|
| 105 |
+
"\n",
|
| 106 |
+
"__Удобная работа с кодом.__ Пока у вас 2 файла, их легко редактивровать прямо в интерфейсе HF spaces. Если же у вас дюжина файлов, вам может быть удобнее редактировать их в любимом vscode/pycharm/.../emacs. Чтобы это не вызывало мучений, можно пользоваться HF spaces как git репозиторием ([подробности тут](https://huggingface.co/docs/hub/spaces#manage-app-with-github-actions)).\n",
|
| 107 |
+
"\n",
|
| 108 |
+
"## __Что нужно сдать__\n",
|
| 109 |
+
"\n",
|
| 110 |
+
"Вы сдаёте проект, который будет проверяться вручную, то что ожидается от каждого проекта:\n",
|
| 111 |
+
"- Текстовое сопровождение вашего конкретного проекта в любом удобно читаемом формате (pdf, html, текст в lk, ...) - что за задачу вы решали, где/как брали данные, какие использовали модели, какие проводили эксперименты, ...\n",
|
| 112 |
+
"- Ссылка на веб интерфейс, где можно протестировать демо вашего проекта - обязательно проверяйте что работает не только у вас (с другого устройства и из под incognito режима)\n",
|
| 113 |
+
"- Код обучения вашей модели (желательно ipynb с заполненными ячейками и не стёртыми выходами, переведённый в pdf / html), но если вы обучали не в ноутбуке, то сдавайте код в виде файла / архива файлов / git ссылки с readme.md описанием того как именно проходило обучение с помощью этого кода.\n",
|
| 114 |
+
"\n",
|
| 115 |
+
"## __Оценка__\n",
|
| 116 |
+
"\n",
|
| 117 |
+
"Мы будем оценивать проект целиком, включая идею и реализацию. Максимум за проект можно получить 10 баллов, но мы оставляем ещё до 5 баллов, котор��е можем выдать как бонусные за особенно интересные и качественно реализованные проекты.\n",
|
| 118 |
+
"\n",
|
| 119 |
+
"### __Тонкие места, за которые могут быть снижения баллов:__\n",
|
| 120 |
+
"\n",
|
| 121 |
+
"__1. Скорость работы.__\n",
|
| 122 |
+
"\n",
|
| 123 |
+
"По умолчанию, streamlit будет выполняет весь ваш код на каждое действие пользователя. То есть всякий раз, когда пользователь меняет что-то в тексте, оно будет заново загружать модель. Чтобы исправить это безобразие, вы можете закэшировать подготовленную модель в `@st.cache`. Подробности в [семинаре](https://lk.yandexdataschool.ru/courses/2025-spring/7.1332-machine-learning-2/classes/13138/), а также [читайте тут](https://docs.streamlit.io/library/advanced-features/caching).\n",
|
| 124 |
+
"\n",
|
| 125 |
+
"__Как будет оцениваться:__\n",
|
| 126 |
+
"\n",
|
| 127 |
+
"Вы не обязаны пользоваться кэшированием, но ваше приложение не должно неоправдано тормозить дольше, чем на 3 секунды. \"Оправданые\" тормоза это те, которые вы явно оправдали текстом в ЛМС :)\n",
|
| 128 |
+
"\n",
|
| 129 |
+
"-----\n",
|
| 130 |
+
"\n",
|
| 131 |
+
"__2. Понятный фронтенд.__\n",
|
| 132 |
+
"\n",
|
| 133 |
+
"Наколеночный графический интерфейс с семинара - пример того, как скорее не надо делать интерфейс приложения. Как надо - сложный вопрос, причём настолько сложный, что есть даже [Школа Разработки Интерфейсов](https://academy.yandex.ru/schools/frontend). Но для начала:\n",
|
| 134 |
+
"\n",
|
| 135 |
+
"- Выводить нужно человекочитаемый текст, а не просто JSON с индексами и метаданными.\n",
|
| 136 |
+
"- Пользователю должно быть понятно, куда и какие данные вводить. Пустые текстовые поля в вакууме - плохой тон.\n",
|
| 137 |
+
"- Сервис не должен падать с не_отловленными ошибками. Даже если пользователь введёт неправильные/пустые данные, нужно это обработать и написать, где произошла ошибка.\n",
|
| 138 |
+
"\n",
|
| 139 |
+
"__Как будет оцениваться:__\n",
|
| 140 |
+
"\n",
|
| 141 |
+
"Для полного балла достаточно соблюсти эти три правила и специально не стрелять себе в ногу.\n",
|
| 142 |
+
"\n",
|
| 143 |
+
"-----\n",
|
| 144 |
+
"\n",
|
| 145 |
+
"__3. Код обучения и инференса.__\n",
|
| 146 |
+
"\n",
|
| 147 |
+
"Сдавая проект мы будем также получать от вас код проекта (как обучения ваших моделей, так и код веб интерфейса).\n",
|
| 148 |
+
"\n",
|
| 149 |
+
"__Как будет оцениваться:__\n",
|
| 150 |
+
"\n",
|
| 151 |
+
"Код не будет отдельно проверяться как часть задания, поэтому пишите как хотите, однако - в спорных ситуациях мы оставляем за собой право проверить ваш код, за чем могут последовать потенциальные снижения баллов при любых нарушениях.\n"
|
| 152 |
+
]
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"cell_type": "markdown",
|
| 156 |
+
"metadata": {},
|
| 157 |
+
"source": []
|
| 158 |
+
}
|
| 159 |
+
],
|
| 160 |
+
"metadata": {
|
| 161 |
+
"language_info": {
|
| 162 |
+
"name": "python"
|
| 163 |
+
}
|
| 164 |
+
},
|
| 165 |
+
"nbformat": 4,
|
| 166 |
+
"nbformat_minor": 2
|
| 167 |
+
}
|
pyproject.toml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[project]
|
| 2 |
+
name = "opinionanalyzer"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
description = "Add your description here"
|
| 5 |
+
readme = "README.md"
|
| 6 |
+
requires-python = ">=3.13"
|
| 7 |
+
dependencies = [
|
| 8 |
+
"accelerate>=1.6.0",
|
| 9 |
+
"datasets>=3.5.0",
|
| 10 |
+
"evaluate>=0.4.3",
|
| 11 |
+
"ipykernel>=6.29.5",
|
| 12 |
+
"scikit-learn>=1.6.1",
|
| 13 |
+
"torch>=2.6.0",
|
| 14 |
+
"transformers>=4.50.3",
|
| 15 |
+
]
|
uv.lock
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|