Поиск по сайту Поиск

Как начать работу с Keras, Deep Learning и Python

Специально для тех, кто только начинает осваивать Deep Learning и нейронные сети, мы подготовили перевод очень полезной статьи. Из неё вы узнаете, как использовать библиотеку Keras для обучения своей первой нейронной сети с собственным набором изображений, а также сможете создать свёрточную нейронную сеть (CNN).

Большинство учебных пособий по Keras основаны на работе со стандартными датасетами, такими как MNIST (распознавание рукописного ввода цифр) или CIFAR-10 (распознавание базовых объектов). Они помогут вам начать использовать Keras, но не смогут научить работать с собственными наборами изображений — вы просто будете вызывать вспомогательные функции для загрузки предварительно скомпилированных датасетов.

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

Введение

Статья предполагает пошаговое выполнение фрагментов кода, для чего понадобится компилятор Python или среда Jupyter Notebook.

Здесь мы не будем подробно рассматривать теорию Deep Learning. Этой теме посвящено большое количество литературы, например, книга Deep Learning for Computer Vision with Python.

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

Наш набор данных

В этом разделе мы определимся с методикой подготовки данных и обсудим структуру проекта.

Никаких CIFAR10 и MNIST!

Для начала отметим, что MNIST и CIFAR-10 представляют собой не самые интересные примеры. Вы не научитесь работать со своими данными, а будете пользоваться встроенными утилитами Keras, которые волшебным образом превращают датасеты MNIST и CIFAR-10 в массивы NumPy. Даже обучающую и тестовую выборку уже сделали за вас!

А если вы захотите использовать собственные изображения, то, скорее всего, не зная, с чего начать, будете задавать себе следующие вопросы:

— откуда эти вспомогательные функции загружают данные?

— в каком формате должны быть изображения на диске?

— как загрузить мой датасет в память?

— какую предварительную обработку необходимо выполнить?

Без паники. Сейчас мы во всём разберёмся.

Для начала, возьмём готовый датасет с животными, состоящий из фотографий собак, кошек и панд.

Цель — правильно классифицировать изображение как содержащее кота, собаку или панду.

Набор содержит 3000 изображений и послужит первоначальным материалом, с помощью которого мы сможем быстро обучить DL модель, используя CPU или GPU, и при этом получить разумную точность.

В процессе работы с этим датасетом вы сможете понять, как выполнить следующие действия:

— упорядочить свой набор изображений на диске;

— загрузить изображения и метки класса с диска;

— разделить данные на обучающую и тестовую выборки;

— обучить вашу первую нейросеть Keras;

— оценить вашу модель на тестовой выборке;

— использовать свою обученную модель в дальнейшем на совершенно новых данных.

Если вы хотите создать набор данных из доступных в Интернете изображений, то сделать это можно простым способом с помощью поиска картинок Bing или чуть более сложным способом с помощью поисковика Google.

Структура проекта

Распаковав zip-архив к статье, вы получите следующую структуру файлов и папок:

Как упоминалось ранее, мы работаем с датасетом Animals. Обратите внимание, как он расположен в дереве проекта. Внутри animals/ находятся каталоги трёх классов: cats/dogs/panda/. В каждом из них содержится 1000 изображений, относящихся к соответствующему классу.

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

Далее идёт каталог images/. Он содержит три изображения для тестирования модели, которые мы будем использовать, чтобы продемонстрировать, как:

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

Папка output/ содержит три типа файлов, которые создаются путём обучения:

— .model: сериализованный файл модели Keras, создаётся после обучения и может использоваться в дальнейших сценариях вывода.

.pickle: сериализованный файл бинаризатора меток. Включает в себя объект, содержащий имена классов и сопряжён с файлом модели.

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

Каталог pyimagesearch/ — модуль, который находится в папке проекта. Содержащиеся в нём классы могут быть импортированы в ваши сценарии.

