Река в лесу, окружённая зелёными деревьями и каменистыми берегами, на фоне солнечного дня.

Оптимизация передачи данных в рабочих нагрузках ИИ/машинного обучения

Подробный анализ узких мест в передаче данных, их выявление и устранение с помощью NVIDIA Nsight™ Systems.

Делиться

3f7f5ce2f03f07f647badd87cf0857b2

В типичной задаче искусственного интеллекта/машинного обучения модель глубокого обучения выполняется на выделенном графическом процессоре (GPU) с использованием пакетов входных данных, получаемых от центрального процессора (CPU). В идеале графический процессор — более дорогостоящий ресурс — должен использоваться максимально эффективно, с минимальным временем простоя. В частности, это означает, что каждый раз, когда он завершает обработку пакета данных, следующий пакет будет «готов к обработке». Если этого не происходит, графический процессор простаивает в ожидании входных данных — распространенное узкое место в производительности, часто называемое «голоданием GPU».

В предыдущих статьях (например, см. «Стратегия кэширования для выявления узких мест в конвейере ввода данных») мы обсуждали распространенные причины этой проблемы, включая: неэффективное извлечение данных из хранилища, исчерпание ресурсов ЦП и узкие места при передаче данных между хостом и устройством. В этой статье мы подробно рассмотрим узкие места при передаче данных и вернемся к их выявлению и устранению — на этот раз с помощью NVIDIA Nsight™ Systems (nsys), профилировщика производительности, предназначенного для анализа общесистемной активности рабочих нагрузок, работающих на графических процессорах NVIDIA.

Сравнение NVIDIA Nsight и PyTorch Profiler

Читатели, знакомые с нашей работой, могут удивиться упоминанию профилировщика NVIDIA Nsight, а не PyTorch Profiler. В наших предыдущих статьях мы настоятельно рекомендовали использовать PyTorch Profiler в разработке моделей ИИ/машинного обучения в качестве инструмента для выявления и оптимизации производительности во время выполнения. Мы неоднократно демонстрировали его применение для решения самых разных проблем с производительностью. Для его использования не требуется специальная установка, и он может запускаться без специальных разрешений операционной системы. NVIDIA Nsight Profiler, с другой стороны, требует специальной настройки системы (или специального контейнера NVIDIA) и — для некоторых своих функций — повышенных прав доступа, что делает его использование менее доступным и более сложным, чем PyTorch Profiler.

Эти два профилировщика различаются по своей направленности: PyTorch profiler — это профилировщик фреймворка, тесно связанный с PyTorch и в значительной степени ориентированный на то, как модели используют программный стек PyTorch и вспомогательные библиотеки. NVIDIA Nsight profiler — это профилировщик системного уровня; он не знает деталей запускаемой модели или используемого фреймворка, а скорее того, как используются и задействуются компоненты всей системы. В то время как PyTorch Profiler отлично справляется с отслеживанием низкоуровневых операций выполнения модели PyTorch, nsys предоставляет подробное представление о деятельности всей системы (оборудование GPU, потоки CUDA, прерывания ОС, сеть, PCIe и т. д.). Для многих проблем с производительностью PyTorch profiler достаточно для выявления и устранения источника узкого места; но в некоторых ситуациях требуется профилировщик nsys, «тяжелая артиллерия», для получения более глубокого понимания внутренней работы базовой системы.

В этой статье мы намерены продемонстрировать некоторые уникальные возможности профилировщика nsys и их применение для решения распространенной проблемы, связанной с узким местом в передаче данных.

Контур

Для упрощения обсуждения мы определим простую рабочую нагрузку машинного обучения с узким местом в производительности передачи данных и приступим к внедрению ряда последовательных оптимизаций в попытке решить эту проблему. На протяжении всего процесса мы будем использовать профилировщик nsys для анализа производительности системы и оценки влияния изменений в коде.

Настраивать

