
Я это сделал. За один день.
Часть 1: Аппаратная часть
Выбор видеокарт: RTX 2060 vs RTX 1060
Когда я начал планировать сборку, первый вопрос был: какие GPU выбрать? У меня лежали две RTX 2060 (2019) и одна RTX 1060 (2017). Интуитивно казалось, что 1060 давно устарела, но я решил проверить.
RTX 1060 — это действительно прошлый век для ML:
Нет поддержки NVLINK (не синхронизируются две карты)
CUDA Compute Capability 6.1 (старая архитектура, плохая поддержка современных операций)
Memory bandwidth всего 192 ГБ/сек
Нет Tensor Cores (ускорение операций матричного умножения)
На Stable Diffusion генерирует 512x512 за 60+ секунд
RTX 2060 — совершенно другой уровень:
CUDA Compute Capability 7.5 (хорошая поддержка современных фреймворков)
Встроены Tensor Cores (ускорение ML операций в 2-3 раза)
Memory bandwidth 360 ГБ/сек (почти в 2 раза выше)
Две карты синхронизируются через PCIe x16 + x4 без проблем
На обеих вместе генерируют 512x512 за 35-40 секунд
Вердикт: две RTX 2060 с 12GB VRAM на двух картах — это идеал для локального ML на бюджете. Они работают параллельно: одна генерирует Stable Diffusion, вторая анализирует через YOLOv8.
Материнская плата и BIOS: Gigabyte Z390-D
Выбрал Z390-D потому что она поддерживает dual-GPU без наворотов и имеет встроенную поддержку аппаратного RAID через Intel EZ RAID.
Критичные BIOS настройки:
Menu: Setting → IO Ports ├─ Initial Display Output: PCIEX16 │ (основной монитор подключается к первой карте) └─ Internal Graphics: Disabled (освобождаем ресурсы для GPU) Menu: Setting → Miscellaneous └─ Re-Size BAR: Enabled (BAR = Base Address Register Resizing) (даёт +5-10% производительности GPU) Menu: Tweaker → AI Tweaker └─ XMP Profile 1: Enabled (память DDR4-3000 работает на полной частоте)
Почему это важно:
Если не отключить Internal Graphics, система может отдать память встроенному видеоядру вместо выделения памяти GPU
Re-Size BAR позволяет CPU полностью адресовать всю VRAM GPU (по умолчанию адресуется только часть)
XMP включает профиль XMP 1 для памяти, поднимая её с стоковых ~2133 МГц до 3000 МГц
После этих настроек обе GPU видны в nvidia-smi без конфликтов.
Дисковая система: 6 дисков с аппаратным RAID 1
Это была самая боль часть настройки — инициализация пяти дополнительных дисков и создание RAID 1 через BIOS.
Текущая конфигурация:
Диск | Тип | Объём | Назначение | Паттерн I/O |
|---|---|---|---|---|
C: | SSD | 1ТБ | Windows 10/11 + Python + PyTorch | Random I/O (система) |
D: | HDD | 2ТБ | Архив исходных изображений | Sequential read |
E: | HDD | 2ТБ | Архив готовых результатов | Sequential write |
F: | SSD | 1ТБ | Кэш ML (временные файлы) | Random I/O (кэш) |
G: | SSD | 1ТБ | Рабочие данные ML | Random read |
Intel RAID 1 | SSD | 2ТБ | Зеркало (Диск 4+5 в BIOS) | Аппаратный RAID |
Почему именно такая схема:
C: на SSD — Windows и Python нужны быстрый доступ. Если загрузка долгая, всё упирается в дисковый I/O
D: и E: на HDD — там гигабайты сырых изображений и результатов. Скорость доступа не критична для архива, но объём нужен
F: на отдельном SSD — ML операции пишут кэш параллельно. Если поставить на HDD, это создаст узкое место (IOPS). SSD обработает одновременно и операции чтения из памяти ML
G: на SSD — рабочие данные, нужен быстрый доступ
Intel RAID 1 — аппаратное зеркало двух SSD на уровне BIOS контроллера
Аппаратный RAID 1 через Intel EZ RAID:
BIOS: Main Menu → EZ RAID ├─ Создаём массив (Array 1) ├─ Выбираем два SSD (физически Диск 4 и Диск 5) ├─ Режим: RAID 1 (зеркало) └─ Применяем Результат: ├─ Два SSD синхронизируются на уровне контроллера ├─ Любые данные пишутся на оба одновременно ├─ Если один выходит из строя — второй продолжает работу ├─ Windows видит это как один логический том └─ RPO (Recovery Point Objective) = 0 (нет потерь данных)
Почему RAID 1, а не другие уровни:
RAID 0 — быстрее, но если один диск сломается, всё потеряется
RAID 1 — медленнее (нужно писать дважды), зато при отказе одного диска данные остаются
RAID 5 — лучше (паритет), но нужно минимум 3 диска
Для критичной системы RAID 1 — компромисс между надёжностью и простотой.
Часть 2: Программная часть
Python 3.12 и экосистема
Почему Python 3.12, а не 3.13/3.14:
3.12 — стабильна, все ML фреймворки полностью совместимы, используется в production
3.13-3.14 — слишком новые, могут быть проблемы совместимости с PyTorch, TensorFlow и др.
3.9-3.10 — уже не поддерживаются, лучше избегать для новых проектов
Установка:
# Скачиваем с https://www.python.org/downloads/ # ОБЯЗАТЕЛЬНО отмечаем "Add Python to PATH" # Проверка python --version # Output: Python 3.12.x
Виртуальное окружение (venv)
Виртуальное окружение изолирует зависимости проекта от системного Python. Это критично, потому что разные проекты могут требовать разные версии одних и тех же пакетов.
# Создание рабочей папки mkdir D:\ML cd D:\ML # Создание venv python -m venv venv # Активация (Windows) venv\Scripts\activate # Результат: (venv) D:\ML>
Почему это нужно:
Если установить пакеты глобально в Python, они загрязняют системный интерпретатор
Разные версии PyTorch для разных GPU или версий CUDA конфликтуют
venv позволяет иметь несколько проектов с несовместимыми зависимостями
PyTorch + CUDA: сердце системы
PyTorch свяжет Python с GPU через CUDA (Compute Unified Device Architecture от NVIDIA).
# Обновление pip (критично!) python -m pip install --upgrade pip # Установка PyTorch с CUDA 11.8 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
Этот шаг займёт 10-15 минут и скачает 2-3GB. Не прерывайте!
Что происходит:
PyTorch скачивает бинарики скомпилированные с поддержкой CUDA 11.8
Если установить просто
pip install torch, по умолчанию скачается CPU-only версия (бесполезная для нас)С флагом
--index-urlhttps://download.pytorch.org/whl/cu118мы принудительно берём GPU версиюСкачивается ~800MB основного пакета PyTorch + зависимости
Проверка:
# Проверка доступности CUDA python -c "import torch; print(torch.cuda.is_available())" # Output: True # Количество GPU python -c "import torch; print(f'GPUs: {torch.cuda.device_count()}')" # Output: GPUs: 2 # Информация о каждой GPU python -c "import torch; print(torch.cuda.get_device_name(0)); print(torch.cuda.get_device_name(1))" # Output: NVIDIA GeForce RTX 2060 # NVIDIA GeForce RTX 2060 # Memory доступная на GPU python -c "import torch; print(f'GPU 0: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f}GB'); print(f'GPU 1: {torch.cuda.get_device_properties(1).total_memory / 1e9:.1f}GB')" # Output: GPU 0: 6.0GB # GPU 1: 6.0GB
ML библиотеки
# Основной стек pip install diffusers transformers accelerate # Computer Vision pip install ultralytics opencv-python # Утилиты pip install pillow numpy pandas matplotlib scikit-learn # Опционально: для работы с моделями pip install safetensors huggingface-hub # Этот шаг займет 5-10 минут
Что это:
diffusers — официальная библиотека HuggingFace для работы с diffusion моделями (Stable Diffusion)
transformers — HuggingFace трансформеры (LLM, BERT и др.)
accelerate — оптимизация обучения/инференса на нескольких GPU/TPU, автоматическое распределение нагрузки
ultralytics — YOLOv8 для детекции объектов, натренирована на COCO dataset
opencv-python — обработка изображений (чтение, запись, трансформации)
safetensors — безопасный формат хранения весов моделей (быстрее чем pickle)
huggingface-hub — скачивание моделей из HuggingFace (где хранятся Stable Diffusion, LLM и т.д.)
Часть 3: Первый тест системы
Создание тестового скрипта
import torch from diffusers import StableDiffusionPipeline from ultralytics import YOLO import time import cv2 import numpy as np print("="*60) print("TESTING DUAL GPU ML SYSTEM") print("="*60) # === ДИАГНОСТИКА === print(f"\n✓ CUDA Available: {torch.cuda.is_available()}") print(f"✓ GPU Count: {torch.cuda.device_count()}") for i in range(torch.cuda.device_count()): props = torch.cuda.get_device_properties(i) total_memory_gb = props.total_memory / 1e9 print(f" GPU {i}: {props.name}, {total_memory_gb:.1f}GB VRAM") # === ТЕСТ GPU #0: STABLE DIFFUSION === print("\n[GPU 0] Loading Stable Diffusion v1.5...") start = time.time() pipe = StableDiffusionPipeline.from_pretrained( "runwayml/stable-diffusion-v1-5", torch_dtype=torch.float16, safety_checker=None # отключаем проверку безопасности для ускорения ) pipe = pipe.to("cuda:0") load_time = time.time() - start print(f"✓ Model loaded in {load_time:.1f}s") # Генерация изображения print("[GPU 0] Generating image (512x512)...") start = time.time() image = pipe( prompt="a beautiful laser engraving design with geometric patterns", height=512, width=512, num_inference_steps=20, guidance_scale=7.5 ).images[0] gen_time = time.time() - start image.save("D:/test_gpu0.png") print(f"✓ Generated in {gen_time:.1f}s") print(f" → Speed: {512*512/gen_time:.0f} pixels/sec") # === ТЕСТ GPU #1: YOLOV8 === print("\n[GPU 1] Loading YOLOv8 nano...") start = time.time() model = YOLO("yolov8n.pt") # Явно указываем device model.to("cuda:1") yolo_load_time = time.time() - start print(f"✓ Model loaded in {yolo_load_time:.1f}s") # Тест детекции print("[GPU 1] Running inference...") test_frame = np.random.randint(0, 255, (640, 480, 3), dtype=np.uint8) start = time.time() results = model(test_frame, device="cuda:1", verbose=False) detect_time = time.time() - start print(f"✓ Detection in {detect_time:.3f}s") print(f" → Throughput: {1/detect_time:.1f} FPS") # === РЕЗУЛЬТАТЫ === print("\n" + "="*60) print("PERFORMANCE SUMMARY") print("="*60) print(f"Stable Diffusion (GPU 0):") print(f" Load time: {load_time:.1f}s") print(f" Generation: {gen_time:.1f}s for 512x512") print(f" Throughput: {512*512/gen_time:.0f} px/s") print(f"\nYOLOv8 (GPU 1):") print(f" Load time: {yolo_load_time:.1f}s") print(f" Inference: {detect_time*1000:.1f}ms per frame") print(f" Throughput: {1/detect_time:.1f} FPS") print("\n✓ SYSTEM READY FOR PRODUCTION") print("="*60)
Запуск теста
# В окне CMD с активированным venv python test_system.py
Ожидаемый результат:
============================================================ TESTING DUAL GPU ML SYSTEM ============================================================ ✓ CUDA Available: True ✓ GPU Count: 2 GPU 0: NVIDIA GeForce RTX 2060, 6.0GB VRAM GPU 1: NVIDIA GeForce RTX 2060, 6.0GB VRAM [GPU 0] Loading Stable Diffusion v1.5... ✓ Model loaded in 12.5s [GPU 0] Generating image (512x512)... ✓ Generated in 38.2s → Speed: 6862 pixels/sec [GPU 1] Loading YOLOv8 nano... ✓ Model loaded in 2.1s [GPU 1] Running inference... ✓ Detection in 0.045s → Throughput: 22.2 FPS ============================================================ PERFORMANCE SUMMARY ============================================================ Stable Diffusion (GPU 0): Load time: 12.5s Generation: 38.2s for 512x512 Throughput: 6862 px/s YOLOv8 (GPU 1): Load time: 2.1s Inference: 45.0ms per frame Throughput: 22.2 FPS ✓ SYSTEM READY FOR PRODUCTION ============================================================
Что это значит:
Обе GPU работают без конфликтов параллельно
Stable Diffusion генерирует адекватную скорость (38 сек — это нормально для RTX 2060)
YOLOv8 готов к real-time обработке видео (22 FPS достаточно для анализа качества)
Обе модели загружены в VRAM одновременно (12+3 = 15GB теоретически, но используется ~11GB из 12 доступных)
Нет ошибок CUDA, конфликтов памяти или синхронизации