В статье мы рассмотрим 4 .py файла. Начнём с обучения простой модели с помощью скрипта train_simple_nn.py. Далее перейдём к обучению SmallVGGNet, используя скрипт train_vgg.py. SmallVGGNet.py содержит класс SmallVGGNet (свёрточную нейронную сеть). Но что хорошего в сериализованной модели, если мы не можем её применить? В predict.py находится образец кода для загрузки модели и файла метки для распознавания изображений. Этот скрипт понадобится только после того, как мы успешно обучим модель с достаточной точностью. Всегда полезно запускать его для проверки модели на изображениях, которые не содержатся в исходных данных.

1. Установка Keras

Для работы над проектом нам понадобится установить Keras, TensorFlow и OpenCV.

Если у вас ещё нет этого ПО, можете воспользоваться простыми руководствами по установке:

руководство по установке OpenCV (для Ubuntu, MacOS или Raspberry Pi).

установка Keras с TensorFlow. С помощью pip вы можете установить Keras и TensorFlow меньше, чем за две минуты. Ваш компьютер или устройство должно быть достаточно производительным. Поэтому  не рекомендуются устанавливать эти пакеты на Raspberry Pi, хотя на таком миникомпьютере могут хорошо работать уже обученные и не слишком объёмные модели.

— установка imutil, scikit-learn и matplotlib:

2. Загрузка данных с диска

Теперь, когда Keras установлен в нашей системе, мы можем приступить к реализации первого простого сценария обучения нейронной сети с использованием Keras. Позже мы реализуем полноценную свёрточную нейронную сеть, но давайте по порядку.

Откройте файл train_simple_nn.py и вставьте в него следующий код:

Рассмотрим инструменты, используемые в скрипте:

matplotlib: готовый пакет для Python. В строке 3 мы подключаем бэкенд “Agg”, который позволяет сохранять графики на диск.

sklearn: библиотека scikit-learn поможет бинаризовать наши метки, разделить данные на обучающую и тестовую выборки и сгенерировать отчёт об обучении в терминале.

keras: высокоуровневый фронтенд для TensorFlow и других бэкендов глубокого обучения.

— imutils: пакет с удобными функциями, модуль path будет использоваться для генерации списка путей к файлам изображений.

numpy: пакет для работы с числами в Python. Если у вас установлен OpenCV и scikit-learn, то у вас уже есть NumPy как зависимый от них пакет.

cv2: это OpenCV. На данный момент необходимо будет использовать версию 2, даже если обычно вы используете OpenCV 3 или выше.

Всё остальное уже встроено в ваш Python.

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

Давайте разберём аргументы командной строки с помощью argparse:

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

У нас есть 4 аргумента командной строки:

--dataset: путь к набору изображений на диске.

--model: наша модель будет сериализована и записана на диск. Этот аргумент содержит путь к выходному файлу модели.

--label-bin: метки набора данных сериализуются на диск для возможности их вызова в других скриптах. Это путь к выходному бинаризованному файлу метки.

--plot: путь к выходному файлу графика обучения. Мы рассмотрим этот график, чтобы проверить недообучение или переобучение наших данных.

Имея информацию о наборе данных, давайте загрузим изображения и метки классов:

Здесь мы:

  1. Инициализируем списки для наших данных (data) и меток (labels) (строки 35 и 36). Позже это будут массивы NumPy.
  2. Случайным образом перемешиваем imagePaths (строки 39-41). Функция paths.list_images найдёт пути ко всем входным изображениям в каталоге нашего датасета перед тем, как мы отсортируем и перемешаем (shuffle) их. Установим константное значение seed так, чтобы случайное переупорядочивание было воспроизводимым.
  3. Начинаем цикл по всем imagePaths в наборе данных (строка 44).

Для каждого imagePath:

а) Загружаем изображение image в память (строка 48).

б) Изменяем его размер на 32x32 пикселя (без учёта соотношения сторон) и сглаживаем (flatten) (строка 49). Очень важно правильно изменить размер изображений (resize), поскольку это необходимо для данной нейронной сети. Каждая нейросеть требует различного разрешения изображений, поэтому просто помните об этом. Сглаживание данных позволяет легко передавать необработанные интенсивности пикселей в нейроны входного слоя. Позже вы увидите, что для VGGNet мы будем передавать в сеть сразу все данные, поскольку она является свёрточной. Но в этом примере пока рассматривается простая несвёрточная сеть.