Мы будем проводить эксперименты на экземпляре Amazon EC2 g6e.2xlarge с графическим процессором NVIDIA L40S, работающем под управлением образа AWS Deep Learning (Ubuntu 24.04) с PyTorch (версия 2.8). Для установки профилировщика nsys-cli (версия 2025.6.1) мы будем следовать официальным рекомендациям NVIDIA:

wget https://developer.nvidia.com/downloads/assets/tools/secure/nsight-systems/2025_6/NsightSystems-linux-cli-public-2025.6.1.190-3689520.deb sudo apt install ./NsightSystems-linux-cli-public-2025.6.1.190-3689520.deb

Библиотека NVIDIA Tools Extension (NVTX) позволяет нам добавлять к коду удобочитаемые метки для повышения читаемости и понимания трассировки производительности. Хотя PyTorch предлагает встроенную поддержку NVTX через свои API torch.cuda.nvtx, мы будем использовать автономный пакет nvtx (версия 0.2.14), который поддерживает цветовое кодирование временной шкалы трассировки для лучшего визуального анализа:

pip install nvtx

Отказ от ответственности

Представленный код предназначен для демонстрационных целей; пожалуйста, не полагайтесь на его корректность или оптимальность. Не следует воспринимать использование нами каких-либо библиотек, инструментов или платформ как одобрение их использования. Влияние рассматриваемых оптимизаций может значительно варьироваться в зависимости от особенностей модели и среды выполнения. Перед внедрением обязательно оцените их влияние на ваш собственный сценарий использования.

Большое спасибо Ицхаку Леви и Гиладу Вассерману за их вклад в эту статью.

Игрушечная модель PyTorch

Мы представляем обучающий скрипт, специально разработанный для того, чтобы имитировать узкое место в конвейере ввода данных.

В приведенном ниже блоке кода мы определяем простую модель классификации изображений с использованием архитектуры ResNet-18.

import time, torch, torchvision DEVICE = «cuda» model = torchvision.models.resnet18().to(DEVICE).train() optimizer = torch.optim.Adam(model.parameters())

Далее мы определим синтетический набор данных, который будем использовать для обучения нашей модельной модели.

from torch.utils.data import Dataset, DataLoader WARMUP_STEPS = 10 PROFILE_STEPS = 3 COOLDOWN_STEPS = 1 TOTAL_STEPS = WARMUP_STEPS + PROFILE_STEPS + COOLDOWN_STEPS BATCH_SIZE = 64 TOTAL_SAMPLES = TOTAL_STEPS * BATCH_SIZE IMG_SIZE = 512 # Синтетический набор данных со случайными изображениями и метками class FakeDataset(Dataset): def __len__(self): return TOTAL_SAMPLES def __getitem__(self, index): img = torch.randn((3, IMG_SIZE, IMG_SIZE)) label = torch.tensor(index % 10) return img, label train_loader = DataLoader( FakeDataset(), batch_size=BATCH_SIZE )

Наконец, мы определяем стандартный этап обучения, запрограммированный на запуск nsys-profiler в три этапа с использованием команд torch.cuda.profiler.start и stop — предназначенный для использования совместно с CLI nsys. Мы выделяем компоненты этапа обучения с помощью утилиты nvtx.annotate. Для получения более подробной информации о профилировании с помощью nsys в PyTorch, пожалуйста, обратитесь к официальной документации.

