ChatGPT — помощник для программиста? Пример реальной задачи: распознавание квадратов Нейросетью

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Как ни крути, но языковая модель ChatGPT никогда не может полностью заменить программиста, так как только около 1/10 от общего времени процесса разработки занимает написание кода. Однако ChatGPT великолепно помогает в различных аспектах программирования. Чем больше навыков и опыта у программиста, тем больше пользы он может извлечь от "помощника", который может:

  • Производить оптимизацию кода и улучшать производительность.

  • Искать и устранять ошибки в коде.

  • Объяснять сложные концепции и алгоритмы.

  • Помогать в разработке идеи и выборе подходящей архитектуры.

  • Создавать прототипы и демонстрационные версии программ.

  • Давать советы по стилю и лучшим практикам программирования.

  • Автоматизировать повторяющиеся задачи.

  • Генерировать код на основе спецификаций или заданных параметров.

  • Расширять функциональность с помощью плагинов и инструментов.

  • Писать документацию и комментарии к коду.

Сегодня невероятно глупо не использовать возможности ChatGPT. Это действительно универсальный помощник, который существенно облегчает жизнь программиста и повышает эффективность разработки. Такое программирование становится гораздо более приятным и эффективным делом, чем когда-либо раньше.

Помощник для программиста

Возьмем не простой пример, которым завален весь интернет, а возьмем задачу поинтереснее: используя помощника ChatGPT напишем код, который используя нейросеть сможет решать задачу по распознаванию квадратов на картинке.

Спросим нейросеть об этапах создания такого кода:
- Из каких этапов состоит код для распознавания квадратов на картинке с помощью нейросети?

Из каких этапов состоит код для распознавания квадратов на картинке с помощью нейросети?

запрос и ответ ChatGPT
запрос и ответ ChatGPT

Итак, мы получили этапы, которые должны закодировать:

Код для распознавания квадратов на картинке с помощью нейросети обычно состоит из следующих этапов:

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

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

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

  4. Оценка модели: После завершения обучения модели оценивают на тестовой выборке, чтобы оценить ее производительность. Возможны различные метрики, такие как точность, полнота и F-мера, чтобы оценить эффективность распознавания квадратов.

  5. Применение модели: После успешной оценки модель можно применять для распознавания квадратов на новых изображениях. Это включает прогон изображений через модель и получение предсказанных меток или координат квадратов на изображении.

  6. Оптимизация и доработка: При необходимости можно производить оптимизацию модели, включая изменение ее архитектуры, параметров обучения и дополнительную настройку для достижения лучшей производительности.

Начнем последовательно писать код по пунктам.

1. Подготовка данных

Сначала мы должны создать картинки с квадратами (датасет для обучения нейросети), так и пишем ей:

напиши код на python генерации картинок 128х128 с квадратом в центре, разных размеров и разных цветов

генерация картинки
генерация картинки

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

Итак, мы получили код для генерации одной картинки.

from PIL import Image, ImageDraw
import random

# Размеры изображения
image_width = 128
image_height = 128

# Создаем новое изображение
image = Image.new("RGB", (image_width, image_height), "white")
draw = ImageDraw.Draw(image)

# Генерация квадрата
square_size = random.randint(10, 80)  # Случайный размер квадрата от 10 до 80 пикселей
square_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))  # Случайный цвет квадрата

# Координаты квадрата в центре изображения
left = (image_width - square_size) // 2
top = (image_height - square_size) // 2
right = left + square_size
bottom = top + square_size

# Рисуем квадрат
draw.rectangle([left, top, right, bottom], fill=square_color)

# Сохраняем изображение
image.save("generated_image.png")

Запуск этого кода генерит такую картинку:

ChatGPT создал одну картинку
ChatGPT создал одну картинку

Круто! Но нам нужен датасет для обучения будущей нейросети, поэтому изменим код сами - добавив цикл, или попросим сделать это нейросеть ChatGPT:

Делаем новый запрос:

измени код выше добавив в него цикл для генерации 100 изображений, которые должны сохраняться в подкаталог "boxes" каталога "training_dataset" с именами картинок генерирующихся циклом от 0 до 100 с расширением png

Получаем ответ:

