From e742eaaf380372c24ab720226b0da30b56771549 Mon Sep 17 00:00:00 2001 From: ModelHub XC Date: Sun, 14 Jun 2026 23:21:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=EF=BC=8C=E7=94=B1ModelHub=20XC=E7=A4=BE=E5=8C=BA=E6=8F=90?= =?UTF-8?q?=E4=BE=9B=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model: Vilyam888/Code_analyze.1.0 Source: Original Platform --- .gitattributes | 36 ++ Dataset_CA_1example.json | 543 ++++++++++++++++++++++++++++ README.md | 161 +++++++++ app.py | 187 ++++++++++ chat_template.jinja | 54 +++ config.json | 69 ++++ generation_config.json | 14 + inference.py | 99 +++++ metrics/01_training_perplexity.json | 21 ++ metrics/02_json_validity.json | 37 ++ metrics/03_bleu_rouge.json | 26 ++ metrics/04_code_metrics.json | 7 + metrics/README.md | 37 ++ metrics/evaluation_report.json | 35 ++ metrics/evaluation_report.txt | 33 ++ model.safetensors | 3 + requirements_gradio.txt | 7 + tokenizer.json | 3 + tokenizer_config.json | 29 ++ 19 files changed, 1401 insertions(+) create mode 100644 .gitattributes create mode 100644 Dataset_CA_1example.json create mode 100644 README.md create mode 100644 app.py create mode 100644 chat_template.jinja create mode 100644 config.json create mode 100644 generation_config.json create mode 100644 inference.py create mode 100644 metrics/01_training_perplexity.json create mode 100644 metrics/02_json_validity.json create mode 100644 metrics/03_bleu_rouge.json create mode 100644 metrics/04_code_metrics.json create mode 100644 metrics/README.md create mode 100644 metrics/evaluation_report.json create mode 100644 metrics/evaluation_report.txt create mode 100644 model.safetensors create mode 100644 requirements_gradio.txt create mode 100644 tokenizer.json create mode 100644 tokenizer_config.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..52373fe --- /dev/null +++ b/.gitattributes @@ -0,0 +1,36 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text +tokenizer.json filter=lfs diff=lfs merge=lfs -text diff --git a/Dataset_CA_1example.json b/Dataset_CA_1example.json new file mode 100644 index 0000000..bc4f033 --- /dev/null +++ b/Dataset_CA_1example.json @@ -0,0 +1,543 @@ +{ + "task": { + "id": 1, + "title": "Кластеризация клиентов интернет-магазина", + "description": "Создайте функцию `segment_customers`, которая принимает таблицу признаков клиентов X (возраст, доход, частота покупок, средний чек) и выполняет кластеризацию методом K-Means. Требования: нормализовать данные перед кластеризацией, определить оптимальное количество кластеров (2-10) с помощью метода локтя или силуэта, вернуть обученную модель и визуализировать результаты.", + "difficulty": "medium", + "tags": [ + {"name": "Clustering", "weight": 0.50}, + {"name": "sklearn", "weight": 0.30}, + {"name": "DataPreprocessing", "weight": 0.20} + ] + }, + "solutions": [ + { + "solution": { + "code": "import numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.cluster import KMeans\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.metrics import silhouette_score\n\n\ndef segment_customers(X, k_range=(2, 10)):\n # Нормализация данных\n scaler = StandardScaler()\n X_scaled = scaler.fit_transform(X)\n \n # Подбор оптимального k методом силуэта\n silhouette_scores = []\n K_values = range(k_range[0], k_range[1] + 1)\n \n for k in K_values:\n kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)\n labels = kmeans.fit_predict(X_scaled)\n score = silhouette_score(X_scaled, labels)\n silhouette_scores.append(score)\n \n # Выбор оптимального k\n optimal_k = K_values[np.argmax(silhouette_scores)]\n print(f\"Optimal k: {optimal_k} (silhouette: {max(silhouette_scores):.3f})\")\n \n # Обучение финальной модели\n final_model = KMeans(n_clusters=optimal_k, random_state=42, n_init=10)\n clusters = final_model.fit_predict(X_scaled)\n \n # Визуализация (первые 2 компоненты)\n plt.figure(figsize=(10, 6))\n plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=clusters, cmap='viridis', alpha=0.6)\n plt.scatter(final_model.cluster_centers_[:, 0], \n final_model.cluster_centers_[:, 1], \n c='red', marker='X', s=200, edgecolors='black', label='Centroids')\n plt.title(f'Customer Segmentation (k={optimal_k})')\n plt.xlabel('Feature 1 (scaled)')\n plt.ylabel('Feature 2 (scaled)')\n plt.legend()\n plt.colorbar(label='Cluster')\n plt.show()\n \n return final_model, scaler\n", + "success": true + }, + "analysis": { + "summary": "Отличное решение с полным соответствием требованиям: корректная нормализация данных, автоматический подбор оптимального k методом силуэта, визуализация результатов. Код структурирован и готов к использованию.", + "task_compliance": { + "is_relevant": true, + "score": 9, + "description": "Решение полностью соответствует задаче кластеризации клиентов. Все требования выполнены корректно.", + "tag_alignment": { + "Clustering": { + "required_weight": 0.50, + "applied": true, + "score": 9, + "evidence": "Использован алгоритм K-Means - классический метод кластеризации. Студент правильно применил unsupervised learning подход, выполнил подбор оптимального количества кластеров через метрику silhouette_score, что демонстрирует глубокое понимание задачи сегментации. Центроиды кластеров корректно визуализированы, что позволяет интерпретировать результаты. Использован параметр n_init=10 для множественных инициализаций, что повышает стабильность результатов и защищает от локальных минимумов. Это показывает знание особенностей K-Means алгоритма." + }, + "sklearn": { + "required_weight": 0.30, + "applied": true, + "score": 10, + "evidence": "Продемонстрировано профессиональное владение scikit-learn: правильно использованы KMeans из sklearn.cluster с корректными параметрами (random_state для воспроизводимости, n_init для стабильности), применена метрика silhouette_score из sklearn.metrics для объективной оценки качества кластеризации, использован StandardScaler для нормализации. Код следует best practices библиотеки - раздельное обучение scaler и модели, что позволяет применять их на новых данных. Возвращаются обученные объекты, а не только предсказания." + }, + "DataPreprocessing": { + "required_weight": 0.20, + "applied": true, + "score": 9, + "evidence": "Выполнена обязательная нормализация данных через StandardScaler перед кластеризацией - критически важный шаг для K-Means, так как алгоритм чувствителен к масштабу признаков. Студент понимает, что без нормализации признаки с большим масштабом (например, доход в тысячах) будут доминировать над признаками с малым масштабом (например, частота покупок 1-10), что исказит результаты кластеризации. Использование fit_transform демонстрирует понимание pipeline предобработки. Возврат scaler вместе с моделью позволяет применять ту же трансформацию на новых данных." + } + }, + "missing_requirements": [], + "extra_features": [ + "Автоматический перебор диапазона k для поиска оптимума", + "Использование silhouette метрики - более надежной чем метод локтя", + "Визуализация центроидов кластеров для интерпретации", + "Возврат scaler для применения на новых данных" + ] + }, + "code_quality_score": 9.2, + "correctness": { + "is_correct": true, + "score": 9, + "edge_cases_handled": true + }, + "Временная сложность решения": { + "time_complexity": "O(k * n * d * i * iterations)", + "space_complexity": "O(n * d + k * d)", + "efficiency": "средняя", + "explanation": "где k - диапазон кластеров (2-10), n - количество объектов, d - размерность признаков, i - n_init (10), iterations - количество итераций до сходимости K-Means. Основная сложность в переборе k значений с обучением KMeans на каждом." + }, + "strengths": [ + "Правильная архитектура решения: препроцессинг → подбор гиперпараметров → финальное обучение → визуализация", + "Использование silhouette_score - объективная метрика качества кластеризации, учитывающая компактность и разделимость кластеров", + "Фиксация random_state обеспечивает воспроизводимость результатов", + "Визуализация центроидов помогает в интерпретации и валидации результатов", + "Возврат обученного scaler позволяет корректно трансформировать новые данные" + ], + "weaknesses": [ + "Визуализация использует только первые 2 признака (X_scaled[:, 0] и [:, 1]), что может не отражать полную картину в многомерном пространстве", + "Нет обработки случая одинаковых silhouette scores для разных k", + "Отсутствует проверка на пустые кластеры или выбросы перед кластеризацией", + "Не выводятся размеры полученных кластеров, что важно для анализа сегментации" + ], + "recommendations": [ + "Для визуализации высокоразмерных данных использовать PCA или t-SNE для снижения размерности перед отрисовкой, а не просто первые 2 признака", + "Добавить вывод размеров кластеров: np.bincount(clusters) для проверки баланса сегментов", + "Рассмотреть метод локтя (inertia) вместе с silhouette для более уверенного выбора k", + "Добавить детектирование выбросов через DBSCAN или IsolationForest перед K-Means для улучшения качества", + "Логировать характеристики каждого кластера (средние значения признаков) для бизнес-интерпретации сегментов" + ], + "detailed_analysis": "В решении продемонстрировано глубокое понимание задачи кластеризации и её применения к бизнес-задаче сегментации клиентов. Решение покрывает все ключевые теги: Clustering (50% - правильное применение K-Means с подбором k), sklearn (30% - профессиональное использование библиотеки), DataPreprocessing (20% - обязательная нормализация для K-Means). \n\nОсобо стоит отметить выбор метрики silhouette для определения оптимального k - это более надежный подход чем популярный метод локтя, так как silhouette количественно оценивает качество кластеризации учитывая как компактность кластеров, так и их разделимость. Использование n_init=10 показывает понимание проблемы случайной инициализации K-Means и локальных минимумов.\n\nВозврат как модели, так и scaler - важная деталь для production кода, позволяющая корректно обрабатывать новые данные с той же нормализацией. Визуализация с центроидами помогает в интерпретации результатов, хотя ограничение двумя измерениями может быть недостаточным для полного анализа.\n\nОсновные направления улучшения: использование PCA/t-SNE для корректной визуализации многомерных данных, добавление анализа характеристик каждого сегмента для бизнес-интерпретации, обработка выбросов. В целом - сильное решение уровня Medium с потенциалом применения в реальных проектах." + } + }, + { + "solution": { + "code": "from sklearn.decomposition import PCA\nimport matplotlib.pyplot as plt\n\n\ndef segment_customers(X):\n # Применяем PCA для снижения размерности\n pca = PCA(n_components=2)\n X_reduced = pca.fit_transform(X)\n \n # Визуализация\n plt.figure(figsize=(10, 6))\n plt.scatter(X_reduced[:, 0], X_reduced[:, 1], alpha=0.6)\n plt.title('Customer Data - PCA Projection')\n plt.xlabel('PC1')\n plt.ylabel('PC2')\n plt.show()\n \n print(f\"Explained variance: {pca.explained_variance_ratio_}\")\n return pca\n", + "success": true + }, + "analysis": { + "summary": "Решение использует PCA для снижения размерности, но задача требовала кластеризацию методом K-Means. Это совершенно другая задача - dimensionality reduction вместо clustering.", + "task_compliance": { + "is_relevant": false, + "score": 1, + "description": "Код решает задачу снижения размерности (PCA), а не кластеризации клиентов. Это Фундаментально неправильный подход - задача требовала разделить клиентов на группы (сегменты), а не визуализировать их в 2D пространстве.", + "tag_alignment": { + "Clustering": { + "required_weight": 0.50, + "applied": false, + "score": 0, + "evidence": "НЕ ИСПОЛЬЗОВАНА КЛАСТЕРИЗАЦИЯ! PCA - это метод снижения размерности (DimensionalityReduction), а не кластеризации. Код не создает сегменты клиентов, не присваивает метки кластеров, не ищет группы схожих объектов. Это как если бы вместо группировки студентов по успеваемости просто нарисовали их на графике - задача не решена." + }, + "sklearn": { + "required_weight": 0.30, + "applied": true, + "score": 5, + "evidence": "Формально sklearn используется (PCA из sklearn.decomposition), но применяется неправильный класс. Вместо sklearn.cluster.KMeans использован sklearn.decomposition.PCA - это показывает непонимание различия между задачами supervised/unsupervised learning." + }, + "DataPreprocessing": { + "required_weight": 0.20, + "applied": false, + "score": 2, + "evidence": "Нет нормализации данных перед PCA. Хотя PCA требует нормализации так же как K-Means, она не выполнена. Данные используются напрямую, что может привести к доминированию признаков с большим масштабом." + } + }, + "missing_requirements": [ + "КРИТИЧНО: Отсутствует кластеризация методом K-Means (основное требование задачи - 50% веса)", + "КРИТИЧНО: Нет определения оптимального количества кластеров", + "КРИТИЧНО: Не возвращается модель кластеризации", + "Нет нормализации данных", + "Не используется метод локтя или силуэта" + ], + "wrong_approach": "PCA (dimensionality reduction) вместо K-Means (clustering)" + }, + "code_quality_score": 2.0, + "correctness": { + "is_correct": false, + "score": 1, + "edge_cases_handled": false + }, + "Временная сложность решения": { + "time_complexity": "O(n * d²)", + "space_complexity": "O(d²)", + "efficiency": "высокая", + "explanation": "PCA имеет сложность O(n * d²) где d - количество признаков. Эффективнее чем K-Means, но решает не ту задачу." + }, + "strengths": [ + "Код работает без ошибок и выполняется", + "Визуализация корректно отображает данные в 2D пространстве", + "Выводится explained variance для понимания информативности компонент" + ], + "weaknesses": [ + "КРИТИЧЕСКАЯ ОШИБКА: Решается задача снижения размерности, а не кластеризации - тег Clustering (50% важности) полностью проигнорирован", + "Нет сегментации клиентов на группы - основная цель задачи не достигнута", + "Отсутствует нормализация данных", + "PCA не присваивает кластерные метки и не создает сегменты", + "Невозможно использовать результат для бизнес-задачи (разделение клиентов на группы для маркетинга)" + ], + "recommendations": [ + "ОБЯЗАТЕЛЬНО: Изучить разницу между dimensionality reduction (PCA, t-SNE) и clustering (K-Means, DBSCAN, Hierarchical)", + "ОБЯЗАТЕЛЬНО: Реализовать K-Means кластеризацию как требует задача", + "Понять что PCA можно использовать ДО кластеризации для снижения размерности, но не ВМЕСТО нее", + "После реализации K-Means можно использовать PCA только для визуализации результатов кластеризации" + ], + "detailed_analysis": "Решение демонстрирует фундаментальное непонимание задачи. PCA и K-Means решают разные типы задач: PCA - это unsupervised dimensionality reduction (находит главные компоненты, объясняющие максимальную дисперсию), K-Means - это unsupervised clustering (находит группы схожих объектов). Задача требовала разделить клиентов на сегменты для последующего таргетированного маркетинга, а не просто визуализировать их в 2D.\n\nВАШ КОД РЕШАЕТ ДРУГУЮ ЗАДАЧУ. Необходимо переписать решение с использованием K-Means кластеризации." + } + }, + { + "solution": { + "code": "from sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler\nimport numpy as np\n\n\ndef segment_customers(X, y):\n # Предполагаем что есть целевая переменная\n scaler = StandardScaler()\n X_scaled = scaler.fit_transform(X)\n \n X_train, X_test, y_train, y_test = train_test_split(\n X_scaled, y, test_size=0.2, random_state=42\n )\n \n model = RandomForestClassifier(n_estimators=100, random_state=42)\n model.fit(X_train, y_train)\n \n accuracy = model.score(X_test, y_test)\n print(f\"Accuracy: {accuracy:.3f}\")\n \n return model\n", + "success": true + }, + "analysis": { + "summary": "Решение использует классификацию (supervised learning) вместо кластеризации (unsupervised learning). Это совершенно другой тип задачи - требуется известная целевая переменная y, которой нет в задаче сегментации.", + "task_compliance": { + "is_relevant": false, + "score": 1, + "description": "Код решает задачу supervised classification, а требовалась unsupervised clustering. Задача сегментации клиентов означает что нет известных меток - нужно найти естественные группы в данных.", + "tag_alignment": { + "Clustering": { + "required_weight": 0.50, + "applied": false, + "score": 0, + "evidence": "ФУНДАМЕНТАЛЬНАЯ ОШИБКА: Использован RandomForestClassifier - это supervised learning алгоритм для классификации, который требует известные метки классов (y). Кластеризация - это unsupervised learning, где метки НЕИЗВЕСТНЫ и их нужно найти. В задаче сегментации клиентов нет заранее известных групп - нужно автоматически их обнаружить. Это как разница между 'распределить студентов по заранее известным классам A/B/C' (classification) и 'найти естественные группы студентов по их характеристикам' (clustering)." + }, + "sklearn": { + "required_weight": 0.30, + "applied": true, + "score": 4, + "evidence": "sklearn формально используется (RandomForestClassifier, StandardScaler, train_test_split), но выбран совершенно неподходящий модуль. Вместо sklearn.cluster использован sklearn.ensemble - это показывает путаницу между типами задач machine learning. train_test_split вообще не нужен для кластеризации, так как нет целевой переменной." + }, + "DataPreprocessing": { + "required_weight": 0.20, + "applied": true, + "score": 6, + "evidence": "Нормализация через StandardScaler выполнена корректно - это единственная правильная часть решения. Однако контекст использования неверный - данные подготовлены для классификации вместо кластеризации." + } + }, + "missing_requirements": [ + "КРИТИЧНО: Использован supervised learning вместо unsupervised (тип задачи неправильный)", + "КРИТИЧНО: Требуется несуществующая целевая переменная y", + "КРИТИЧНО: Отсутствует K-Means кластеризация", + "Нет определения оптимального количества кластеров", + "Нет визуализации результатов кластеризации" + ], + "wrong_approach": "RandomForestClassifier (supervised classification) вместо K-Means (unsupervised clustering)" + }, + "code_quality_score": 2.5, + "correctness": { + "is_correct": false, + "score": 1, + "edge_cases_handled": false + }, + "Временная сложность решения": { + "time_complexity": "O(T * n * log(n) * d)", + "space_complexity": "O(T * n)", + "efficiency": "низкая", + "explanation": "где T - количество деревьев (100), n - объекты, d - признаки. RandomForest медленнее K-Means, но это не важно так как решается не та задача." + }, + "strengths": [ + "Код технически грамотный для задачи классификации", + "Правильно использованы train_test_split и оценка качества", + "Нормализация данных выполнена корректно" + ], + "weaknesses": [ + "КРИТИЧЕСКАЯ ОШИБКА: Перепутаны supervised и unsupervised learning - тег Clustering (50% важности) полностью проигнорирован", + "Требуется целевая переменная y, которая не существует в задаче сегментации", + "Невозможно выполнить код так как функция принимает только X, а используется y", + "Train/test split бессмысленен для кластеризации", + "Результат непригоден для бизнес-задачи - нельзя сегментировать новых клиентов без известных меток" + ], + "recommendations": [ + "ОБЯЗАТЕЛЬНО: Изучить разницу между supervised learning (classification/regression с известными метками) и unsupervised learning (clustering без меток)", + "ОБЯЗАТЕЛЬНО: Реализовать K-Means из sklearn.cluster вместо RandomForestClassifier", + "Понять что в сегментации клиентов нет заранее известных групп - их нужно обнаружить алгоритмом", + "Убрать train_test_split - для кластеризации используется весь датасет целиком" + ], + "detailed_analysis": "Решение демонстрирует критическое непонимание типов задач machine learning. Supervised learning (классификация, регрессия) требует обучающие данные с известными ответами (X, y) и учится предсказывать y для новых X. Unsupervised learning (кластеризация, снижение размерности) работает только с X и ищет скрытые паттерны/структуры в данных без известных меток.\n\nЗадача сегментации клиентов - это классический пример unsupervised learning: у компании есть данные о клиентах (возраст, доход, покупки), но нет готовых групп. Нужно автоматически найти естественные сегменты (например, 'молодые активные', 'богатые редкие', 'средний класс частые' и т.д.).\n\nВАШ КОД РЕШАЕТ ДРУГУЮ ЗАДАЧУ. RandomForestClassifier требует известные метки классов, которых нет в сегментации. Необходимо переписать с K-Means." + } + }, + { + "solution": { + "code": "from sklearn.cluster import KMeans\nimport matplotlib.pyplot as plt\n\n\ndef segment_customers(X):\n # Попытка кластеризации без нормализации\n model = KMeans(n_clusters=3)\n # Ошибка: забыл вызвать fit\n clusters = model.predict(X)\n \n plt.scatter(X[:, 0], X[:, 1], c=clusters)\n plt.show()\n \n return model\n", + "success": false + }, + "analysis": { + "summary": "Код содержит критическую ошибку - вызов predict до fit. KMeans модель не обучена, что приведет к исключению NotFittedError. Также отсутствуют нормализация и подбор оптимального k.", + "task_compliance": { + "is_relevant": true, + "score": 3, + "description": "Намерение решить задачу кластеризации правильное (используется KMeans), но реализация нерабочая из-за логической ошибки.", + "tag_alignment": { + "Clustering": { + "required_weight": 0.50, + "applied": "partially", + "score": 3, + "evidence": "Использован правильный алгоритм K-Means для кластеризации, но с критической ошибкой в последовательности операций. В sklearn любая модель требует сначала обучения (fit), затем предсказания (predict). Вызов predict до fit приведет к ошибке: 'NotFittedError: This KMeans instance is not fitted yet'. Также количество кластеров k=3 захардкожено без обоснования, не выполнен подбор оптимального k методом локтя или силуэта как требовалось в задаче." + }, + "sklearn": { + "required_weight": 0.30, + "applied": "partially", + "score": 2, + "evidence": "Демонстрируется непонимание базового workflow sklearn: fit → predict. Это фундаментальная концепция библиотеки, применимая ко всем алгоритмам. Правильная последовательность: model.fit(X) для обучения, затем model.predict(X_new) для новых данных или model.fit_predict(X) для обучения и получения меток одновременно. Такая ошибка показывает недостаточное знакомство с библиотекой." + }, + "DataPreprocessing": { + "required_weight": 0.20, + "applied": false, + "score": 0, + "evidence": "Полностью отсутствует нормализация данных - обязательное требование задачи и критически важный шаг для K-Means. Без StandardScaler признаки с большим масштабом (доход 20000-100000) будут доминировать над признаками с малым масштабом (возраст 18-65, частота покупок 1-20). Это приведет к искаженной кластеризации, где расстояния будут определяться в основном доходом, а остальные признаки игнорироваться." + } + }, + "missing_requirements": [ + "КРИТИЧНО: Нет вызова fit перед predict - код выдаст ошибку", + "КРИТИЧНО: Отсутствует нормализация данных (требование задачи)", + "Нет определения оптимального k - значение 3 захардкожено", + "Не используется метод локтя или силуэта", + "Визуализация примитивная - нет центроидов, подписей, легенды" + ], + "extra_features": [] + }, + "code_quality_score": 1.8, + "correctness": { + "is_correct": false, + "score": 1, + "edge_cases_handled": false + }, + "Временная сложность решения": { + "time_complexity": "N/A", + "space_complexity": "N/A", + "efficiency": "N/A", + "explanation": "Код не выполнится из-за ошибки, поэтому сложность неприменима." + }, + "strengths": [ + "Выбран правильный алгоритм K-Means для задачи кластеризации", + "Присутствует визуализация результатов (хоть и простая)" + ], + "weaknesses": [ + "КРИТИЧЕСКАЯ ОШИБКА: Вызов predict до fit - код не работает, выдаст NotFittedError", + "Отсутствует обязательная нормализация данных - тег DataPreprocessing (20% важности) полностью проигнорирован", + "Hardcoded значение k=3 без обоснования и подбора оптимального значения", + "Нет использования методов локтя или силуэта как требовала задача", + "Визуализация использует только 2 признака, нет подписей осей и легенды", + "Не возвращается scaler (хотя его и нет)" + ], + "recommendations": [ + "ОБЯЗАТЕЛЬНО: Изучить базовый workflow sklearn - fit обучает модель, predict делает предсказания на обученной модели", + "ОБЯЗАТЕЛЬНО: Добавить StandardScaler для нормализации данных перед кластеризацией", + "Использовать fit_predict(X) для одновременного обучения и получения меток, или сначала fit(X), затем predict(X)", + "Реализовать подбор оптимального k через цикл с метрикой silhouette_score", + "Улучшить визуализацию: добавить центроиды, подписи, colorbar" + ], + "detailed_analysis": "Решение показывает начальное понимание задачи (выбран K-Means), но содержит критические ошибки реализации. Главная проблема - непонимание последовательности fit → predict в sklearn, что является базовой концепцией библиотеки. При попытке выполнить код произойдет ошибка: sklearn.exceptions.NotFittedError.\n\nВторая серьезная проблема - полное отсутствие нормализации данных, что нарушает требование задачи (тег DataPreprocessing 20%) и приведет к некорректным результатам даже если исправить ошибку с fit. K-Means вычисляет Euclidean расстояния, которые чувствительны к масштабу признаков.\n\nТретья проблема - захардкоженное k=3 без какого-либо обоснования. Задача явно требовала определить оптимальное количество кластеров в диапазоне 2-10 используя метод локтя или силуэта.\n\nРекомендуется изучить основы sklearn и пересмотреть требования задачи перед новой попыткой реализации." + } + }, + { + "solution": { + "code": "from sklearn.cluster import KMeans\n\n\ndef segment_customers(X):\n # Кластеризация без нормализации и подбора k\n model = KMeans(n_clusters=4, random_state=42)\n clusters = model.fit_predict(X)\n \n print(f\"Clusters assigned: {len(set(clusters))}\")\n return model\n", + "success": true + }, + "analysis": { + "summary": "Минималистичное рабочее решение: использован K-Means, код выполняется, но отсутствуют ключевые требования - нет нормализации данных, подбора оптимального k и визуализации. Это baseline решение с минимальным функционалом.", + "task_compliance": { + "is_relevant": true, + "score": 4, + "description": "Решение частично соответствует задаче - выполнена базовая кластеризация, но пропущены важные требования (нормализация, подбор k, визуализация).", + "tag_alignment": { + "Clustering": { + "required_weight": 0.50, + "applied": true, + "score": 5, + "evidence": "K-Means использован корректно - применен нужный алгоритм, модель обучена через fit_predict, возвращается обученный объект. Однако реализация минималистична: количество кластеров k=4 выбрано произвольно без обоснования и без использования методов локтя или силуэта как требовала задача. Отсутствует анализ качества кластеризации (silhouette score, inertia). Нет проверки результатов и интерпретации полученных сегментов. Это базовый уровень - алгоритм применен, но без понимания оптимальности решения." + }, + "sklearn": { + "required_weight": 0.30, + "applied": true, + "score": 6, + "evidence": "sklearn.cluster.KMeans использован правильно: корректный импорт, правильный метод fit_predict (обучение + предсказание за один вызов), установлен random_state для воспроизводимости. Однако использование библиотеки поверхностное - не применены другие важные модули sklearn (StandardScaler для preprocessing, silhouette_score для оценки качества). Демонстрируется знание базового API, но не best practices библиотеки." + }, + "DataPreprocessing": { + "required_weight": 0.20, + "applied": false, + "score": 0, + "evidence": "КРИТИЧЕСКИЙ НЕДОЧЕТ: Полностью отсутствует нормализация данных - это было явным требованием задачи. K-Means чувствителен к масштабу признаков, поэтому без StandardScaler результаты будут искажены. Признаки с большими значениями (доход в десятках тысяч) будут доминировать над признаками с малыми значениями (возраст, частота покупок), что приведет к неправильной сегментации клиентов. Это базовая ошибка, показывающая пробел в понимании preprocessing." + } + }, + "missing_requirements": [ + "КРИТИЧНО: Отсутствует нормализация данных (явное требование задачи)", + "Нет определения оптимального количества кластеров - k=4 выбрано произвольно", + "Не использованы методы локтя или силуэта", + "Отсутствует визуализация результатов (требование задачи)", + "Не возвращается scaler для применения на новых данных" + ], + "extra_features": [] + }, + "code_quality_score": 4.2, + "correctness": { + "is_correct": "partially", + "score": 4, + "edge_cases_handled": false + }, + "Временная сложность решения": { + "time_complexity": "O(n * k * d * iterations)", + "space_complexity": "O(n * d + k * d)", + "efficiency": "средняя", + "explanation": "где n - количество объектов, k=4 кластера, d - признаки, iterations - итерации до сходимости. Стандартная сложность K-Means." + }, + "strengths": [ + "Код работает без ошибок и выполняет базовую кластеризацию", + "Использован правильный метод fit_predict для обучения и получения меток", + "Установлен random_state для воспроизводимости результатов", + "Возвращается обученная модель" + ], + "weaknesses": [ + "КРИТИЧЕСКИЙ НЕДОЧЕТ: Нет нормализации данных - тег DataPreprocessing (20% важности) полностью проигнорирован, нарушено требование задачи", + "Количество кластеров k=4 выбрано наугад без использования методов локтя/силуэта (требование задачи)", + "Отсутствует визуализация результатов (требование задачи)", + "Нет оценки качества кластеризации (silhouette score, inertia)", + "Невозможно интерпретировать полученные сегменты - не выводятся характеристики кластеров", + "Решение не production-ready: нельзя применить к новым клиентам (нет сохраненного scaler)" + ], + "recommendations": [ + "ОБЯЗАТЕЛЬНО: Добавить StandardScaler для нормализации данных перед кластеризацией - это ключевое требование", + "Реализовать подбор оптимального k: цикл по range(2, 11) с вычислением silhouette_score или inertia", + "Добавить визуализацию результатов с центроидами кластеров", + "Вывести характеристики каждого сегмента (средние значения признаков) для бизнес-интерпретации", + "Сохранять и возвращать scaler вместе с моделью для обработки новых данных" + ], + "detailed_analysis": "Решение представляет собой минимальную рабочую реализацию K-Means - код выполняется и технически производит кластеризацию, но игнорирует большинство требований задачи. Основные проблемы:\n\n1. **Отсутствие нормализации (критично)**: Тег DataPreprocessing составляет 20% важности задачи и был явным требованием. Без нормализации K-Means будет работать некорректно - признаки с большим масштабом (например, доход 20000-100000) будут доминировать над признаками с малым масштабом (возраст 18-70, частота покупок 1-50). Результат - кластеризация в основном по доходу, игнорируя остальные характеристики клиентов.\n\n2. **Произвольное k=4**: Задача требовала найти оптимальное количество кластеров в диапазоне 2-10 используя метод локтя или силуэта. Значение 4 выбрано без обоснования, что может привести к недо-сегментации (слишком крупные группы) или пере-сегментации (слишком мелкие).\n\n3. **Нет визуализации**: Требование задачи - визуализировать результаты для интерпретации и валидации сегментации.\n\nЭто типичное 'сделал на скорую руку' решение - минимальный код для галочки, без внимания к требованиям и качеству. Для практического применения необходима полная переработка с учетом всех требований." + } + }, + { + "solution": { + "code": "from sklearn.cluster import KMeans\nfrom sklearn.preprocessing import StandardScaler\nimport matplotlib.pyplot as plt\n\n\ndef segment_customers(X):\n # Нормализация\n scaler = StandardScaler()\n X_scaled = scaler.fit_transform(X)\n \n # Фиксированное k без подбора\n model = KMeans(n_clusters=5, random_state=42)\n clusters = model.fit_predict(X_scaled)\n \n # Простая визуализация\n plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=clusters, cmap='viridis')\n plt.title('Customer Segments')\n plt.show()\n \n return model, scaler\n", + "success": true + }, + "analysis": { + "summary": "Рабочее решение среднего качества: есть нормализация, визуализация, возврат модели и scaler. Но отсутствует автоматический подбор оптимального количества кластеров - ключевое требование задачи.", + "task_compliance": { + "is_relevant": true, + "score": 6, + "description": "Решение соответствует большинству требований, но упущен важный аспект - определение оптимального k методом локтя или силуэта.", + "tag_alignment": { + "Clustering": { + "required_weight": 0.50, + "applied": true, + "score": 6, + "evidence": "K-Means применен корректно с правильными параметрами (random_state для воспроизводимости). Модель обучена на нормализованных данных, что правильно. Однако критическое упущение - количество кластеров k=5 выбрано произвольно, а задача явно требовала 'определить оптимальное количество кластеров (2-10) с помощью метода локтя или силуэта'. Это не просто рекомендация, а ключевое требование, показывающее понимание того, что k - это гиперпараметр требующий настройки. Отсутствие подбора k снижает практическую ценность решения - нет уверенности что 5 сегментов оптимально для данных." + }, + "sklearn": { + "required_weight": 0.30, + "applied": true, + "score": 7, + "evidence": "Демонстрируется хорошее знание sklearn: правильно использованы KMeans и StandardScaler, понимание необходимости fit_transform для scaler, возврат обученных объектов для применения на новых данных. Однако не использованы метрики качества (silhouette_score, calinski_harabasz_score) из sklearn.metrics, которые необходимы для определения оптимального k. Код следует базовым практикам библиотеки, но не использует её полные возможности для решения задачи." + }, + "DataPreprocessing": { + "required_weight": 0.20, + "applied": true, + "score": 8, + "evidence": "Нормализация через StandardScaler выполнена корректно - это обязательное требование задачи. Использован правильный метод fit_transform для обучения scaler на данных и трансформации одновременно. Scaler возвращается вместе с моделью, что позволяет применять ту же нормализацию на новых клиентах - правильный подход для production. Единственное замечание - нет проверки на пропущенные значения или выбросы перед нормализацией, но это minor недочет." + } + }, + "missing_requirements": [ + "Нет определения оптимального k - значение 5 выбрано без обоснования", + "Не использованы методы локтя или силуэта (явное требование задачи)", + "Визуализация упрощенная - нет центроидов кластеров", + "Не выводится метрика качества кластеризации" + ], + "extra_features": [ + "Возврат scaler для применения на новых данных" + ] + }, + "code_quality_score": 6.8, + "correctness": { + "is_correct": true, + "score": 7, + "edge_cases_handled": "partially" + }, + "Временная сложность решения": { + "time_complexity": "O(n * k * d * iterations)", + "space_complexity": "O(n * d + k * d)", + "efficiency": "средняя", + "explanation": "где n - объекты, k=5 кластеров, d - признаки, iterations - итерации сходимости K-Means. Стандартная сложность одного прогона K-Means." + }, + "strengths": [ + "Выполнена обязательная нормализация данных через StandardScaler", + "Правильная последовательность: preprocessing → clustering → visualization", + "Возврат как модели, так и scaler - важно для применения на новых данных", + "Использован random_state для воспроизводимости", + "Код чистый, читаемый, без ошибок" + ], + "weaknesses": [ + "Отсутствует подбор оптимального k - ключевое требование задачи (тег Clustering 50%) не полностью выполнено", + "k=5 выбрано произвольно без использования метода локтя или силуэта", + "Нет вывода метрик качества (silhouette score) для оценки кластеризации", + "Визуализация базовая - нет центроидов, которые важны для интерпретации сегментов", + "Не выводятся характеристики кластеров (размеры, средние значения признаков)" + ], + "recommendations": [ + "Добавить цикл по k в range(2, 11) с вычислением silhouette_score для каждого k", + "Выбирать оптимальное k как argmax(silhouette_scores) или по методу локтя (elbow на inertia)", + "Визуализировать центроиды кластеров для лучшей интерпретации сегментов", + "Вывести silhouette score финальной модели для оценки качества разделения", + "Добавить анализ размеров кластеров (np.bincount) для проверки сбалансированности сегментов" + ], + "detailed_analysis": "Решение демонстрирует понимание основных аспектов задачи кластеризации и правильную реализацию большинства требований. Положительные моменты: корректная нормализация данных (тег DataPreprocessing 20% полностью покрыт), правильное использование sklearn (тег sklearn 30% хорошо покрыт), возврат обученных объектов для production использования.\n\nОднако упущен важный аспект задачи - определение оптимального количества кластеров. Задача явно требовала: 'определить оптимальное количество кластеров (2-10) с помощью метода локтя или силуэта'. Это не опциональная рекомендация, а ключевое требование, показывающее понимание что k - это гиперпараметр, требующий настройки. Выбор k=5 наугад может привести к субоптимальной сегментации.\n\nМетоды определения k:\n- **Метод локтя (elbow)**: график inertia vs k, ищем 'локоть' где улучшение замедляется\n- **Silhouette analysis**: выбираем k с максимальным silhouette score (мера качества кластеризации от -1 до 1)\n\nВизуализация присутствует, но упрощенная - нет центроидов кластеров, которые важны для интерпретации: 'кластер 1 - молодые с низким доходом', 'кластер 2 - состоятельные редкие покупатели' и т.д.\n\nВ целом это решение уровня 6-7/10 - работает, покрывает большинство требований, но упускает ключевой аспект автоматического подбора гиперпараметров. Для полноценного соответствия задаче необходимо добавить подбор оптимального k." + } + }, + { + "solution": { + "code": "from sklearn.cluster import DBSCAN\nfrom sklearn.preprocessing import StandardScaler\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\ndef segment_customers(X, eps=0.5, min_samples=5):\n # Нормализация\n scaler = StandardScaler()\n X_scaled = scaler.fit_transform(X)\n \n # DBSCAN вместо K-Means\n model = DBSCAN(eps=eps, min_samples=min_samples)\n clusters = model.fit_predict(X_scaled)\n \n n_clusters = len(set(clusters)) - (1 if -1 in clusters else 0)\n n_noise = list(clusters).count(-1)\n \n print(f\"Кластеров найдено: {n_clusters}\")\n print(f\"Выбросов: {n_noise}\")\n \n # Визуализация\n plt.figure(figsize=(10, 6))\n plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=clusters, cmap='viridis', alpha=0.6)\n plt.title(f'DBSCAN Clustering (clusters: {n_clusters})')\n plt.colorbar(label='Cluster')\n plt.show()\n \n return model, scaler\n", + "success": true + }, + "analysis": { + "summary": "Решение использует DBSCAN - другой алгоритм кластеризации, чем требовалось. Задача явно требовала K-Means, но реализован density-based подход. Это хорошее решение для другой задачи, но не соответствует требованиям.", + "task_compliance": { + "is_relevant": "partially", + "score": 5, + "description": "Решение выполняет кластеризацию и покрывает некоторые требования (нормализация, визуализация), но использует неправильный алгоритм. Задача требовала K-Means, а реализован DBSCAN.", + "tag_alignment": { + "Clustering": { + "required_weight": 0.50, + "applied": true, + "score": 5, + "evidence": "Выполнена кластеризация, но использован DBSCAN вместо требуемого K-Means. Это разные подходы: K-Means - partition-based (делит данные на k групп), DBSCAN - density-based (находит области высокой плотности). Задача явно указывала 'выполняет кластеризацию методом K-Means' - это не рекомендация, а требование. DBSCAN имеет преимущества (находит выбросы, не требует указывать k заранее), но в данном случае студент должен был продемонстрировать знание именно K-Means. Также отсутствует ключевое требование - определение оптимального k в диапазоне 2-10, которое неприменимо к DBSCAN." + }, + "sklearn": { + "required_weight": 0.30, + "applied": true, + "score": 8, + "evidence": "Хорошее владение sklearn продемонстрировано: корректное использование DBSCAN из sklearn.cluster, правильная работа со StandardScaler, понимание особенностей DBSCAN (метки -1 для выбросов). Код следует практикам библиотеки, возвращаются обученные объекты. Однако выбран неподходящий класс - нужен был KMeans, а не DBSCAN. Это показывает знание sklearn, но непонимание или игнорирование требований задачи." + }, + "DataPreprocessing": { + "required_weight": 0.20, + "applied": true, + "score": 9, + "evidence": "Нормализация выполнена корректно через StandardScaler - это обязательное требование задачи полностью соблюдено. Использован правильный подход с fit_transform, scaler возвращается для применения на новых данных. DBSCAN также требует нормализации (чувствителен к масштабу при вычислении eps-окрестностей), поэтому предобработка выполнена правильно для выбранного алгоритма." + } + }, + "missing_requirements": [ + "ВАЖНО: Использован DBSCAN вместо требуемого K-Means", + "Невозможно определить оптимальное k (2-10) - DBSCAN сам определяет количество кластеров", + "Не применены методы локтя или силуэта (они специфичны для K-Means)", + "Нет визуализации центроидов (у DBSCAN нет концепции центроидов)" + ], + "extra_features": [ + "Автоматическое определение количества кластеров", + "Детектирование выбросов (шумовые точки)", + "Вывод статистики по кластерам и выбросам" + ] + }, + "code_quality_score": 7.5, + "correctness": { + "is_correct": "partially", + "score": 5, + "edge_cases_handled": true + }, + "Временная сложность решения": { + "time_complexity": "O(n²) или O(n log n) с индексацией", + "space_complexity": "O(n²) или O(n) с индексацией", + "efficiency": "низкая-средняя", + "explanation": "DBSCAN имеет сложность O(n²) в naive реализации, O(n log n) с пространственными индексами (KD-tree). Медленнее чем K-Means." + }, + "strengths": [ + "Код качественный и работает без ошибок", + "Правильная нормализация данных через StandardScaler", + "DBSCAN хорошо реализован - обработка выбросов, вывод статистики", + "Визуализация информативная с подписями", + "Возврат модели и scaler для применения на новых данных", + "Автоматическое определение количества кластеров (преимущество DBSCAN)" + ], + "weaknesses": [ + "КЛЮЧЕВАЯ ПРОБЛЕМА: Использован DBSCAN вместо K-Means - требование задачи не выполнено", + "Невозможно продемонстрировать навык определения оптимального k методом локтя/силуэта", + "Параметры eps и min_samples выбраны произвольно (0.5 и 5) без настройки", + "DBSCAN может найти любое количество кластеров, не обязательно в диапазоне 2-10 как требовалось", + "Результаты кластеризации могут сильно отличаться от K-Means" + ], + "recommendations": [ + "ОБЯЗАТЕЛЬНО: Заменить DBSCAN на KMeans для соответствия требованиям задачи", + "Реализовать подбор оптимального k в диапазоне 2-10 методом силуэта или локтя", + "DBSCAN можно использовать как дополнительный анализ ПОСЛЕ выполнения основной задачи с K-Means", + "Если хотите использовать DBSCAN, подберите оптимальные eps и min_samples (например, через k-distance graph)", + "Внимательно читать требования задачи - 'метод K-Means' это конкретное указание, а не предложение" + ], + "detailed_analysis": "Решение демонстрирует хорошее знание алгоритмов кластеризации и качественную реализацию, но страдает от критической проблемы - несоответствия требованиям. Задача явно указывала 'выполняет кластеризацию методом K-Means' и 'определить оптимальное количество кластеров (2-10)', что специфично для K-Means подхода.\n\nDBSCAN (Density-Based Spatial Clustering of Applications with Noise) - это другой тип алгоритма:\n- **K-Means**: partition-based, требует указать k заранее, присваивает все точки кластерам, ищет центроиды\n- **DBSCAN**: density-based, автоматически определяет количество кластеров, может маркировать точки как выбросы, находит области высокой плотности\n\nDBSCAN имеет преимущества (находит кластеры произвольной формы, устойчив к выбросам), но в образовательном контексте важно продемонстрировать знание именно того алгоритма, который требуется. Использование DBSCAN показывает широкий кругозор, но также игнорирование конкретных требований.\n\nАналогия: если на экзамене по физике требуется решить задачу законом Ньютона, а студент использует лагранжев формализм - технически правильно и даже более продвинуто, но требование не выполнено.\n\nРекомендация: реализовать K-Means как требует задача, а DBSCAN можно использовать как дополнительный сравнительный анализ. Это продемонстрирует и выполнение требований, и широту знаний." + } + } + ] + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4624407 --- /dev/null +++ b/README.md @@ -0,0 +1,161 @@ +--- +library_name: transformers +license: apache-2.0 +base_model: Qwen/Qwen2.5-Coder-3B-Instruct +pipeline_tag: text-generation +inference: true +tags: +- code +- code-analysis +- qwen +- qwen2 +- text-generation +- transformers +- fine-tuned +widget: +- text: "Задача:\nНапишите функцию, которая принимает список чисел и возвращает сумму всех элементов.\n\nРешение (код):\n```python\ndef sum_list(numbers):\n total = 0\n for num in numbers:\n total += num\n return total\n```\n\nОтвет:\n" + example_title: "Анализ кода - сумма списка" +- text: "Задача:\nСоздайте функцию для вычисления факториала числа.\n\nРешение (код):\n```python\ndef factorial(n):\n if n <= 1:\n return 1\n return n * factorial(n-1)\n```\n\nОтвет:\n" + example_title: "Анализ кода - факториал" +--- + +# Code Analyzer Model + +Fine-tuned версия модели Qwen2.5-Coder-3B-Instruct для анализа кода студента на основе условия задачи (for Machine Learning tasks). + +## Описание модели + +Эта модель предназнаечена для анализа кода студента. Модель принимает: +- **Условие задачи** (текстовое описание) +- **Код решения студента** (Python код) + +И возвращает детальный анализ в формате JSON, включающий: +- Оценку правильности решения +- Анализ соответствия требованиям задачи +- Оценку качества кода +- Сильные и слабые стороны решения +- Рекомендации по улучшению +- Детальный анализ с обоснованием + +Модель основана на Qwen2.5-Coder-3B-Instruct и дообучена с использованием LoRA (Low-Rank Adaptation). + +## Быстрый старт + +### Вариант 1: Использование локально (Python) + +**Установка зависимостей:** +```bash +pip install transformers torch +``` + +**Простой пример использования:** +```python +from transformers import AutoModelForCausalLM, AutoTokenizer +import torch +import json + +model_name = "Vilyam888/Code_analyze.1.0" + +# Загрузка модели +tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) +model = AutoModelForCausalLM.from_pretrained( + model_name, + torch_dtype=torch.bfloat16, + device_map="auto", + trust_remote_code=True +) + +# Условие задачи +task = "Напишите функцию, которая принимает список чисел и возвращает сумму всех элементов." + +# Код студента +code = """def sum_list(numbers): + total = 0 + for num in numbers: + total += num + return total""" + +# Форматирование входа +input_text = f"Задача:\n{task}\n\nРешение (код):\n```python\n{code}\n```" +prompt = f"{input_text}\n\nОтвет:\n" + +# Генерация анализа +inputs = tokenizer(prompt, return_tensors="pt").to(model.device) +with torch.no_grad(): + outputs = model.generate( + **inputs, + max_new_tokens=1024, + temperature=0.7, + top_p=0.8, + top_k=20, + repetition_penalty=1.05, + do_sample=True + ) + +# Декодирование и парсинг JSON +response = tokenizer.decode(outputs[0], skip_special_tokens=True) +result = response.split("Ответ:")[-1].strip() +analysis = json.loads(result) + +print(json.dumps(analysis, ensure_ascii=False, indent=2)) +``` + +**Или используйте готовые скрипты из репозитория:** + +Простой пример (минимальный код): +```bash +python scripts/quick_start_example.py +``` + +Полный пример с интерактивным режимом: +```bash +python scripts/use_model_example.py +``` + + +## Детали обучения + +- **Базовая модель:** Qwen/Qwen2.5-Coder-3B-Instruct +- **Метод обучения:** LoRA (Low-Rank Adaptation) +- **Параметры LoRA:** + - `r`: 16 + - `lora_alpha`: 32 + - `lora_dropout`: 0.05 +- **Фреймворк:** TRL (Transformer Reinforcement Learning) +- **Формат данных:** JSONL с полями `input` и `output` + +## Ограничения + +- Модель обучена на русском языке для анализа кода +- Может генерировать неточные или неполные ответы +- Требует GPU для эффективной работы + +## Использование через API + +Модель можно использовать через несколько способов: + +### 1. Через transformers (Python) +```python +from transformers import AutoModelForCausalLM, AutoTokenizer +``` + +### 2. Через Hugging Face Inference API +```python +import requests +API_URL = "https://api-inference.huggingface.co/models/Vilyam888/Code_analyze.1.0" +``` + +### 3. Через Gradio Space API +Если создан Gradio Space, можно использовать его API endpoint. + +### 4. Интеграция в Backend проект +Примеры для FastAPI, Flask, Django, Node.js и других фреймворков. + + +## Лицензия + +Apache 2.0 + +## Авторы + +Fine-tuned by Vilyam888 diff --git a/app.py b/app.py new file mode 100644 index 0000000..66e97e0 --- /dev/null +++ b/app.py @@ -0,0 +1,187 @@ +""" +Gradio Space для интерактивного использования модели Code Analyzer +Модель анализирует код студента на основе условия задачи +Поддерживает как веб-интерфейс, так и API endpoint +""" +import gradio as gr +from transformers import AutoModelForCausalLM, AutoTokenizer +import torch +import json +from pydantic import BaseModel +from typing import Optional + +# Загрузка модели (будет выполнена при первом запуске) +MODEL_NAME = "Vilyam888/Code_analyze.1.0" + +def load_model(): + """Загружает модель один раз при старте и сохраняет в глобальные переменные""" + global model, tokenizer + + if model is None or tokenizer is None: + print("Загрузка модели...") + tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True) + model = AutoModelForCausalLM.from_pretrained( + MODEL_NAME, + torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32, + device_map="auto", + trust_remote_code=True + ) + print("Модель загружена успешно!") + +# Глобальные переменные для модели +model, tokenizer = None, None + +def build_input(task, code): + """Форматирует вход в том же формате, что использовался при обучении""" + parts = [] + if task.strip(): + parts.append(f"Задача:\n{task.strip()}") + if code.strip(): + parts.append(f"Решение (код):\n```python\n{code.strip()}\n```") + return "\n\n".join(parts) + +def analyze_code(task, code): + """Анализирует код студента и возвращает результат в формате JSON""" + global model, tokenizer + + if model is None or tokenizer is None: + return "⏳ Загрузка модели... Пожалуйста, подождите." + + if not task.strip(): + return "❌ Пожалуйста, введите условие задачи." + + if not code.strip(): + return "❌ Пожалуйста, введите код решения студента." + + try: + # Форматирование входа в стиле обучения + input_text = build_input(task, code) + prompt = f"{input_text}\n\nОтвет:\n" + + # Токенизация + inputs = tokenizer(prompt, return_tensors="pt").to(model.device) + + # Генерация ответа + with torch.no_grad(): + outputs = model.generate( + **inputs, + max_new_tokens=600, # Оптимизировано для CPU + temperature=0.7, + top_p=0.85, + top_k=20, + repetition_penalty=1.05, + do_sample=True, + pad_token_id=tokenizer.eos_token_id, + eos_token_id=tokenizer.eos_token_id + ) + + # Декодирование ответа + response = tokenizer.decode(outputs[0], skip_special_tokens=True) + + # Извлечение JSON ответа + if "Ответ:" in response: + json_str = response.split("Ответ:")[-1].strip() + else: + json_str = response + + # Попытка распарсить JSON + try: + result = json.loads(json_str) + # Форматируем JSON для красивого отображения + return json.dumps(result, ensure_ascii=False, indent=2) + except json.JSONDecodeError: + # Если не JSON, возвращаем как есть + return json_str + + except Exception as e: + return f"❌ Ошибка: {str(e)}" + +# Создание Gradio интерфейса +with gr.Blocks(title="Code Analyzer Model") as demo: + gr.Markdown(""" + # 🔍 Code Analyzer Model + + Модель для анализа кода студента на основе условия задачи. + + **Как использовать:** + 1. Введите условие задачи в первое поле + 2. Введите код решения студента во второе поле + 3. Нажмите "Анализировать код" + 4. Получите детальный анализ в формате JSON + + **API Endpoint:** `/api/predict` - используйте для интеграции в другие проекты + """) + + with gr.Row(): + with gr.Column(): + task_input = gr.Textbox( + label="Условие задачи", + placeholder="Введите условие задачи...", + lines=5 + ) + code_input = gr.Textbox( + label="Код решения студента", + placeholder="Введите код решения...", + lines=10 + ) + submit_btn = gr.Button("Анализировать код", variant="primary", size="lg") + + with gr.Column(): + result_output = gr.JSON( + label="Результат анализа" + ) + # Также показываем как текст для удобства копирования + result_text = gr.Textbox( + label="Результат (JSON текст)", + lines=15, + interactive=False + ) + + # Примеры + gr.Examples( + examples=[ + [ + "Напишите функцию, которая принимает список чисел и возвращает сумму всех элементов.", + "def sum_list(numbers):\n total = 0\n for num in numbers:\n total += num\n return total" + ], + [ + "Создайте функцию для вычисления факториала числа.", + "def factorial(n):\n if n <= 1:\n return 1\n return n * factorial(n-1)" + ], + ], + inputs=[task_input, code_input] + ) + + def analyze_and_format(task, code): + """Анализирует код и форматирует результат""" + result_str = analyze_code(task, code) + try: + result_json = json.loads(result_str) + return result_json, result_str + except: + return None, result_str + + # Загрузка модели при старте + demo.load(load_model, outputs=None) + + # Обработчик кнопки + submit_btn.click( + fn=analyze_and_format, + inputs=[task_input, code_input], + outputs=[result_output, result_text] + ) + + # Обработчик Enter в поле кода + code_input.submit( + fn=analyze_and_format, + inputs=[task_input, code_input], + outputs=[result_output, result_text] + ) + +# Gradio автоматически создает API endpoint на /api/predict +# Для использования из других проектов: +# POST https://YOUR_SPACE_URL.hf.space/api/predict +# Body: {"data": ["task", "code"]} + +if __name__ == "__main__": + demo.launch(theme=gr.themes.Soft(), server_name="0.0.0.0") diff --git a/chat_template.jinja b/chat_template.jinja new file mode 100644 index 0000000..9840d40 --- /dev/null +++ b/chat_template.jinja @@ -0,0 +1,54 @@ +{%- if tools %} + {{- '<|im_start|>system\n' }} + {%- if messages[0]['role'] == 'system' %} + {{- messages[0]['content'] }} + {%- else %} + {{- 'You are Qwen, created by Alibaba Cloud. You are a helpful assistant.' }} + {%- endif %} + {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n" }} + {%- for tool in tools %} + {{- "\n" }} + {{- tool | tojson }} + {%- endfor %} + {{- "\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{\"name\": , \"arguments\": }\n<|im_end|>\n" }} +{%- else %} + {%- if messages[0]['role'] == 'system' %} + {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }} + {%- else %} + {{- '<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n' }} + {%- endif %} +{%- endif %} +{%- for message in messages %} + {%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %} + {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }} + {%- elif message.role == "assistant" %} + {{- '<|im_start|>' + message.role }} + {%- if message.content %} + {{- '\n' + message.content }} + {%- endif %} + {%- for tool_call in message.tool_calls %} + {%- if tool_call.function is defined %} + {%- set tool_call = tool_call.function %} + {%- endif %} + {{- '\n\n{"name": "' }} + {{- tool_call.name }} + {{- '", "arguments": ' }} + {{- tool_call.arguments | tojson }} + {{- '}\n' }} + {%- endfor %} + {{- '<|im_end|>\n' }} + {%- elif message.role == "tool" %} + {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %} + {{- '<|im_start|>user' }} + {%- endif %} + {{- '\n\n' }} + {{- message.content }} + {{- '\n' }} + {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} + {{- '<|im_end|>\n' }} + {%- endif %} + {%- endif %} +{%- endfor %} +{%- if add_generation_prompt %} + {{- '<|im_start|>assistant\n' }} +{%- endif %} diff --git a/config.json b/config.json new file mode 100644 index 0000000..3ff067b --- /dev/null +++ b/config.json @@ -0,0 +1,69 @@ +{ + "architectures": [ + "Qwen2ForCausalLM" + ], + "attention_dropout": 0.0, + "bos_token_id": 151643, + "dtype": "bfloat16", + "eos_token_id": 151645, + "hidden_act": "silu", + "hidden_size": 2048, + "initializer_range": 0.02, + "intermediate_size": 11008, + "layer_types": [ + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention", + "full_attention" + ], + "max_position_embeddings": 32768, + "max_window_layers": 36, + "model_type": "qwen2", + "num_attention_heads": 16, + "num_hidden_layers": 36, + "num_key_value_heads": 2, + "pad_token_id": null, + "rms_norm_eps": 1e-06, + "rope_parameters": { + "rope_theta": 1000000.0, + "rope_type": "default" + }, + "sliding_window": null, + "tie_word_embeddings": true, + "transformers_version": "5.0.0", + "use_cache": true, + "use_sliding_window": false, + "vocab_size": 151936 +} diff --git a/generation_config.json b/generation_config.json new file mode 100644 index 0000000..fcbed66 --- /dev/null +++ b/generation_config.json @@ -0,0 +1,14 @@ +{ + "bos_token_id": 151643, + "do_sample": true, + "eos_token_id": [ + 151645, + 151643 + ], + "pad_token_id": 151643, + "repetition_penalty": 1.05, + "temperature": 0.7, + "top_k": 20, + "top_p": 0.8, + "transformers_version": "5.0.0" +} diff --git a/inference.py b/inference.py new file mode 100644 index 0000000..b665209 --- /dev/null +++ b/inference.py @@ -0,0 +1,99 @@ +""" +Inference code for Code Analyzer Model +This file enables the "Use this model" button on Hugging Face. +""" + +from transformers import AutoModelForCausalLM, AutoTokenizer +import torch + + +def load_model_and_tokenizer(model_name: str): + """Load model and tokenizer""" + tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) + model = AutoModelForCausalLM.from_pretrained( + model_name, + torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32, + device_map="auto", + trust_remote_code=True + ) + return model, tokenizer + + +def build_input(task, code): + """Build input in the same format as used during training""" + parts = [] + if task.strip(): + parts.append(f"Задача:\n{task.strip()}") + if code.strip(): + parts.append(f"Решение (код):\n```python\n{code.strip()}\n```") + return "\n\n".join(parts) + + +def generate_response( + model, + tokenizer, + task: str, + code: str, + max_new_tokens: int = 1024, + temperature: float = 0.7, + top_p: float = 0.8, + top_k: int = 20, + repetition_penalty: float = 1.05, +): + """Generate analysis response for task and student code""" + # Format input in training style + input_text = build_input(task, code) + prompt = f"{input_text}\n\nОтвет:\n" + + inputs = tokenizer(prompt, return_tensors="pt").to(model.device) + + with torch.no_grad(): + outputs = model.generate( + **inputs, + max_new_tokens=max_new_tokens, + temperature=temperature, + top_p=top_p, + top_k=top_k, + repetition_penalty=repetition_penalty, + do_sample=True, + pad_token_id=tokenizer.eos_token_id + ) + + response = tokenizer.decode(outputs[0], skip_special_tokens=True) + # Extract only the answer part + if "Ответ:" in response: + response = response.split("Ответ:")[-1].strip() + + return response + + +if __name__ == "__main__": + # Example usage + import json + + model_name = "Vilyam888/Code_analyze.1.0" + + print("Loading model...") + model, tokenizer = load_model_and_tokenizer(model_name) + + # Example: task and student code + task = "Напишите функцию, которая принимает список чисел и возвращает сумму всех элементов." + code = """def sum_list(numbers): + total = 0 + for num in numbers: + total += num + return total""" + + print(f"\nЗадача: {task}") + print(f"\nКод студента:\n{code}\n") + print("Generating analysis...") + + response = generate_response(model, tokenizer, task, code) + + # Try to parse as JSON + try: + result = json.loads(response) + print(f"\nРезультат анализа (JSON):") + print(json.dumps(result, ensure_ascii=False, indent=2)) + except json.JSONDecodeError: + print(f"\nРезультат анализа:\n{response}") diff --git a/metrics/01_training_perplexity.json b/metrics/01_training_perplexity.json new file mode 100644 index 0000000..502fbb0 --- /dev/null +++ b/metrics/01_training_perplexity.json @@ -0,0 +1,21 @@ +{ + "metric_group": "training_perplexity", + "model": "Code_analyze.1.0", + "hf_model": "Vilyam888/Code_analyze.1.0", + "base_model": "Qwen/Qwen2.5-Coder-3B-Instruct", + "finetuning_method": "LoRA", + "base_model_quantization": "none", + "inference_dtype": "bfloat16", + "checkpoint": "outputs/code-analyze-qlora/checkpoint-222", + "source": "outputs/code-analyze-qlora/checkpoint-222/trainer_state.json", + "validation_file": "prepared_data/code_analyze/val.jsonl", + "evaluation_date": "2026-06-11", + "metrics": { + "train_loss_final": 0.241, + "eval_loss_final": 0.2776, + "eval_mean_token_accuracy": 0.925, + "perplexity_validation": 1.32, + "num_train_epochs": 2, + "global_step": 222 + } +} \ No newline at end of file diff --git a/metrics/02_json_validity.json b/metrics/02_json_validity.json new file mode 100644 index 0000000..4de292a --- /dev/null +++ b/metrics/02_json_validity.json @@ -0,0 +1,37 @@ +{ + "metric_group": "json_validity", + "model": "Code_analyze.1.0", + "hf_model": "Vilyam888/Code_analyze.1.0", + "evaluation_file": "prepared_data/code_analyze/test.jsonl", + "evaluation_date": "2026-06-11", + "samples_evaluated": 100, + "generation_params": { + "temperature": 0.2, + "top_p": 0.95, + "max_new_tokens": 2048, + "seed": 42 + }, + "required_fields": [ + "summary", + "tags", + "suggested_tags", + "overall_score", + "code_quality_score", + "correctness", + "task_compliance", + "strengths", + "weaknesses", + "recommendations", + "detailed_analysis" + ], + "metrics": { + "valid_json_rate": 0.93, + "required_fields_rate": 0.9, + "tag_name_match_rate": 0.88 + }, + "metrics_counts": { + "valid_json": 93, + "required_fields_complete": 90, + "tag_name_match": 88 + } +} \ No newline at end of file diff --git a/metrics/03_bleu_rouge.json b/metrics/03_bleu_rouge.json new file mode 100644 index 0000000..4f1e146 --- /dev/null +++ b/metrics/03_bleu_rouge.json @@ -0,0 +1,26 @@ +{ + "metric_group": "bleu_rouge", + "model": "Code_analyze.1.0", + "hf_model": "Vilyam888/Code_analyze.1.0", + "evaluation_file": "prepared_data/code_analyze/test.jsonl", + "evaluation_date": "2026-06-11", + "text_fields": [ + "summary", + "detailed_analysis", + "recommendations" + ], + "pairs_evaluated": 93, + "generation_params": { + "temperature": 0.2, + "top_p": 0.95, + "max_new_tokens": 2048, + "seed": 42 + }, + "metrics": { + "bleu4_corpus": 0.7, + "bleu4_summary": 0.72, + "rouge1_f1": 0.71, + "rouge2_f1": 0.56, + "rougeL_f1": 0.69 + } +} \ No newline at end of file diff --git a/metrics/04_code_metrics.json b/metrics/04_code_metrics.json new file mode 100644 index 0000000..bf41835 --- /dev/null +++ b/metrics/04_code_metrics.json @@ -0,0 +1,7 @@ +{ + "metric_group": "code_metrics", + "model": "Code_analyze.1.0", + "status": "not_applicable", + "reason": "Модель генерирует JSON-анализ кода; метрика CodeBLEU не входит в протокол оценки.", + "metrics": {} +} \ No newline at end of file diff --git a/metrics/README.md b/metrics/README.md new file mode 100644 index 0000000..d1e366f --- /dev/null +++ b/metrics/README.md @@ -0,0 +1,37 @@ +# Метрики оценки Code_analyze.1.0 + +Автоматическая оценка дообученной модели [Vilyam888/Code_analyze.1.0](https://huggingface.co/Vilyam888/Code_analyze.1.0) на hold-out выборке. + +## Протокол оценки + +| Параметр | Значение | +|----------|----------| +| Базовая модель | Qwen/Qwen2.5-Coder-3B-Instruct | +| Метод дообучения | LoRA (без 4-bit квантизации), 2 эпохи, checkpoint-222 | +| Инференс | bfloat16, merged-модель | +| Тестовая выборка | `prepared_data/code_analyze/test.jsonl`, N = 100 | +| Reference | Поля JSON из test split | +| Temperature | 0.2 | +| max_new_tokens | 2048 | + +## Итоговые метрики + +| Метрика | Значение | +|---------|----------| +| Perplexity (validation) | **1.32** | +| valid_json_rate | **93 %** | +| required_fields_rate | **90 %** | +| tag_name_match_rate | **88 %** | +| BLEU-4 (corpus) | **0.70** | +| ROUGE-L F1 | **0.69** | +| CodeBLEU | не применяется | + +## Файлы + +- `evaluation_report.json` / `evaluation_report.txt` — сводный отчёт +- `01_training_perplexity.json` — метрики обучения (loss, PPL) +- `02_json_validity.json` — валидность и полнота JSON +- `03_bleu_rouge.json` — BLEU и ROUGE по текстовым полям +- `04_code_metrics.json` — пояснение по CodeBLEU + +Human Evaluation в протокол оценки данной модели **не входит**. diff --git a/metrics/evaluation_report.json b/metrics/evaluation_report.json new file mode 100644 index 0000000..ddcae06 --- /dev/null +++ b/metrics/evaluation_report.json @@ -0,0 +1,35 @@ +{ + "title": "Отчёт об оценке модели Code_analyze.1.0", + "model": "Code_analyze.1.0", + "hf_model": "Vilyam888/Code_analyze.1.0", + "base_model": "Qwen/Qwen2.5-Coder-3B-Instruct", + "finetuning_method": "LoRA", + "base_model_quantization": "none", + "inference_dtype": "bfloat16", + "evaluation_date": "2026-06-11", + "evaluation_sample": "test.jsonl, N = 100", + "reference_split": "hold-out test", + "generation": { + "temperature": 0.2, + "max_new_tokens": 2048 + }, + "training": { + "train_loss_final": 0.241, + "eval_loss_final": 0.2776, + "eval_mean_token_accuracy": 0.925, + "perplexity_validation": 1.32, + "num_train_epochs": 2, + "global_step": 222 + }, + "generation_metrics": { + "valid_json_rate": 0.93, + "required_fields_rate": 0.9, + "tag_name_match_rate": 0.88, + "bleu4_corpus": 0.7, + "bleu4_summary": 0.72, + "rouge1_f1": 0.71, + "rouge2_f1": 0.56, + "rougeL_f1": 0.69, + "codebleu_status": "not_applicable" + } +} \ No newline at end of file diff --git a/metrics/evaluation_report.txt b/metrics/evaluation_report.txt new file mode 100644 index 0000000..7597a72 --- /dev/null +++ b/metrics/evaluation_report.txt @@ -0,0 +1,33 @@ +ОТЧЁТ ОБ ОЦЕНКЕ МОДЕЛИ Code_analyze.1.0 +Репозиторий: Vilyam888/Code_analyze.1.0 +Базовая модель: Qwen/Qwen2.5-Coder-3B-Instruct +Метод дообучения: LoRA (без 4-bit квантизации) +Инференс: bfloat16, merged-модель +Дата оценки: 2026-06-11 +Выборка: test.jsonl, N = 100 (hold-out test) +Генерация: temperature = 0.2, max_new_tokens = 2048 + +1. Perplexity (validation, checkpoint-222): + • train_loss_final: 0.241 + • eval_loss_final: 0.2776 + • eval_mean_token_accuracy: 0.925 + • perplexity_validation: 1.32 + • num_train_epochs: 2 + • global_step: 222 + +2. JSON validity: + • valid_json_rate: 0.93 + • required_fields_rate: 0.9 + • tag_name_match_rate: 0.88 + • counts: valid_json=93, required_fields=90, tag_match=88 + +3. BLEU: + • bleu4_corpus: 0.7 + • bleu4_summary: 0.72 + +4. ROUGE-N: + • rouge1_f1: 0.71 + • rouge2_f1: 0.56 + • rougeL_f1: 0.69 + +5. CodeBLEU: не применяется (модель анализа кода, JSON-выход) \ No newline at end of file diff --git a/model.safetensors b/model.safetensors new file mode 100644 index 0000000..31cdd0f --- /dev/null +++ b/model.safetensors @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1211b3b8d562ad360b2b896a383081b835e769b54d3c2a6fc48b4c3b3a692427 +size 6171927112 diff --git a/requirements_gradio.txt b/requirements_gradio.txt new file mode 100644 index 0000000..1cf6d45 --- /dev/null +++ b/requirements_gradio.txt @@ -0,0 +1,7 @@ +gradio>=4.0.0 +transformers>=5.0.0 +torch>=2.0.0 +accelerate +sentencepiece +fastapi>=0.104.0 +uvicorn[standard]>=0.24.0 \ No newline at end of file diff --git a/tokenizer.json b/tokenizer.json new file mode 100644 index 0000000..34510ff --- /dev/null +++ b/tokenizer.json @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3fd169731d2cbde95e10bf356d66d5997fd885dd8dbb6fb4684da3f23b2585d8 +size 11421892 diff --git a/tokenizer_config.json b/tokenizer_config.json new file mode 100644 index 0000000..a83f1ee --- /dev/null +++ b/tokenizer_config.json @@ -0,0 +1,29 @@ +{ + "add_prefix_space": false, + "backend": "tokenizers", + "bos_token": null, + "clean_up_tokenization_spaces": false, + "eos_token": "<|im_end|>", + "errors": "replace", + "extra_special_tokens": [ + "<|im_start|>", + "<|im_end|>", + "<|object_ref_start|>", + "<|object_ref_end|>", + "<|box_start|>", + "<|box_end|>", + "<|quad_start|>", + "<|quad_end|>", + "<|vision_start|>", + "<|vision_end|>", + "<|vision_pad|>", + "<|image_pad|>", + "<|video_pad|>" + ], + "is_local": false, + "model_max_length": 32768, + "pad_token": "<|endoftext|>", + "split_special_tokens": false, + "tokenizer_class": "Qwen2Tokenizer", + "unk_token": null +}