import nvtx from torch.cuda import profiler def copy_data(batch): data, targets = batch data_gpu = data.to(DEVICE) targets_gpu = targets.to(DEVICE) return data_gpu, targets_gpu def compute_step(model, batch, optimizer): data, targets = batch output = model(data) loss = torch.nn.functional.cross_entropy(output, targets) loss.backward() optimizer.step() optimizer.zero_grad() return loss data_iter = iter(train_loader) for i in range(TOTAL_STEPS): if i == WARMUP_STEPS: # start nsys profiler torch.cuda.synchronize() start_time = time.perf_counter() profiler.start() elif i == WARMUP_STEPS + PROFILE_STEPS: # stop nsys profiler torch.cuda.synchronize() profiler.stop() end_time = time.perf_counter() with nvtx.annotate(f»Пакет {i}», color=»blue»): with nvtx.annotate(«Получить пакет», color=»red»): batch = next(data_iter) with nvtx.annotate(«Копировать пакет», color=»yellow»): batch = copy_data(batch) with nvtx.annotate(«Вычислить», color=»green»): compute_step(model, batch, optimizer) total_time = end_time — start_time throughput = PROFILE_STEPS / total_time print(f»Пропускная способность: {throughput:.2f} шагов/сек»)

Мы запускаем наш скрипт, используя опцию cudaProfilerApi для программного запуска и остановки профилировщика. Подробную информацию о профилировании из командной строки nsys см. в официальной документации.

nsys profile —capture-range=cudaProfilerApi —trace=cuda,nvtx,osrt —output=baseline python train.py

В результате получается файл трассировки baseline.nsys-rep, который мы копируем на нашу машину для разработки для анализа.

Для сравнения с PyTorch Profiler мы определяем альтернативный цикл обучения, запрограммированный с помощью PyTorch Profiler и аннотированный утилитой torch.profiler.record_function:

from torch.profiler import ( profile, record_function, schedule, tensorboard_trace_handler ) with profile( schedule=schedule(wait=0, warmup=WARMUP_STEPS, active=PROFILE_STEPS, repeat=1), on_trace_ready=tensorboard_trace_handler('./baseline'), record_shapes=True, with_stack=True ) as prof: for i in range(TOTAL_STEPS): with record_function(«get batch»): batch = next(data_iter) with record_function(«copy batch»): batch = copy_data(batch) with record_function(«compute»): compute_step(model, batch, optimizer) prof.step()

Пропускная способность нашего базового эксперимента составляет 2,97 шагов в секунду. В следующих разделах мы будем использовать трассировки профилирования для выявления узких мест производительности на этапе обучения и попытаемся улучшить этот результат.

Базовый анализ производительности

Для анализа полученного файла трассировки nsys мы открываем его в графическом интерфейсе пользователя Nsight Systems. На изображении ниже мы увеличили масштаб временной шкалы двух этапов обучения, зафиксированных профилировщиком:

e2d4bf4fec860abb57336988c68f03b2

Трассировка содержит огромное количество информации, лишь часть которой мы затронем в этом посте. Дополнительные функции и возможности см. в документации nsys.

Временная шкала разделена на две части: раздел CUDA, в котором отображается активность графического процессора, и раздел потоков, в котором отображается активность центрального процессора. В разделе CUDA четко различается активность ядра графического процессора (вычисления) (90,9%) и активность памяти (9,1%). Верхние столбцы в каждом разделе показывают использование каждого из ресурсов, и оба раздела включают раздел NVTX с цветными аннотациями, которые мы использовали на этапе обучения. Мы отмечаем следующие наблюдения:

  1. Графический процессор простаивает примерно 50% времени каждого шага обучения. Это видно по доле времени, затраченному на обработку каждого пакета данных (синим цветом) на индикаторе NVTX графического процессора, и по большим промежуткам между ними.
  2. Работа графического процессора для каждого пакета начинается сразу после завершения операции «получение пакета» на центральном процессоре. Она начинается с копирования данных из памяти хоста на устройство (отмечено светло-зеленым цветом) и продолжается вычислениями ядра (отмечено светло-синим цветом).
  3. После того как ЦП запустит команды обработки данных в памяти и вычисления на графическом процессоре для пакета N, он переходит к следующему пакету в цикле обучения, что приводит к частичному перекрытию пакета N+1 на ЦП с пакетом N на графическом процессоре.
  4. Подавляющее большинство потоков ЦП тратится на операцию «получения пакета». Это является основным узким местом в нашем базовом эксперименте.