from PIL import Image, ImageDraw
import random
import os

# Размеры изображения
image_width = 128
image_height = 128

# Создаем директорию для сохранения изображений
output_dir = "training_dataset/boxes"
os.makedirs(output_dir, exist_ok=True)

# Цикл для генерации 100 изображений
for i in range(100):
    # Создаем новое изображение
    image = Image.new("RGB", (image_width, image_height), "white")
    draw = ImageDraw.Draw(image)

    # Генерация квадрата
    square_size = random.randint(10, 80)  # Случайный размер квадрата от 10 до 80 пикселей
    square_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))  # Случайный цвет квадрата

    # Координаты квадрата в центре изображения
    left = (image_width - square_size) // 2
    top = (image_height - square_size) // 2
    right = left + square_size
    bottom = top + square_size

    # Рисуем квадрат
    draw.rectangle([left, top, right, bottom], fill=square_color)

    # Сохраняем изображение
    image_name = f"image_{i}.png"
    image_path = os.path.join(output_dir, image_name)
    image.save(image_path)

Ответ ChatGPT: В этом обновленном коде добавлен цикл, который выполняется 100 раз, генерируя 100 изображений с квадратами разных размеров и цветов. Изображения сохраняются в подкаталог "boxes" внутри каталога "training_dataset". Имена файлов генерируются в формате "image_0.png", "image_1.png" и так далее, в зависимости от номера итерации цикла.

Я уже в шоке! Вот результат запуска кода:

датасет создан ChatGPT
датасет создан ChatGPT

Теперь у нас есть загруженные(сгенерированные) изображения, преобразованные в формат совместимый с нейросетью - т.е. в формате png (можно использовать другой формат) и все одинакового размера с нужными нам объектами, причем все они сохранены в каталог training_dataset/boxes. Причем эти каталоги создаются автоматом, если их нет.

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

используя библиотеку tensorflow напиши команды для загрузки этих изображений из каталога "training_dataset" для обучающей и тестовой выборки

P.S. почему я указал каталог "training_dataset", а не каталог "training_dataset/boxes"?
- Т.к. каталог boxes - фактически играет роль маркера одного класса картинок находящихся в нем.

# pip install "tensorflow<2.11"
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# Путь к каталогу с изображениями
image_dir = "training_dataset"

# Создание генератора изображений для обучающей выборки
train_data_gen = ImageDataGenerator(rescale=1./255, validation_split=0.2)

# Загрузка обучающей выборки
train_generator = train_data_gen.flow_from_directory(
    image_dir,
    target_size=(128, 128),
    batch_size=32,
    class_mode=None,
    subset="training"
)

# Загрузка валидационной выборки
validation_generator = train_data_gen.flow_from_directory(
    image_dir,
    target_size=(128, 128),
    batch_size=32,
    class_mode=None,
    subset="validation"
)

Запускаем код:

загрузка картинок для обучающей и валидационной выборки для нейросети
загрузка картинок для обучающей и валидационной выборки для нейросети

Видим, что успешно загрузили картинки класса boxes, из них 80 отдали обучающей выборке и 20 для проверочного набора.

Немного поправим код, добавим перемешивание наших картинок:

добавь в код выше перемешивание картинок

Нейросеть взяла и кардинально поменяла код, выдав такой результат:

Вот обновленный код с перемешиванием изображений в каждой эпохе для обучающей выборки:

import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import numpy as np

# Путь к каталогу с изображениями
image_dir = "training_dataset/boxes"

# Загрузка изображений в виде массива numpy
images = tf.keras.preprocessing.image_dataset_from_directory(
    image_dir,
    image_size=(128, 128),
    batch_size=32,
    shuffle=True,
    seed=42,
    validation_split=0.2,
    subset="training"
)

# Перемешивание данных
images = images.unbatch()
images = np.array([img for img, _ in images])
np.random.shuffle(images)

# Разделение на обучающую и валидационную выборки
train_size = int(0.8 * len(images))
train_images = images[:train_size]
val_images = images[train_size:]