в) Добавляем изменённое изображение к массиву данных (строка 50).

г) Извлекаем метку класса изображения из его пути (строка 54) и добавляем к остальным меткам (строка 55). Список меток содержит классы, соответствующие каждому изображению в массиве данных.

Теперь мы легко можем применить операции с массивами к нашим данным и меткам:

В строке 58 мы отображаем интенсивность пикселя из диапазона целых чисел [0, 255] в непрерывный вещественный диапазон [0, 1] (обычный этап предварительной обработки).

Также конвертируем метки в массив NumPy (строка 59).

3. Создание обучающей и тестовой выборок

Теперь, когда мы загрузили данные с диска, нужно разделить их на обучающую и тестовую выборки:

Обычно большая часть данных выделяется для обучения, и около 20-30% для тестирования. Scikit-learn предоставляет удобную функцию train_test_split, которая разделит для нас данные.

trainX и testX — это изображения, а trainY и testY — соответствующие метки.

Наши метки классов сейчас представлены в виде строк, однако Keras будет считать, что:

  1. Метки кодируются целыми числами.
  2. Для этих меток выполняется One-Hot Encoding, в результате чего каждая метка представляется в виде вектора, а не целого числа.

Для того чтобы выполнить эту кодировку, можно использовать класс LabelBinarizer из scikit-learn:

В строке 70 мы инициализируем объект LabelBinarizer.

Вызов fit_transform находит все уникальные метки класса в testY, а затем преобразует их в метки One-Hot Encoding.

Вызов .transform выполняет всего один шаг One-Hot Encoding — уникальный набор возможных меток классов уже был определён вызовом fit_transform.

Пример:

4. Определение архитектуры модели Keras

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

Поскольку наша модель очень простая, мы определим её прямо в этом сценарии (обычно для архитектуры модели приходится создавать отдельный класс).

Входной слой и первый скрытый слой определены в строке 76. input_shape будет равен 3072, так как мы имеем 32x32x3=3072 пикселей в сглаженном входном изображении. Первый скрытый слой будет иметь 1024 узла.

Второй скрытый слой имеет 512 узлов (строка 77).

И, наконец, количество узлов выходного слоя (строка 78) будет равно числу возможных меток классов — в нашем случае, выходной слой будет иметь три узла, один для каждой метки класса (“cats”, “dogs”, и “panda” соответственно).

5. Компиляция модели

После того как мы определили архитектуру нашей нейронной сети, нам необходимо скомпилировать её:

Сначала мы инициализируем скорость обучения и общее число эпох (полных проходов по выборке) (строки 81 и 82).

Затем мы скомпилируем модель, используя метод стохастического градиентного спуска (SGD) и  "categorical_crossentropy" (категориальную кросс-энтропию) в качестве функции потерь.

Категориальная кросс-энтропия используется почти для всех нейросетей, обученных выполнять классификацию. Единственное исключение — когда имеется только два класса и две возможные метки. В этом случае используется бинарная кросс-энтропия ("binary_crossentropy").

6. Обучение модели

Теперь, когда наша модель Keras скомпилирована, мы можем “подогнать” (fit) (т.е. обучить) её:

Здесь нам известно обо всём, кроме batch_size (размер пакета). Параметр batch_size контролирует размер каждой группы данных для передачи по сети. Мощные GPU могут обрабатывать большие пакеты, но рекомендуется отталкиваться от размеров 32 и 64.

7. Оценка модели

Мы обучили модель, теперь нужно оценить её с помощью тестовой выборки.

Оценка модели очень важна, поскольку необходимо получить непредвзятое (или как можно более близкое к непредвзятому) представление о том, насколько хорошо наша модель работает с данными, на которых она никогда не обучалась.