Результаты профилирования указывают на явного виновника — загрузчик данных. По умолчанию PyTorch выполняет загрузку данных в один процесс — один процесс ЦП используется для загрузки следующего пакета входных данных, копирования его на графический процессор и запуска вычислительных ядер — всё это последовательно. Это обычно приводит к серьёзной неэффективности использования ресурсов ЦП из-за: 1) ограничения загрузки данных только одним процессом и 2) зависимости загрузки следующего пакета от завершения обработки ЦП (т.е. загрузки ядра) предыдущего пакета. Наше безответственное использование ресурсов ЦП привело к тому, что наш графический процессор испытывает нехватку входных данных.

К тому же выводу можно было бы прийти, используя трассировку PyTorch Profiler, показанную ниже:

1be29a324606a0c6151bba303ba25af0

Здесь также можно наблюдать длительные периоды недоиспользования графического процессора, вызванные длинными блоками «получения пакета» на стороне центрального процессора.

Оптимизация 1: Многопроцессная загрузка данных

Первый шаг — модификация конвейера ввода данных для использования многопроцессной загрузки данных. Мы устанавливаем количество рабочих процессов в соответствии с 8 виртуальными процессорами, доступными на нашем экземпляре Amazon EC2 g6e.2xlarge. В реальных условиях это значение следует оптимизировать для достижения максимальной пропускной способности:

NUM_WORKERS = 8 train_loader = DataLoader( FakeDataset(), batch_size=BATCH_SIZE, num_workers=NUM_WORKERS )

После этого изменения наша пропускная способность подскочила до 4,81 шагов в секунду — улучшение на 62% по сравнению с базовым результатом. Соответствующая трассировка профилировщика nsys показана ниже:

37dbd374a052d164938adfc40c5b84e9

Обратите внимание, что красный сегмент «получить пакет» теперь занимает лишь крошечную часть каждого шага на панели NVTX. На его месте теперь находится желтый блок «копировать пакет». Благодаря использованию многопроцессной загрузки данных, теперь всегда есть новый пакет, готовый к обработке — но можно ли сделать лучше?

При более внимательном рассмотрении раздела GPU мы видим, что между операцией с памятью и вычислениями ядра остается значительная часть времени простоя (~290 миллисекунд). Это время простоя идеально совпадает с операцией «munmap» в панели выполнения ОС. Блок «munmap» — это операция очистки памяти на стороне ЦП, выполняемая сразу после завершения копирования памяти CUDA. Она происходит в самом конце длинной желтой операции «пакетного копирования». Вычислительные ядра запускаются на GPU только после завершения очистки памяти. Это явная закономерность синхронного копирования памяти с хоста на устройство: ЦП не может приступить к загрузке ядра, пока операция копирования данных не будет полностью завершена, а GPU остается в режиме ожидания, пока ЦП не загрузит ядра.

Трассировка профилировщика PyTorch показывает то же время простоя графического процессора, но не предоставляет ту же подсказку «munmap». Это наш первый пример преимущества общесистемной видимости профилировщика nsys.

19b9c1309d220a29d3ecfed33c103b69

Обнаружив узкое место в производительности копирования данных, мы переходим к следующему этапу оптимизации.

Оптимизация 2: Асинхронная передача данных

Решение обнаруженного нами узкого места заключается в том, чтобы запрограммировать этап обучения на асинхронную загрузку данных. Это позволяет ЦП запускать вычислительные ядра сразу после отправки команды копирования памяти — без ожидания завершения копирования памяти. Таким образом, графический процессор может начать обработку ядер, как только будет завершено копирование памяти CUDA. Включение асинхронного копирования данных требует двух изменений: во-первых, мы должны запрограммировать загрузчик данных на использование закрепленной памяти (вместо страничной памяти), и во-вторых, мы должны передать аргумент non_blocking=True операциям to():