В этом обновленном коде мы используем функцию image_dataset_from_directory из TensorFlow для загрузки изображений в виде набора данных. Мы устанавливаем параметр shuffle=True, чтобы перемешать изображения в каждой эпохе. Параметр seed=42 используется для фиксации случайного перемешивания, чтобы результат был воспроизводимым.

Затем мы преобразуем набор данных в отдельные изображения, чтобы выполнить перемешивание вручную. Мы используем функцию unbatch для этого. После этого мы перемешиваем массив изображений с помощью np.random.shuffle.

Наконец, мы разделяем перемешанный массив на обучающую и валидационную выборки, используя индекс train_size. В результате у нас будет переменная train_images, содержащая обучающие изображения, и переменная val_images, содержащая валидационные изображения.

Причем код рабочий, вот результат его выполнения:

нейросеть переписала код...
нейросеть переписала код...

Считаю, что нужно сделать более логично, такой командой:

используя библиотеку tensorflow напиши команды для загрузки этих изображений из каталога "training_dataset" для обучающей и тестовой выборки, не используя numpy, с перемешиванием изображений в обучающей и тестовой выборке

Получаем упрощенный ответ:

Вот пример кода для загрузки изображений из каталога "training_dataset/boxes" в TensorFlow для обучающей и тестовой выборки с перемешиванием:

import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# Путь к каталогу с изображениями
image_dir = "training_dataset/boxes"

# Создание генератора изображений для обучающей и тестовой выборки
data_gen = ImageDataGenerator(rescale=1./255, validation_split=0.2)

# Загрузка обучающей выборки
train_data = data_gen.flow_from_directory(
    image_dir,
    target_size=(128, 128),
    batch_size=32,
    class_mode=None,
    subset="training",
    shuffle=True,
    seed=42
)

# Загрузка тестовой выборки
test_data = data_gen.flow_from_directory(
    image_dir,
    target_size=(128, 128),
    batch_size=32,
    class_mode=None,
    subset="validation",
    shuffle=True,
    seed=42
)

В этом коде мы используем ImageDataGenerator для создания генератора изображений. Опция rescale=1./255 выполняет масштабирование значений пикселей в диапазоне от 0 до 1. Опция validation_split=0.2 указывает, что 20% данных будет использоваться для валидации.

Затем мы используем метод flow_from_directory для загрузки изображений из каталога. Мы указываем target_size=(128, 128), чтобы изменить размер изображений до 128x128 пикселей. batch_size определяет размер пакета данных, а class_mode=None указывает, что у нас нет категориальных меток для классификации.

Обучающая и тестовая выборки загружаются с помощью subset="training" и subset="validation" соответственно. Параметры shuffle=True и seed=42 используются для перемешивания данных в обеих выборках. Это гарантирует, что изображения будут перемешаны одинаковым образом в каждой выборке при повторном запуске кода.

Такой код меня уже устраивает, но нужно проверить, поэтому его запускаем:

заново переписанный и упрощенный код нейросетью
заново переписанный и упрощенный код нейросетью

Теперь Ок, можем двигаться дальше.

2. Создание модели нейросети

Пишем запрос)) пока практически всё сделали за нас...

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

Получаем ответ:

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

import tensorflow as tf

# Создание модели нейросети
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

# Компиляция модели
model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

# Обучение модели
model.fit(train_data, epochs=10, validation_data=test_data)

В этом коде мы используем модуль tf.keras для создания модели нейросети. Мы определяем модель как последовательную сеть с несколькими сверточными слоями и плотными слоями.

В нашем примере, мы используем три сверточных слоя Conv2D с активацией relu и пулингом MaxPooling2D для уменьшения размерности данных. Затем мы выпрямляем данные с помощью слоя Flatten и добавляем два плотных слоя Dense с активацией relu. Наконец, мы добавляем выходной слой Dense с активацией sigmoid, так как мы хотим решить задачу бинарной классификации - определение присутствия или отсутствия квадрата.

Модель компилируется с оптимизатором adam, функцией потерь binary_crossentropy для бинарной классификации и метрикой accuracy для оценки производительности модели.

Затем мы обучаем модель с помощью метода fit, используя обучающую выборку train_data и валидационную выборку test_data из предыдущего кода. Мы указываем epochs=10, чтобы обучение выполнилось в течение 10 эпох.

