Делаем 10-минутную задачу за 2 часа с помощью ChatGPT

Все мы видели много статей, где с помощью AI-инструментов за минуты выполняется работа, на которую раньше мог легко уйти день. Особенно впечатляют примеры, где работа (успешно) идет вне зоны компетенции человека (т.е. когда AI позволяет делать то, что человек в принципе один сделать не мог бы). Но сегодня у меня получился несколько другой случай:

Задача стояла относительно тривиальная: нужно было сгенерировать look-up table (LUT) для по-канального увеличения контраста (S-кривая), и применить эту кривую на фотографии с камеры. Берем ChatGPT (даже 3.5 должен прокатить, тут всего-то одна формула), за 10 секунд получаем Python-код типичной S-кривой (также ChatGPT для моего удобства сразу добавил отрисовку графика через matplotlib), настраиваем параметр "кривизны" кривой по вкусу - и можно вставлять в финальное приложение. Среди множества S-кривых/сигмоид ChatGPT использовал "логистическую функцию" - она одна из наиболее простых. Но у неё есть и недостаток - параметром "кривизны" нельзя сменить увеличение контраста на снижение (и наоборот) - впрочем, мне это особо и не нужно было, снижать контраст в целевом применении не нужно никогда (крайний случай - оставить все как есть, а это логистическая функция может).

Но праздновать завершение работы оказалось рано: сгенерированный код упрямо рисовал график, снижающий контраст вместо его увеличения. Когда я предъявил эту претензию ChatGPT - он извинился, и с каждым разом выдавал все более и более поломанный код. Просто изменить параметр кривой оказалось невозможно т.к. формула недостаточно универсальная. Что-ж, похоже тут с ChatGPT ничего не получится - но это и не конец света. В конечном итоге, границы применимости LLM известны, и чем более узкая сфера - тем проще за них выйти. Но история тут не заканчивается.


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

import numpy as np
import matplotlib.pyplot as plt

def create_s_curve_lut():
    # Define parameters for the sigmoid curve
    a = 10.0  # Adjust this parameter to control the curve's shape
    b = 127.5  # Midpoint of the curve (127.5 for 8-bit grayscale)

    # Create the S-curve LUT using the sigmoid function
    lut = np.arange(256)
    lut = 255 / (1 + np.exp(-a * (lut - b) / 255))

    # Normalize the LUT to the 0-255 range
    lut = (lut - np.min(lut)) / (np.max(lut) - np.min(lut)) * 255

    return lut.astype(np.uint8)

# Create the S-curve LUT
s_curve_lut = create_s_curve_lut()

# Plot the S-curve for visualization
plt.plot(s_curve_lut, range(256))
plt.xlabel("Input Values (0-255)")
plt.ylabel("Output Values (0-255)")
plt.title("S-curve Contrast Enhancement LUT")
plt.show()

# You can access the S-curve LUT with s_curve_lut

В этот момент я поставил крест на LUT от ChatGPT и переделал (если так можно говорить про пару строчек кода из google) используя регуляризованную неполную бета-функцию. Покрутил параметры a=b пока не получил на графике кривую по вкусу (аналогично тому, что выставляю обычно руками в графическом редакторе) и наконец применил LUT на тестовое изображение используя в OpenCV. К моему полному удивлению, функция уменьшила контраст, а не увеличила его. Как так?

Медитирование не позволило быстро найти ошибку. Я написал тестовый кусочно-линейный LUT для увеличения контраста - и на изображении он дал ожидаемый результат. Лишь добавив кусочно-линейный LUT на график - корень проблемы стал виден: когда я выкинул функцию генерации S-curve LUT от ChatGPT, я оставил код рисования графика. Там ChatGPT старательно напечатал заголовок графика и названия осей.. но сделал конкретную подставу используя данные оси X - в Y, и наоборот. Т.к. параметры plt.plot используются без имени - не используя регулярно / не помня порядок параметров человеку очень легко тут не заметить ошибку.

Таким образом, когда я настраивал фактор формы кривой - я настраивал его на перевернутом графике, и сделал его уменьшающим контраст. Когда я обвинял ChatGPT в том, что он неправильную формулу мне сделал - и он соглашаясь со мной судорожно пытался что-то исправить - у него не было шансов. Т.к. формула была правильная, а ошибка была в графике. Конечно, если ChatGPT указать на ошибку в выводе графика - он радостно соглашается и исправляет её (но так я и сам могу). Это подстава уровня #define true false на университетских компьютерах.

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

▶ Глянуть в код

Но и это оказался не конец: Взглянув на график - бросается в глаза легкая асимметричность кривой GPT-TRAP в районе 255. Это банальная ошибка округления : вычисленное вещественное число результата просто приводят к uint8 (=отбрасывают дробную часть), а значит результат (и яркость изображения) будет в среднем на 0.5 единицы / 0.25% меньше, пиксели с полной яркостью (255) будут намного более редкими. Интересной эту ошибку делает то, что она есть в коде, сгенерированной и ChatGPT, и Bing Copilot и Google Bard. Т.е. видимо такой код очень распространен в тренировочных данных и все модели решили что "умножить на 255 и привести к uint8" - это успех. Технически конечно в диапазон мы попали, но результат не безупречен.

▶ Глянуть в код

Выводы:
  • Языковые модели - как junor разработчики: они могут и будут делать неожиданные ошибки, им нужны четкие инструкции и руководство. Впрочем, разница в том, что джуны вырастут, а у моделей остается ждать следующих поколений. Как и с джунами - с моделями нужно иметь реалистичные ожидания.
  • Весь код от языковых моделей нужно проверять, никому верить нельзя. И чем менее истоптанная поляна, тем тщательнее нужно проверять. Языковые модели генерируют код очень похожий на правду, а значит ошибки могут быть очень дороги в исправлении.
  • Если получаем неожиданный результат - зачастую проще спросить несколько разных моделей и сравнить результаты : сейчас в дополнение к ChatGPT (3.5/4) есть Copilot, Bard, Replit и другие. Никто из них не выдал идеальный код с первой попытки, но по этому пути мне не пришлось бы залипать с графиком.
  • Некоторые ошибки - систематические для языковых моделей, видимо унаследованные из частично пересекающегося набора данных для обучения, где эти ошибки были широко представлены (т.к. языковые модели на текущий момент доверяют примерам для обучения безусловно, в отличие от людей). Т.е. модели пока не могут превзойти по качеству данные для обучения, и могут лишь к ним приблизится. Непонятно, сколько работы еще предстоит чтобы "превзойти учителя", может так оказаться, что это тот случай когда 10% работы занимают 90% времени. Но прогресс в последние 3 года движется стремительно, возможны и сюрпризы.

22 Октября 2023

RSS@BarsMonster3@14.by