NUM_WORKERS = 8 ASYNC_DATATRANSFER = True train_loader = DataLoader( FakeDataset(), batch_size=BATCH_SIZE, num_workers=NUM_WORKERS, pin_memory=ASYNC_DATATRANSFER ) def copy_data(batch): data, targets = batch data_gpu = data.to(DEVICE, non_blocking=ASYNC_DATATRANSFER) targets_gpu = targets.to(DEVICE, non_blocking=ASYNC_DATATRANSFER) return data_gpu, targets_gpu

Использование асинхронной загрузки данных обеспечивает пропускную способность 5,91 шагов в секунду — дополнительное улучшение на 23% и общее улучшение на 99%. Полученный результат профилирования показан ниже:

b2a387304fcb908e8a9e488d40659333

Теперь мы видим, что все операции ЦП сгруппированы в начале трассировки. Мы устранили все препятствия для производительности на стороне ЦП, позволив ему свободно загружать данные и ядра на графический процессор. В разделе, посвященном графическому процессору, мы видим непрерывную активность без простоев. Однако мы видим четкое разделение между активностью памяти CUDA (светло-зеленым цветом) и активностью ядра CUDA (светло-синим цветом). Профилировщик PyTorch, напротив, не делает это различие очевидным. Это еще одно преимущество аппаратно-ориентированного профилировщика, и в случае нашего тестового эксперимента именно это определяет следующие шаги нашей оптимизации.

c221171a4862d5c76b849eee5034ad0b

Оптимизация 3: Конвейерная обработка с использованием CUDA Streams

Наши окончательные оптимизации обусловлены тем, что современные графические процессоры, такие как NVIDIA L40S, используют независимые механизмы для копирования памяти (DMA) и выполнения вычислительных ядер (SM). Мы можем воспользоваться этим, распараллелив отдельные операции с памятью и ядрами, которые мы наблюдали в трассировке профилировщика nsys. Мы запрограммируем это с помощью потоков CUDA.

В предыдущей публикации мы подробно рассмотрели возможности оптимизации рабочих нагрузок ИИ/машинного обучения с использованием потоков CUDA. Здесь мы применяем аналогичную стратегию конвейерной обработки: мы определяем два отдельных потока CUDA «копирование» и «вычисление» и программируем поток «копирование» таким образом, чтобы он копировал пакет N+1 одновременно с обработкой пакета N потоком «вычисление»:

# Определяем два потока CUDA compute_stream = torch.cuda.Stream() copy_stream = torch.cuda.Stream() # Извлекаем первый пакет next_batch = next(data_iter) with torch.cuda.stream(copy_stream): next_batch = copy_data(next_batch) for i in range(TOTAL_STEPS): if i == WARMUP_STEPS: torch.cuda.synchronize() start_time = time.perf_counter() profiler.start() elif i == WARMUP_STEPS + PROFILE_STEPS: torch.cuda.synchronize() profiler.stop() end_time = time.perf_counter() with nvtx.annotate(f»Пакет {i}», color=»blue»): # Ждем завершения копирования пакета N compute_stream.wait_stream(copy_stream) batch = next_batch # Выполняем модель на пакете N+1 compute stream try: with nvtx.annotate(«get batch», color=»red»): next_batch = next(data_iter) with torch.cuda.stream(copy_stream): with nvtx.annotate(«copy batch», color=»yellow»): next_batch = copy_data(next_batch) except: # достигнут конец набора данных next_batch = None # выполнить модель на пакете N compute stream with torch.cuda.stream(compute_stream): with nvtx.annotate(«Compute», color=»green»): compute_step(model, batch, optimizer) total_time = end_time — start_time throughput = PROFILE_STEPS / total_time print(f»Пропускная способность: {throughput:.2f} шагов/сек»)