Запустим код, добавив в него из прошлого кода загрузку обучающей и валидационной выборки:

Наконец-то получаем ошибку: ValueError: Target data is missing. Your model was compiled with loss=binary_crossentropy, and therefore expects target data to be provided in fit().

Спросим об этом нейросеть:

исправь ошибку ValueError: Target data is missing. Your model was compiled with loss=binary_crossentropy, and therefore expects target data to be provided in `fit()`

её ответ:

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

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

import tensorflow as tf

# Создание модели нейросети
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

# Компиляция модели
model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

# Создание целевых данных для обучающей выборки
train_labels = tf.concat([tf.ones((len(train_data.filepaths))), tf.zeros((len(train_data.filepaths)))], axis=0)

# Создание целевых данных для тестовой выборки
test_labels = tf.concat([tf.ones((len(test_data.filepaths))), tf.zeros((len(test_data.filepaths)))], axis=0)

# Обучение модели
model.fit(train_data, train_labels, epochs=10, validation_data=(test_data, test_labels))

В этом обновленном коде мы создаем метки целевых данных для обучающей и тестовой выборок. Мы используем функцию tf.concat для объединения тензоров из единиц (положительные примеры) и нулей (отрицательные примеры) в соответствующих пропорциях. Затем мы передаем эти метки целевых данных в метод fit вместе с обучающей и тестовой выборками для выполнения обучения модели.

Теперь модель будет корректно обучаться на задаче бинарной классификации для распознавания квадратов.

Запускаем и проверяем!

Опять ошибка: ValueError: y argument is not supported when using keras.utils.Sequence as input.

ValueError: y argument is not supported when using keras.utils.Sequence as input.
ValueError: y argument is not supported when using keras.utils.Sequence as input.

Давайте и эту ошибку исправим с помощью ChatGPT:

исправь ошибку ValueError: `y` argument is not supported when using `keras.utils.Sequence` as input.

Получаем ответ и новый код:

При использовании объекта ImageDataGenerator.flow_from_directory с параметром class_mode=None, модель ожидает, что данные будут представлены в виде генератора типа keras.utils.Sequence, а не массива.

Для решения этой проблемы, мы можем создать собственный класс-последовательность (sequence) для предоставления данных модели. Вот исправленный код:

import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.utils import Sequence
import numpy as np

# Путь к каталогу с изображениями
image_dir = "training_dataset/boxes"

# Создаем собственный класс-последовательность (Sequence)
class ImageSequence(Sequence):
    def __init__(self, image_dir, batch_size, shuffle=True):
        self.image_generator = ImageDataGenerator(rescale=1./255, validation_split=0.2)
        self.image_data = self.image_generator.flow_from_directory(
            image_dir,
            target_size=(128, 128),
            batch_size=batch_size,
            class_mode='binary',
            subset="training",
            shuffle=shuffle,
            seed=42
        )
        self.batch_size = batch_size

    def __len__(self):
        return len(self.image_data)

    def __getitem__(self, idx):
        batch_x, batch_y = self.image_data[idx]
        return batch_x, batch_y

# Создание обучающей и тестовой последовательностей
train_seq = ImageSequence(image_dir, batch_size=32)
test_seq = ImageSequence(image_dir, batch_size=32, shuffle=False)

# Создание модели нейросети
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

# Компиляция модели
model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

# Обучение модели
model.fit(train_seq, epochs=10, validation_data=test_seq)

В этом коде мы создаем класс ImageSequence, который наследуется от Sequence. В методе __getitem__ мы возвращаем пакеты данных и меток целевых данных. В методе __len__ мы возвращаем общее количество пакетов данных.

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

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

Обратите внимание какие везде логические объяснения, хотя прошлый код мы могли исправить вот здесь закомментировав строки запрещающие "класс".

исправление ошибки вручную
исправление ошибки вручную

Ок, давайте запустим итоговый код, который создала нейросеть:

Вот он момент истины:

Код получился условно "рабочий", т.к. код датасеты генерит +1, делит и загружает обучающие выборки +1, модель создает +1, обучает +1 - НО модель не сходится -1 ! т.е. идет переобучение модели и поэтому такая модель не особо пригодна.