Для оценки модели Keras можно использовать комбинацию методов .predict и classification_report из scikit-learn:

Запустив этот скрипт, вы увидите, что нейронная сеть начала обучаться, и теперь мы можем оценить модель на тестовых данных:

Поскольку сеть небольшая (как и набор данных), этот процесс в среднем занимает около двух секунд.

Можно увидеть, что наша нейросеть точна на 61%.

Так как шанс случайного выбора правильной метки для изображения равен 1/3, мы можем утверждать, что сеть фактически выучила шаблоны, которые могут использоваться для различения трёх классов.

Также мы сохранили следующие графики:

— потери при обучении

— потери при оценке

— точность обучения

— точность оценивания

С их помощью мы можем определить переобучение или недообучение модели.

Глядя на график, можно увидеть небольшое переобучение, начинающееся после шага ~45, когда между потерями при обучении и оценке появляется явный разрыв.

Наконец, мы можем сохранить нашу модель на диск, чтобы позже использовать её, не занимаясь обучением снова:

8. Распознавание изображений с использованием обученной модели

Сейчас наша модель обучена — но что, если нам снова понадобится классифицировать новые изображения? Как загрузить модель с диска? Как обработать изображение для классификации?Для начала откроем скрипт predict.py и вставим туда следующий код:

Сначала мы импортируем необходимые пакеты и модули.

load_model позволяет загрузить модель Keras с диска. OpenCV будет использоваться для вывода изображений. Модуль pickle загружает бинаризатор меток.

Далее снова разберём аргументы командной строки:

--image: путь к входному изображению.

--model: путь к нашей обученной и сериализованной модели.

--label-bin: путь к бинаризатору меток.

--width: ширина изображения для CNN. Помните, что вы не можете просто указать тут что-нибудь. Вам необходимо указать ширину, для которой предназначена модель.

--height: высота входного изображения. Также должна соответствовать конкретной модели.

--flatten: надо ли сглаживать изображение (по умолчанию мы не будем этого делать).

Загрузим изображение и изменим его размер, исходя из аргументов командной строки:

Если необходимо, изображение можно сгладить:

В случае с CNN мы указываем размер пакета, но не выполняем сглаживание (строки 39-41). Пример с CNN рассматривается в следующем разделе.

Теперь загрузим нашу модель и бинаризатор меток в память и попробуем распознать изображение:

Модель и бинаризатор загружаются в строках 45 и 46.

Распознавание изображений (прогнозирование принадлежности объекта к одному из классов) осуществляется с помощью метода model.predict  (строка 49).

Как же выглядит массив preds?

Двумерный массив содержит (1) индекс изображения в пакете (здесь он только один, поскольку было передано одно изображение) и (2) проценты, соответствующие возможной принадлежности изображения к каждой метке класса:

— cats: 54.6%

— dogs: 45.4%

— panda: ~0%

То есть  наша нейросеть «думает», что, вероятнее всего, видит кошку, и определённо не видит панду.

В строке 53 мы находим индекс наибольшего значения (в данном случае нулевой).

И в строке 54 извлекаем строковую метку “cats” из бинаризатора меток.

Легко, правда?

Теперь отобразим результаты:

Мы форматируем текстовый вывод в строке 57 (метку класса и прогнозируемое значение в процентах).

Затем помещаем текст на выходное изображение (строки 58 и 59).

Наконец, выводим картинку на экран и ждём, пока пользователь не нажмёт какую-либо клавишу (строки 62 и 63).

Наш скрипт для распознавания изображений оказался довольно простым.

Теперь вы можете открыть терминал и попробовать запустить обученную нейросеть на собственных снимках:

Убедитесь, что вы скопировали/вставили команду целиком (включая аргументы командной строки) из папки со скриптом.

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


Примечание:

Обратите внимание, что полученные вами результаты могут отличаться от приведённых в этой статье. Скорее всего, это происходит из-за того, что процесс обучения каждый раз может проходить по-разному даже на одних и тех же исходных данных. Например, в нашем эксперименте точность нейросети снизилась до 60%, и изображение с котом классифицировалось как “dogs” с вероятностью 45.34%. Можете поделиться своими результатами и предположениями, с чем это может быть связано.