Сравнение: локальное решение vs облако
Метрика | RTX 2060 (локально) | ChatGPT API | Google Cloud AI |
|---|---|---|---|
Генерация 512x512 | 38 сек | 20-30 сек | ~15 сек |
Стоимость 1000 операций | ₽0 (один раз) | ₽50-100 | ₽30-50 |
Конфиденциальность | 100% (на машине) | 0% (облако Openai) | 0% (облако Google) |
Latency сети | 0мс | 200-500ms | 200-500ms |
Работает offline | Да | Нет | Нет |
Полный контроль | Да | Нет | Нет |
Масштабируемость | Одна машина | Неограниченно | Неограниченно |
Гарантия 99.9% uptime | Нет | Да | Да |
Для ACMER P3 локальное решение — идеально:
Нет задержек из-за интернета (критично для real-time обработки)
Полный контроль над процессом генерации (можно встроить в workflow)
Можно встроить в автоматизацию без API лимитов
Бесплатно после первоначальной инвестиции
Заключение
За ₽0 и несколько часов работы я собрал production-grade ML сервер, который:
✅ Генерирует дизайны через Stable Diffusion (38 сек/изображение)
✅ Анализирует изображения через YOLOv8 в real-time (22 FPS)
✅ Работает полностью локально (без облака, без API лимитов)
✅ Использует аппаратный RAID 1 для надёжности системы
✅ Готов к интеграции с ACMER P3 для автоматизированной лазерной гравировки
✅ Масштабируется для других ML задач (LLM, компьютерное зрение и т.д.)
Стоимость: ₽0 (всё из хлама)
Время сборки: 1 день
Потенциал: неограниченный
Следующая часть: интеграция с ACMER P3 и первая гравировка.
Кто ещё собирал ML сервер на б/у железе? Какие трудности встретили? Какие модели планируете запускать? Пишите в комментарии!
Подпишитесь на мой Telegram канал!
Там я публикую:
🤖 Еженедельные обновления про AI и ML
🔧 Практические гайды по настройке железа и ПО
💡 Инсайты про нейротехнологии и локальные LLM
📝 Промежуточные результаты этого проекта и интеграцию с ACMER P3
🚀 Ранний доступ к новым статьям и экспериментам
В канале уже обсуждается:
Часть 2: Python 3.12 + PyTorch установка (детальный гайд)
Оптимизация Stable Diffusion для максимальной скорости
Подключение лазера ACMER P3 к ML pipeline
Обзор локальных LLM для различных задач
Присоединяйтесь, чтобы не пропустить следующую часть про интеграцию лазера!
Используемые технологии:
PyTorch 2.x + CUDA 11.8
Stable Diffusion v1.5 (HuggingFace)
YOLOv8 (Ultralytics)
Python 3.12
Gigabyte Z390-D с Intel EZ RAID
2x NVIDIA RTX 2060 + 32GB DDR4-3000