Следовательно нам уже нужно "руками" доработать только модель нейросети.

Или )) попросить ChatGPT сделать это:

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

Вот ответ:

Чтобы бороться с проблемой переобучения и улучшить обобщающую способность модели, можно применить следующие изменения в коде:

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

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

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

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

  5. Увеличить количество эпох обучения для длительного обучения модели.

Вот обновленный код, учитывающий эти изменения:

import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.regularizers import l2

# Путь к каталогу с изображениями
image_dir = "training_dataset"

# Создаем собственный класс-последовательность (Sequence)
class ImageSequence(tf.keras.utils.Sequence):
    def __init__(self, image_dir, batch_size, shuffle=True):
        self.image_generator = ImageDataGenerator(rescale=1./255, validation_split=0.2)
        self.image_data = self.image_generator.flow_from_directory(
            image_dir,
            target_size=(128, 128),
            batch_size=batch_size,
            class_mode='binary',
            subset="training",
            shuffle=shuffle,
            seed=42
        )
        self.batch_size = batch_size

    def __len__(self):
        return len(self.image_data)

    def __getitem__(self, idx):
        batch_x, batch_y = self.image_data[idx]
        return batch_x, batch_y

# Создание обучающей и тестовой последовательностей
train_seq = ImageSequence(image_dir, batch_size=32)
test_seq = ImageSequence(image_dir, batch_size=32, shuffle=False)

# Создание модели нейросети
model = tf.keras.models.Sequential([
    Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
    MaxPooling2D((2, 2)),
    Dropout(0.25),
    Conv2D(64, (3, 3), activation='relu'),
    MaxPooling2D((2, 2)),
    Dropout(0.25),
    Conv2D(128, (3, 3), activation='relu'),
    MaxPooling2D(2, 2),
    Dropout(0.25),
    Flatten(),
    Dense(128, activation='relu', kernel_regularizer=l2(0.001)),
    Dropout(0.5),
    Dense(1, activation='sigmoid')
])

# Compilation
model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

# Training
model.fit(train_seq, epochs=20, validation_data=test_seq)

# Evaluate on the test set
model.evaluate(test_seq)

В этом обновленном коде мы добавили Dropout слои после каждого сверточного слоя и перед Conv2D слоями. Мы установили коэффициент отсева равным 0,25, чтобы случайным образом снизить 25% выходной мощности нейронов во время обучения.

Мы также добавили регуляризацию L2 (kernel_regularizer=l2(0.001)) к слою Dense с параметром регуляризации, равным 0.001. Это помогает контролировать сложность модели и предотвращает переобучение.

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

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

Давайте проверим это в деле:

Опять не то ....

А теперь делаем небольшую магию) Меняем всего лишь модель нейросети:

И получаем уже сходимость сети.

Т.е. в целом можно пользовать нейросеть как хорошего помощника в написании некоторого драфт кода, но требуется дорабатывать этот код. И иногда большой объем работ именно такая нейросеть пишет быстро и почти не надо правок. А вот там, где требуется некоторая экспертность - там нужно вручную править существенные моменты.

Источник: https://habr.com/ru/articles/735298/


Интересные статьи

Интересные статьи

Вы хотите создать простую капсулу, способную распознавать естественные движения трости? Хотите внедрить машинное обучение / искусственный интеллект на микроконтроллерах и других устройствах? Мы пока...
Недавно Google изменил политику по отношению к доступу к аккаунту из неизвестных источников. Давно приходили предупреждения, но я до последнего надеялся, что обойдется и не коснется меня. Наивный.Дока...
Итак, у вас есть отличная идея для новой фичи в OpenStack, которая улучшит/упростит/ускорит/оптимизирует какой-либо бизнес сценарий. При этом вы хотите не только реализовать ее для downstream нужд (на...
Разработчик по имени Питер, как и многие из нас, попал на долгое время в ловушку карантина. У него появилось свободное время, причем много, и Питер решил разработать систему распознав...
Нейросети — это та тема, которая вызывает огромный интерес и желание разобраться в ней. Но, к сожалению, поддаётся она далеко не каждому. Когда видишь тома непонятной литературы, теряешь желание ...