9. БОНУС: Обучение свёрточной нейронной сети с Keras

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

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

В этом разделе будет использоваться уменьшенный вариант VGGNet (назовём её “SmallVGGNet”).

VGGNet-подобные модели имеют две общие особенности:

  1. Используются только свёрточные фильтры 3х3
  2. Свёрточные слои (“convolution layers”) чередуются со слоями подвыборки (“pooling layers”).

Приступим к реализации SmallVGGNet.

Откройте файл smallvggnet.py и вставьте туда следующий код:

Как вы могли заметить, всё, что необходимо для SmallVGGNet, импортируется из Keras. С каждым из модулей можно ознакомиться в документации Keras.

Теперь определим наш класс SmallVGGNet (строка 12) и метод сборки (build) (строка 14):

Для сборки требуется 4 параметра: ширина входных изображений (width), высота (height), глубина (depth) и число классов (classes).

Глубина также может интерпретироваться как число каналов. Поскольку мы используем RGB-изображения, то при вызове метода build будем передавать глубину = 3.

Сначала инициализируем последовательную (Sequential) модель (строка 17).

Затем определяем порядок каналов. Keras поддерживает "channels_last" (TensorFlow) и "channels_first" (Theano). Строки 18-25 позволяют использовать любой из них.

Теперь добавим несколько слоёв в сеть:

В этом блоке добавляются слои CONV => RELU => POOL.

Первый слой CONV имеет 32 фильтра размером 3х3.

Важно, чтобы мы указали inputShape для первого слоя, так как все последующие размеры слоёв будут рассчитываться с использованием метода “просачивания” (trickle-down).

В этой архитектуре сети мы будем использовать функцию активации ReLU (Rectified Linear Unit). Также будут использованы: пакетная нормализация (Batch Normalization), функция максимума (MaxPooling) и метод исключения (Dropout).

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

К слоям POOL применяется функция постепенного уменьшения размера (т.е. ширины и высоты) входного слоя. Обычно в архитектуре CNN слои POOL вставляются между последовательно идущими слоями CONV.

Метод исключения деактивирует случайные нейроны между слоями. В результате процесс становится более устойчивым: уменьшается переобучение, повышается точность; и нейросеть лучше сможет распознавать незнакомые изображения. В нашем случае (строка 33) 25% нейронных соединений случайным образом деактивируются между слоями для каждой итерации обучения.

Переходим к следующим слоям:

Обратите внимание, что размеры фильтра остаются прежними (3х3), а общее число фильтров увеличивается с 32 до 64.

Затем идёт набор слоёв (CONV => RELU) * 3 => POOL:

Опять же, число фильтров удвоилось с 64 до 128, а размер остался прежним. Увеличение общего количества фильтров при уменьшении размера входных данных в CNN — обычная практика.

И, наконец, последний набор слоёв:

Полностью связанные слои в Keras обозначаются как Dense. Последний слой соединён с тремя выходами (так как в нашем наборе данных три класса). Слой softmax возвращает вероятность принадлежности к определённому классу для каждой метки.

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

Большая часть кода такая же, как и в предыдущем примере. Откройте скрипт train_vgg.py:

Все import-ы те же, но с двумя отличиями:

  1. Вместо from keras.models import Sequential мы загружаем модель SmallVGGNet: from pyimagesearch.smallvggnet import SmallVGGNet
  2. Данные будут дополняться с помощью ImageDataGenerator.

Теперь аргументы командной строки:

Видим, что аргументы такие же, как и в предыдущем примере.

Загружаем и предварительно обрабатываем данные:

Снова почти никаких отличий.

Разделяем данные на обучающую и тестовую выборки и бинаризуем метки:

Теперь дополняем данные:

В строках 75-77 мы инициализируем генератор для добавления изображений.

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

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