В результате этой оптимизации пропускная способность составляет 6,44 шага в секунду — улучшение на 9% по сравнению с нашим предыдущим экспериментом. Отметим, что влияние этой оптимизации ограничено длительностью более длительного из двух типов операций. В нашем предыдущем профилировании блок памяти занимал 15,5 миллисекунд, а блок ядра — 155 миллисекунд. В текущем профилировании все шаги на графическом процессоре занимают 155 миллисекунд, что означает, что время копирования памяти полностью перекрывается временем вычислений ядра, и наша оптимизация достигает максимально возможного результата.

Использование потоков CUDA и его влияние на загрузку графического процессора можно увидеть в трассировках обоих профилировщиков:

42cf0ac19153ec1e4b551c071a6bb0e5
c25904a3afa6e4411c5a68f7a9ee8413

Оптимизация 4: Предварительная выборка данных в CUDA

На заключительном этапе мы переносим копирование данных из основного цикла обучения в процесс загрузки данных: вместо явного вызова функции копирования внутри цикла обучения мы предполагаем, что пакеты данных, возвращаемые итератором данных, уже размещены на графическом процессоре.

В приведенном ниже блоке кода мы оборачиваем наш загрузчик данных классом итератора предварительной выборки CUDA. Обратите внимание, что это упрощенная реализация, предназначенная для демонстрационных целей. Для более сложных сценариев (например, обучения DDP) может потребоваться дополнительная работа. В качестве альтернативы вы можете рассмотреть стороннюю реализацию, такую как torchtnt.utils.data.data_prefetcher.CudaDataPrefetcher:

class DataPrefetcher: def __init__(self, loader): self.loader = iter(loader) self.stream = torch.cuda.Stream() self.next_batch = None self.preload() def preload(self): try: data, targets = next(self.loader) with torch.cuda.stream(self.stream): with nvtx.annotate(«copy batch», color=»yellow»): next_data = data.to(DEVICE, non_blocking=True) next_targets = targets.to(DEVICE, non_blocking=True) self.next_batch = (next_data, next_targets) except: self.next_batch = (None, None) def __iter__(self): return self def __next__(self): torch.cuda.current_stream().wait_stream(self.stream) data, targets = self.next_batch self.preload() return data, targets data_iter = DataPrefetcher(train_loader) for i in range(TOTAL_STEPS): if i == WARMUP_STEPS: torch.cuda.synchronize() start_time = time.perf_counter() profiler.start() elif i == WARMUP_STEPS + PROFILE_STEPS: torch.cuda.synchronize() profiler.stop() end_time = time.perf_counter() with nvtx.annotate(f»Batch {i}», color=»blue»): with nvtx.annotate(«get batch», color=»red»): batch = next(data_iter) with nvtx.annotate(«Compute», color=»green»): loss = compute_step(model, batch, optimizer) total_time = end_time — start_time throughput = PROFILE_STEPS / total_time print(f»Пропускная способность: {throughput:.2f} шагов/сек»)

В результате этой оптимизации пропускная способность составляет 6,44 шага в секунду — столько же, сколько и в нашем предыдущем эксперименте. Это не должно нас удивлять, поскольку мы уже видели, что пропускная способность ограничена временем вычислений на графическом процессоре (155 миллисекунд), и наша оптимизация никак не повлияла на сокращение времени вычислений ядра.

В более общем плане, несмотря на удаление вызова копирования из основного цикла, вам будет сложно найти ситуацию, в которой это окажет существенное влияние на производительность, поскольку вызов и так выполняется асинхронно. Однако, учитывая минимальные изменения в цикле обучения, вы можете обнаружить, что это решение является более чистым и/или более применимым для использования с высокоуровневыми библиотеками, которые не позволяют осуществлять тонкое управление циклом обучения.

Как и ожидалось, результаты профилирования для этого эксперимента практически идентичны результатам предыдущих. Главное отличие заключается в расположении желтого блока «копирование данных» в строке NVTX раздела ЦП.

37a9492253e201da14c3f6af68499a69
a2cf1dd19fc709aaa3f49e09420df661