Чтобы собрать нашу SmallVGGNet, просто вызовем метод SmallVGGNet.build в процессе передачи необходимых параметров (строки 80 и 81).

Скомпилируем и обучим модель:

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

Наконец, оценим модель, построив кривые потерь/точности и сохраним её:

Мы делаем прогнозы на тестовой выборке, а затем оцениваем точность классификации (строки 103-105).

Построение и сохранение на диск графиков, модели и меток аналогично предыдущему примеру.

Продолжим обучать нашу модель. Откройте терминал и выполните следующую команду:

Убедитесь, что вы ввели все аргументы командной строки.

Обучение на CPU займёт довольно продолжительное время — каждый из 75 шагов требует более минуты, и процесс будет длиться около полутора часов.

GPU завершит процесс гораздо быстрее — каждый шаг выполняется всего за 2 секунды, как и продемонстрировано.

Посмотрим на итоговый график обучения в каталоге output/:

Как можно увидеть, мы достигли точности в 78% на наборе изображений Animals с использованием свёрточной нейронной сети — значительно выше, чем предыдущее значение в 60%.

Теперь мы можем применить нашу обученную CNN к новым изображениям:

CNN полностью уверена, что это панда.

Алгоритмы CNN используются для поиска изображений, например, в Google Photo, но распознавание и классификация фотографий — не единственный пример использования свёрточных нейросетей: они также хорошо себя показали, например, в задачах обработки естественного языка (Natural Language Processing, NLP).

Исходный код

Код и датасет к статье можно загрузить отсюда (размер архива 246 МБ).

Дерзайте и делитесь своими результатами, а если что-то непонятно — задавайте вопросы в комментариях, мы ответим и поможем разобраться. Также будем рады услышать от вас предложения тем следующих статей — пишите, о чём хотели бы почитать.  

С оригинальной статьёй можно ознакомиться на сайте pyimagesearch.com.

Какие показатели нужно отслеживать новому бизнесу? 10 главных метрик

Полный список финансовых показателей, которые нужно учитывать при запуске и развитии бизнеса. С формулами, комментариями и понятными примерами расчета. (далее…)
Read More

Драма Microsoft и Apple: от вражды до сотрудничества

Техногиганты всё время своего существования судились, обменивались колкостями и пытались обогнать друг друга по уровню новаторства в разработках. Наши коллеги...
Read More

Как компании меняли свой бренд из-за испорченной репутации: три кейса

В бизнесе нет страховки от ошибок — любой промах отражается на репутации. И иногда исправить ситуацию может только ребрендинг и...
Read More

Запускаем email-рассылку: как не попасть в спам при отправке писем

В статье рассказываем, почему рассылки попадают в спам, и делимся советами, как сделать так, чтобы письма всегда доставлялись до адресатов....
Read More

Ключ к успешному продвижению: что такое SMM-стратегия и как ее составить

Разберем, что такое SMM-стратегия, зачем она нужна и как эффективно использовать социальные сети для решения бизнес-задач. (далее…)
Read More

Новогодний маркетинг: лучшие приемы праздничной рекламы

Для бизнеса Новый год и Рождество — время всплеска продаж и увеличения прибыли. А способствуют этому всем знакомые персонажи: от...
Read More

Россияне предпочитают .ru вместо .com, а Дональд Трамп проиграл доменный спор за mar-a-lago.com

Рассказываем самые интересные новости доменного мира. (далее…)
Read More

Прокрастинация: что такое, виды и как бороться

Прокрастинатор полон идей и амбиций, но ему часто не хватает самодисциплины и силы воли, чтобы начать действовать. Что заставляет нас...
Read More

Что нужно покупателям в 2024: 5 трендов электронной коммерции

Ежегодно рынок e-commerce в России растет на треть, а в 2024 году, по прогнозам экспертов, его оборот составит более 7,2...
Read More

Гайд: стильный интернет-магазин на WordPress с помощью двух инструментов

Онлайн-торговля растет на 40-50% в год, поэтому открыть свой интернет-магазин никогда не поздно. Для старта не понадобятся знания HTML и...
Read More