Результаты

В таблице ниже приведены результаты наших экспериментов:

1a351c1a1e853fe480d3f7bdfea974b5

Оптимизация, достигнутая с помощью профилировщика Nsight Systems, привела к общему увеличению производительности во время выполнения в 2,17 раза.

Краткое содержание

Проблема нехватки ресурсов графического процессора (GPU starvation) — распространённое узкое место в производительности, которое может оказать разрушительное воздействие на эффективность и стоимость рабочих нагрузок в области искусственного интеллекта и машинного обучения. В этой статье мы продемонстрировали, как использовать профилировщик Nsight Systems для изучения причин узкого места в производительности и принятия обоснованных мер по его устранению. Попутно мы подчеркнули уникальные возможности профилировщика Nsight Systems по сравнению со встроенным профилировщиком PyTorch, ориентированным на фреймворки, — в частности, его глубокую системную видимость.

В этой статье мы сосредоточились на копировании данных с хоста на устройство, которое обычно происходит в начале этапа обучения. Однако на разных этапах обучения могут возникать проблемы с передачей данных. В продолжении этой статьи мы планируем повторить наш анализ профилирования nsys для копирования данных в обратном направлении — с устройства на хост. Следите за обновлениями!

Источник: towardsdatascience.com

✅ Найденные теги: Данных, машинное обучение, новости, Оптимизация, передача, Рабочие Нагрузки

ОСТАВЬТЕ СВОЙ КОММЕНТАРИЙ

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

Фото сгенерированных лиц: исследование показывает, что люди не могут отличить настоящие лица от сгенерированных
Нейросети построили капитализм за трое суток: 100 агентов Claude заперли…
Скетч: цифровой осьминог и виртуальный мир внутри компьютера с человечком.
Сцена с жестами пальцами, где один жест символизирует "VPN", а другой "KHP".
‼️Paramount купила Warner Bros. Discovery — сумма сделки составила безумные…
Скриншот репозитория GitHub "Claude Scientific Skills" AI для научных исследований.
Структура эффективного запроса Claude с элементами задачи, контекста и референса.
Эскиз и готовая веб-страница платформы для AI-дизайна в современном темном режиме.
ideipro logotyp
Image Not Found
Звёздное небо с галактиками и туманностями, космос, Вселенная, астрофотография.

Система оповещения обсерватории Рубина отправила 800 000 сигналов в первую ночь наблюдений.

Астрономы будут получать оповещения о небесных явлениях в течение нескольких минут после их обнаружения. Теренс О'Брайен, редактор раздела «Выходные». Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной…

Мар 2, 2026
Женщина с длинными тёмными волосами в синем свете, нейтральный фон.

Расследование в отношении 61-фунтовой машины, которая «пожирает» пластик и выплевывает кирпичи.

Обзор компактного пресса для мягкого пластика Clear Drop — и что будет дальше. Шон Холлистер, старший редактор Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной странице вашего…

Мар 2, 2026
Черный углеродное волокно с текстурой плетения, отражающий свет.

Материал будущего: как работает «бессмертный» композит

Учёные из Университета штата Северная Каролина представили композит нового поколения, способный самостоятельно восстанавливаться после серьёзных повреждений.  Речь идёт о модифицированном армированном волокном полимере (FRP), который не просто сохраняет прочность при малом весе, но и способен «залечивать» внутренние…

Мар 2, 2026
Круглый экран с изображением замка и горы, рядом электронная плата.

Круглый дисплей Waveshare для креативных проектов

Круглый 7-дюймовый сенсорный дисплей от Waveshare создан для разработчиков и дизайнеров, которым нужен нестандартный экран.  Это IPS-панель с разрешением 1 080×1 080 пикселей, поддержкой 10-точечного ёмкостного сенсора, оптической склейкой и защитным закалённым стеклом, выполненная в круглом форм-факторе.…

Мар 2, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых