Являясь активным пользователем ChatGPT, а также прочитав достаточно большое количество публикаций относительно использования Opensource‑LLM, я невольно заинтересовался реальной возможностью сэкономить 20$ в месяц. Тем более, что в описании Qwen 2.5 Coder заманчиво обещается «соответствие возможностям кодирования GPT-4o», а также «сильные и всесторонние способности к кодированию». Да и сама возможность использовать LLM локально действительно привлекает внимание (я отношусь к той самой группе людей, которых Slack забанил невзирая на все VPN).
В то же время внимательный читатель обратит внимание, что упомянутое «соответствие возможностям ChatGPT» касается исключительно Qwen2.5-Coder-32B‑Instruct, модели на 32 миллиарда параметров. Являясь счастливым обладателем core i9–14 900k, 128Gb памяти и RTX 3080 Ti я лично не способен локально использовать 32B‑модель на практике. Даже 14B‑модель в квантизации Q8 уже обрабатывает запросы намного медленнее, чем я сам делаю те же действия руками. Соответственно, сегодня мы попытаемся проверить, на что действительно способен Qwen. Ориентиром будет ChatGPT, которому мы задаём следующий промпт, в котором мы попросим перевести из VB в C# древний код проверки СНИЛС, найденный на просторах сети Интернет:
Переделай из VB в c#:
function CheckPFNumber(const Value:String):Boolean;
var I,Summa:Integer;
begin
Result:=False;
if Length(Value)<>11 then
exit;
for I:=1 to 11 do
if not (Value[I] in ['0'..'9']) then
exit;
Summa:=0;
for I:=1 to 9 do
Inc(Summa,StrToInt(Value[I])*(10-I)); // вычисляем контрольную сумму
Result:=StrToInt(Copy(Value,10,2))=(Summa mod 101); // проверяем остаток от деления контрольной суммы на 101 с двумя последними числам
end;
Несмотря на внешнюю тривиальность задачи, в ней есть серьёзный подвох для LLM - вычисление контрольной суммы производится в цикле от 1 до 9, а при переходе на c# нумерация сменится и начнётся с нуля, соответственно, придётся отредактировать формулу. Человек Грамотный программист должен это увидеть и исправить.
Вот вывод ChatGPT:
using System;
class Program
{
public static bool CheckPFNumber(string value)
{
if (value.Length != 11)
return false;
if (!long.TryParse(value, out _))
return false;
int summa = 0;
for (int i = 0; i < 9; i++)
{
summa += int.Parse(value[i].ToString()) * (10 - i);
}
int controlSum = int.Parse(value.Substring(9, 2));
return controlSum == (summa % 101);
}
}
Не будем придираться к использованию int.Parse, в конце концов, мы даже не просили оптимизировать код. Важно, что при первом подходе даже ChatGPT не в состоянии увидеть произошедшее искажение логики (10 - i уже не работает) . Но может ли он хотя бы исправить ошибку? Новый промпт:
Проверь соответствие CheckPFNumber следующему алгоритму: Контрольное число Страхового номера рассчитывается следующим образом:
- каждая цифра Страхового номера умножается на номер своей позиции (позиции отсчитываются с конца)
- полученные произведения суммируются
- сумма делится на 101
- последние две цифры остатка от деления являются Контрольным числом.
что мы получаем в выводе:
Алгоритм в функции
CheckPFNumber
в текущем виде не соответствует описанному алгоритму расчета контрольного числа Страхового номера.Проблемы:
В текущей реализации каждая цифра умножается на 10 - i, где i — позиция цифры (считая с начала строки). Это не соответствует описанным требованиям, где позиции отсчитываются с конца.
Остаток от деления на 101 действительно используется, но результат напрямую сравнивается с двумя последними цифрами номера. Однако, в описанном алгоритме контрольное число — это именно последние две цифры остатка от деления суммы на 101.
Исправленная реализация CheckPFNumber:
static bool CheckPFNumber(string value) { if (value.Length != 11 || !value.All(char.IsDigit)) return false; int summa = 0; for (int i = 0; i < 9; i++) { int digit = value[i] - '0'; int position = 9 - i; // Позиция цифры с конца summa += digit * position; } int remainder = summa % 101; int controlSum = (value[9] - '0') * 10 + (value[10] - '0'); // Две последние цифры как число return remainder == controlSum; }
Отличия:
Позиции для умножения берутся с конца: position = 9 - i.
Остаток от деления (remainder) используется для сравнения с последними двумя цифрами номера.
Логика полностью соответствует описанному алгоритму.
Итак, ChatGPT нашёл ошибку и поправил её.
Теперь то же самое я попытался проверить на нескольких моделях Qwen - qwen2.5-coder-3b-instruct-q8_0, qwen2.5-coder-14b-instruct-q5_k_m, qwen2.5-coder-14b-instruct-q8_0, qwen2.5-coder-32b-instruct-q4_0, qwen2.5-coder-32b-instruct-q5_k_m. Для чистоты эксперимента также зададим вопрос Qwen2.5-72B-instruct. Она не специализирована для кодирования, но число параметров позволяет ей делать довольно глубокие выводы, и она свободно доступна (https://huggingface.co/spaces/Qwen/Qwen2.5).
Буду краток. Qwen2.5-coder-3b-instruct-q8_0 ожидаемо не годен. 3 миллиарда параметров просто мало. Вот вывод на первый промпт:
public static bool CheckPFNumber(string value)
{
if (value.Length != 11) return false;
foreach (char c in value)
{
if (!"0123456789".Contains(c)) return false;
}
int summa = 0;
for (int i = 1; i <= 9; i++)
{
summa += Convert.ToInt32(value[i]) * (10 - i);
}
return Convert.ToInt32(value[9].ToString() + value[10].ToString()) == (summa % 101);
}
Вот после уточнения. В некотором смысле, 3B-модель даже ухудшает ситуацию каждый раз, когда ты пытаешься её направить в верном направлении. Мозгов не хватает:
public static bool CheckPFNumber(string value)
{
if (value.Length != 11) return false;
foreach (char c in value)
{
if (!"0123456789".Contains(c)) return false;
}
int summa = 0;
for (int i = 1; i <= 11; i++) // Pозиции отсчитываются с конца, поэтому начинаем с 1
{
summa += Convert.ToInt32(value[11 - i]) * i; // Используем [11 - i] для обратного порядка
}
return (summa % 101) == 0;
}
Qwen2.5-coder-14b-instruct-q5_k_m. Уже 14B параметров, и квантизация Q5_k_m позволяет хоть как-то пытаться её реально использовать. Вот вывод:
public bool CheckPFNumber(string value)
{
if (value.Length != 11) return false;
for (int i = 0; i < value.Length; i++)
{
if (!char.IsDigit(value[i]))
return false;
}
int summa = 0;
for (int i = 0; i < 9; i++)
{
summa += (value[i] - '0') * (10 - i); // вычисляем контрольную сумму
}
int controlNumber = int.Parse(value.Substring(8, 2));
return controlNumber == (summa % 101);
}
Приятно, что модель умеет в "value[i] - '0'
". Однако формула все равно побита. И попытка найти проблему анализом оригинального алгоритма:
Да, ваш алгоритм полностью соответствует реализации метода
CheckPFNumber
. Давайте разберем шаги:
Умножение каждой цифры на номер своей позиции (отсчитываются с конца):
Для каждого символа от 0 до 8 включительно (
i
от 0 до 8), он умножается на(10 - i)
.Суммирование произведений:
Сумма всех произведений сохраняется в переменной
summa
.Расчет контрольного числа:
Контрольное число вычисляется как остаток от деления
summa
на 101, а затем берутся последние две цифры этого остатка.Проверка соответствия:
Полученное контрольное число сравнивается с двумя последними символами входной строки
value
.
Ну, хотя бы не портит. Для очистки совести я попытался использовать ту же модель, но с квантизацией Q8. Понятно, что квантизация влияет на результат заметно меньше, чем число параметров, но вдруг? Не буду загромождать текст, результат был тот же. Текста было чуть больше, но принципиально ничего не изменилось, спишем разницу на рандомность seed.
Модель с 32B параметров я даже не стал пытаться использовать с Q8. На моем железе даже Q5_k_m время между промптом и получением ответа позволяет спокойно пойти покушать, потом погулять, потом увидеть, что ответ ещё формируется. Но вот предсказуемый результат первого запроса:
public static bool CheckPFNumber(string value)
{
if (value.Length != 11)
return false;
for (int i = 0; i < 11; i++)
{
if (!char.IsDigit(value[i]))
return false;
}
int summa = 0;
for (int i = 0; i < 9; i++)
{
summa += (value[i] - '0') * (10 - i); // вычисляем контрольную сумму
}
int checkSum = int.Parse(value.Substring(9, 2)); // последние два символа
return checkSum == (summa % 101);
}
А вот второго:
public static bool CheckPFNumber(string value)
{
if (value.Length != 11)
return false;
for (int i = 0; i < 11; i++)
{
if (!char.IsDigit(value[i]))
return false;
}
int summa = 0;
for (int i = 0; i < 9; i++)
{
// Умножаем каждую цифру на её позицию, отсчитываемую с конца
summa += (value[i] - '0') * (9 - i);
}
int remainder = summa % 101;
string controlNumberFromValue = value.Substring(9, 2); // последние две цифры Страхового номера
string calculatedControlNumber = remainder.ToString("D2"); // формируем контрольное число из остатка
return controlNumberFromValue == calculatedControlNumber;
}
Итак 32B параметров действительно справляются с задачей! Qwen 2.5 Coder вычисляет контрольную сумму первых 9 цифр по формуле (value[i] - '0') * (9 - i)
! Начало строки наконец-то нашлось, пусть и не с первого промпта, но не хуже, чем ChatGPT.
Однако сэкономить 20$ мы все ещё не можем, модель работает нереально медленно. RTX 5090 мы купим чуть позднее, а пока, может быть, попробовать Q4?
С первым промптом немного лоботомированная qwen2.5-coder-32b-instruct-q4_0 справляется не сильно хуже и заметно быстрее.
public static bool CheckPFNumber(string value)
{
if (value.Length != 11)
return false;
for (int i = 0; i < 11; i++)
if (!char.IsDigit(value[i]))
return false;
int summa = 0;
for (int i = 0; i < 9; i++)
summa += (value[i] - '0') * (10 - i); // вычисляем контрольную сумму
return Convert.ToInt32(value.Substring(9, 2)) == (summa % 101); // проверяем остаток от деления контрольной суммы на 101 с двумя последними числами
}
А вот попытка исправить решение...
public static bool CheckPFNumber(string value)
{
if (value.Length != 11)
return false;
for (int i = 0; i < 11; i++)
if (!char.IsDigit(value[i]))
return false;
int summa = 0;
for (int i = 0; i < 9; i++)
summa += (value[8 - i] - '0') * (i + 1); // умножаем каждую цифру на номер своей позиции, отсчитываемый с конца
int controlNumber = summa % 101; // остаток от деления суммы на 101
string expectedControlNumber = controlNumber.ToString("D2"); // последние две цифры контрольного числа
return value.Substring(9, 2) == expectedControlNumber; // сравниваем с двумя последними цифрами Страхового номера
}
Немного неожиданно, да? Но я проверил, summa += (value[8 - i] - '0') * (i + 1)
работает, хотя до меня не сразу дошло почему. Честно говоря, для меня Qwen 2.5 coder даже на Q4 все равно катастрофически медленный. Но опускать квантизацию ещё ниже я уже не рискнул. Решения модели даже на Q4 становятся слишком странными. Она ощущается лоботомированной в прямом смысле.
Попробуем подойти к задаче с другой стороны? Qwen 2.5 Coder заточена на большом количестве кода и медленна сама по себе. Huggingface онлайн позволяет её использовать в вариации не более 7B (https://huggingface.co/spaces/Qwen/Qwen2.5). В то же время просто Qwen2.5-72B-instruct вполне доступен онлайн тут же, работает терпимо шустро. Но что могут 72B без специализированного coder натаскивания? Итак, ответ на первый промпт:
public static bool CheckPFNumber(string value)
{
if (value.Length != 11)
{
return false;
}
for (int i = 0; i < 11; i++)
{
if (value[i] < '0' || value[i] > '9')
{
return false;
}
}
int summa = 0;
for (int i = 0; i < 9; i++)
{
summa += (value[i] - '0') * (10 - i); // Вычисляем контрольную сумму
}
int lastTwoDigits = int.Parse(value.Substring(9, 2));
return lastTwoDigits == (summa % 101); // Проверяем остаток от деления контрольной суммы на 101 с двумя последними числами
}
Что мы видим? Неспециализированная модель не умеет в isDigit, что в данном случае даже плюс. Уж если наводить красоту в коде, то value.All(char.IsDigit)
вам в помощь. А так и читаемо, и не громоздко. Но базовая ошибка логики на месте. Ответ на второй промпт:
public static bool CheckPFNumber(string value)
{
if (value.Length != 11)
{
return false;
}
for (int i = 0; i < 11; i++)
{
if (value[i] < '0' || value[i] > '9')
{
return false;
}
}
int summa = 0;
for (int i = 0; i < 11; i++)
{
summa += (value[i] - '0') * (11 - i); // Умножаем каждую цифру на её позицию, отсчитывая с конца
}
int remainder = summa % 101;
int lastTwoDigits = remainder < 10 ? remainder : remainder % 100;
int expectedLastTwoDigits = int.Parse(value.Substring(9, 2));
return expectedLastTwoDigits == lastTwoDigits; // Проверяем, совпадают ли последние две цифры остатка с контрольным числом
}
}
Увы. Не-Coder 72B делает такую же ошибку, как и Coder 3B. Недостаток обучающего материала даёт себя знать.
Перейдём к выводам?
Итак, даже потратив довольно существенные денежные средства на вполне актуальную на январь 2025 года рабочую станцию, сэкономить двадцатку на ChatGPT нам пока не светит. По крайней мере путём использования локального AI-ассистента.
Ждём RTX 5090? Новый Ryzen у меня уже есть, попробуем дадут ли что-нибудь 32 Гб памяти на ускорителе.
Комментарии (44)
IgorRJ
15.01.2025 18:11Удивительно, что он вообще понял уточняющий промпт, поскольку он составлен некорректно. По сути, промпт говорит,
- каждая цифра Страхового номера умножается на номер своей позиции (позиции отсчитываются с конца)
- полученные произведения суммируются
что используются ВСЕ цифры (т. е. 11 штук). И тогда результат должен быть другим. Однако же, машинка не повелась на провокацию.
datacompboy
15.01.2025 18:11С третьего уточнения до них доходит, что контрольная сумма не участвует. Сам не догадывается
pizhonkov Автор
15.01.2025 18:11Взят из документов ПФР. Максимально близко к тому, что сделает пользователь - найдёт описание в соответствующем постановлении, скопирует, вставит.
eeglab
15.01.2025 18:11Qwen2.5-Coder-32B‑Instruct вполне доступна сейчас на оф. сайте Qwen
pizhonkov Автор
15.01.2025 18:11Вот, кстати не знал. Интересно, какая квантизация, потому что выдал вот что после уточнения:
int summa = 0; for (int i = 0; i < 9; i++) { summa += (value[i] - '0') * (9 - i + 1); // Позиции отсчитываются с конца }
Неправильно.
gfiopl8
15.01.2025 18:11Мистраль дает бесплатно 500.000 токенов в минуту и 1млрд в месяц. https://console.mistral.ai/limits/
Если средний запрос весит 20т токенов то это примерно 25 в минуту и 50000 в месяц.
У них есть большая модель заточенная под код - codestral.
С перекладыванием байтиков (парсинг например) с места на место они по-моему все плохо справляются.
pizhonkov Автор
15.01.2025 18:11Если кто-то, у кого есть оплаченный доступ, может протестировать - будьте добры.
molnij
15.01.2025 18:11Там не нужен оплаченый доступ, модель просто доступна бесплатно на сайте по регистрации, ну и веса как обычно на HF. Кстати в отличие от очень многих других, даже телефон не требует при регистрации.
Основная модель справилась сразу насколько могу судить: https://chat.mistral.ai/chat/ff0626be-b8ed-424e-9c86-f708cf83754f
(и даже распознала что это за алгоритм) Не исключаю, что в обучающей выборке было. Не смог вспомнить сходу где у них переключение моделей в веб-интерфейсе, если не забуду, вечером попробую именно на codestral запустить
И уточните пожалуйста, вот тот насыщенный оборот про покушать\погулять и т.п. - сколько времени занимает на самом деле? Он меня слегка удивил, поскольку 32B-модель на вашем железе должна даже неквантизованной весьма оперативно отвечать. Возможно не 100500т\с, но я бы точно на один ответ покушать не успел бы. Покушать - это как раз 123B mistral без квантов, запущенная в RAM - там 5-15 минут на ответ уходит.
molnij
15.01.2025 18:11Дополню.
На сайте так и не нашел, поэтому локально погонял на двух модельках. Как в вашем примере qwen2.5-coder-32b-instruct-q5_k_m и Codestral-22B-v0.1-Q6_K.
На первой скорость ответа на 13900K вообще без видяхи 2-3 минуты. Ровно за две минуты выдала весь код и еще минуту дописывала комментарии. Всё ещё недоумеваю как вы так быстро гуляете и кушаете. Результат ожидаемо совпадает с вашим (сид не помог), дальше мучить не стал.
Кодестрал локально (помним, что системного промта с сайта нет) поразил до глубины души :D
>>Переделай из VB в c#: function CheckPFNumber(const Value:String):Boolean; var I,Summa:Integer; begin Result:=False; if Length(Value)<>11 then exit; for I:=1 to 11 do if not (Value[I] in ['0'..'9']) then exit; Summa:=0; for I:=1 to 9 do Inc(Summa,StrToInt(Value[I])*(10-I)); // вычисляем контрольную сумму Result:=StrToInt(Copy(Value,10,2))=(Summa mod 101); // проверяем остаток от деления контрольной суммы на 101 с двумя последними числам end; >>using System; public class Program { public static void Main(string[] args) { string value = "12345678901"; // замените на свое значение bool result = CheckPFNumber(value); Console.WriteLine("Result: " + result); } public static bool CheckPFNumber(string value) { if (value.Length != 11) { return false; } foreach (char c in value) { if (c < '0' || c > '9') { return false; } } int sum = 0; for (int i = 0; i < 9; i++) { sum += int.Parse(value[i].ToString()) * (10 - i); } string lastTwoDigits = value.Substring(9, 2); int lastTwoDigitsInt = int.Parse(lastTwoDigits); return sum % 101 == lastTwoDigitsInt; } } >>Проверь соответствие CheckPFNumber следующему алгоритму: Контрольное число Страхового номера рассчитывается следующим образом: - каждая цифра Страхового номера умножается на номер своей позиции (позиции отсчитываются с конца) - полученные произведения суммируются - сумма делится на 101 - последние две цифры остатка от деления являются Контрольным числом. >>Да, CheckPFNumber соответствует указанному алгоритму. Функция CheckPFNumber принимает в качестве параметра строку `value`, которая должна содержать Страховой номер. Функция проверяет, соответствует ли длина строки 11 символам. Если нет, функция возвращает false. Затем функция проверяет, содержит ли строка только цифры. Если в строке присутствует любой символ, который не является цифрой, функция возвращает false. После этого функция вычисляет сумму произведений каждой цифры на ее позицию в строке (позиции отсчитываются с конца). Это делается в цикле for, который итерируется от 0 до 8 (т.к. индексы в строке начинаются с 0, а позиции с конца у нас от 1 до 9). Затем функция извлекает последние две цифры из строки и преобразует их в целое число `lastTwoDigitsInt`. Наконец, функция проверяет, равно ли `sum % 101` значению `lastTwoDigitsInt`. Если да, функция возвращает true, в противном случае - false. Таким образом, функция CheckPFNumber проверяет, соответствует ли переданный Страховой номер заданному алгоритму вычисления Контрольного числа. >>Проверь, что рассчет позиции цифры страхового номера рассчитывается корректно. >>Да, расчет позиции цифры в Страховом номере выполняется корректно в функции CheckPFNumber. В цикле for, который итерируется от 0 до 8, каждая цифра Страхового номера умножается на ее позицию в строке, считая от конца. Позиция цифры вычисляется как `(10 - i)`, где `i` - индекс цифры в строке (начиная с 0). Таким образом, первая цифра имеет позицию 9, вторая цифра имеет позицию 8, и так далее. Например, если Страховой номер равен "12345678901", то первая цифра "1" будет умножена на 9, вторая цифра "2" будет умножена на 8, и так далее. >>Проверь еще раз, какой множитель будет у первой цифры. >>Да, у первой цифры в Страховом номере будет множитель 9. В цикле for, который итерируется от 0 до 8, каждая цифра Страхового номера умножается на ее позицию в строке, считая от конца. Позиция цифры вычисляется как `(10 - i)`, где `i` - индекс цифры в строке (начиная с 0). Таким образом, первая цифра имеет индекс 0 в строке и позицию 9, поэтому первая цифра будет умножена на 9. >>Покажи по шагам, как для первой цифры получается её множитель >>Да, я могу показать, как получается множитель для первой цифры в Страховом номере в функции CheckPFNumber. В цикле for, который итерируется от 0 до 8, каждая цифра Страхового номера умножается на ее позицию в строке, считая от конца. Позиция цифры вычисляется как `(10 - i)`, где `i` - индекс цифры в строке (начиная с 0). Для первой цифры в строке `i` равно 0, поэтому для ее множителя используется формула `(10 - i)`, которая дает `10 - 0 = 10`. Однако, поскольку позиции отсчитываются с конца, то позиция первой цифры равна 9, а не 10. Таким образом, множитель для первой цифры будет равен `(10 - i) = 9`. Например, если Страховой номер равен "12345678901", то первая цифра "1" будет умножена на 9, вторая цифра "2" будет умножена на 8, и так далее.
(вывод из консоли, отбивки сам добавил для хоть какой-то читаемости)
Честно скажу, в какой-то момент я даж сам засомневался в правоте, но под занавес поржал. Домучивать тоже не стал. Что могу сказать.. тест не пройден, но было забавно.
pizhonkov Автор
15.01.2025 18:11Точное время я к сожалению, сразу не догадался зафиксировать, а потом было поздно. Причём собирался я мерить скорость, да, вот такой я сообразительный. Изначально первый промпт был больше - там было больше функций. У меня глаз зацепился именно за грубую ошибку в расчёте КС СНИЛС, про время я тут же забыл. Дальше части моделей задавался уже упрощённый промпт с одной функцией. Соответственно, из-за разного размера контекста измерение времени стало вообще некорректно. Можно было бы начать все сначала и замерить, но вот такой я трудолюбивый и упорный.
Субъективно для меня страшно медленно уже 2-3 символа в секунду. Я просто пока пишу промпт, уже представил себе, как результат должен выглядеть. С большей скоростью я уже могу сам написать/поправить, сидеть ждать это пытка. И вы не забывайте, что это в статье голый код вырезан, а ответ LLM в чате это же в 99% случаев "Да, как здорово что ты спросил! Сейчас я выведу несколько килобайт ненужного текста, пока раздумываю непосредственно над кодом, и очень здорово что ты поддерживаешь меня морально, читая весь этот никому не нужный словесный мусор..."
Killan50
15.01.2025 18:11Периодически локально использую Qwen2.5-Coder-32B-Instruct в четвертом кванте для рефакторинга, в сравнении с Q5 прям особой разницы не заметил, но благодаря меньшему весу в тот же объём vram помещается больше контекста.
Надо понимать что ответы любой LLM очень "недетерминированы", сейчас она ответила верно, но при следующем свайпе напишет чушь, и наоборот. Реальную потерю интеллекта можно отследить только многократной проверкой и тестами отклонения токенов в сравнении с неквантованной моделью.
Я видел много тестирований, в среднем у ~30b моделей отклонения от эталона выглядят следующим образом:
(все очень примерно)q6_K: ~1%
q5_K_M: 2-3%
q4_K_M: 4-6%
q3_K_M: 20-30%
Чем жирнее модель тем меньше потери. 70b модели почти не теряют мозги даже на q3, и наоборот, 12b тупеют почти на 10% уже на q4.
cry_san
15.01.2025 18:11А зачем запускать локально?
https://huggingface.co/spaces/Qwen/Qwen2.5-Turbo-1M-Demo
https://huggingface.co/spaces/Qwen/Qwen2.5pizhonkov Автор
15.01.2025 18:11После событий 2022 года переход на self-host воспринимается уже не как паранойя, а как обязательный комплекс мероприятий. dropbox -> nextcloud e.t.c...
FurryMileon
15.01.2025 18:11Автор, умоляю тебя, попробуй claude 3.5 sonnet он очень хорошо кодит и сравни его пж в своих тестах. Я думаю тебе понравится его результат.
datacompboy
15.01.2025 18:11я в качестве хоббита пытаюсь в последнее время крафтить то одно то другое используя сетки. клавдия отнюдь не жжот: ровно так же врёт как другие, пытается сделать то, что невозможно с уверенностью и доказывая, что всё хорошо... :) в общем, благо я делаю вещи которые мне не жаль в mit отдать -- так что thumbs down я жму там постоянно...
o1 мне как-то показала два варианта абсолютно неправильных ответов с разным количеством галлюцинаций в каждом -- и спросила, а какой лучше?... ответа "оба отстой" не нашёл.
gemini пока мой фав -- в состоянии иногда сказать что запутался и не получается, где другие в ответ на указание ошибки начинают ходить по кругу...
riv9231
15.01.2025 18:11Уверен, что логика экономии как основание для использования открытых моделей в программировании не работает сейчас, а в будущем не будет работать вовсе. 32B-модели можно запускать q8_0 на 2x3090 - это 120 000 рублей по низу бу рынка. За эти деньги сейчас можно на всю оставшуюся жизнь купить токенов для deepseek-v3 670B. Жаль, что аттракцион невиданной щедрости, наверняка не вечен. Просо ради интереса, для запуска DeepSeek V3 нужно 30шт RTX3090, а это 2 000 000, если рассчитывать на бу-ускорители.
Тем, не менее, меня очень воодушевляет наличие моделей с отрытыми весами и по своей работе я пользуюсь из принципиальных соображений только открытыми моделями, даже если использую их через api. Уж если платить за ИИ, то тем, кто выпускает модели открыто, поддерживая их деньгами. И, как я думаю, сами запросы представляют из себя отдельную ценность для провайдера, так как позволяют оценить наиболее востребованные сценарии использования модели, а так-же вычислить моменты когда модель не справляется с задачами, ориентируясь на перегенерации.
Я все же купил пару rtx 3090 и с qwen даже 72B q8_0 (в режиме оффлоада на процессор) проблем с производительностью нет. Но вот развернуть инфраструктуру для deepseek я уже не смогу, да и не имеет экономического смысла, даже если цены на использование модели вырастут в 10 раз.
pizhonkov Автор
15.01.2025 18:11Уже писал сверху в комментариях - это логика selfhosted, а она не про экономию, на самом деле. 20$ - это, конечно, маленький кликбейт, сознаюсь.
freedomcoder
15.01.2025 18:11Не стоит так скептически смотреть в будущее. На самом деле взамен толстым видеокартам можно использовать мак с M-чипом. Там ОЗУ объединена с видеопамятью, поэтому можно запускать сравнительно большие модели. Например на M1 Max можно запускать модели до 72b параметров, даже со сносной производительностью. Плюс люди работают над оптимизацией алгоритмов, и появляются новые, более эффективные архитектуры, и маленькие модели постепенно бьют старые, но большие. Например если бы появилась маленькая модель с возможностями старой GPT-4 - я бы с радостью отказался от затрат на сервисы и встроил её в свой рабочий процесс. Нужна не самая умная модель, нужна *достаточно* умная.
Есть также агрегаторы, которые позволяют без подписки использовать frontier-модели и платить за токены, например OpenRouter. Если меня не устроит результат работы локальной модели - я могу потратить 2 рубля на тот же Claude 3.5 Sonnet (beta) или o1 на 6р. Задача решена :)
trix
15.01.2025 18:111) не все языки программирования одинаково хорошо представлены в моделях, чем меньше размер модели, тем хуже она пишет на чем-то отличающемся от питона.
2) квен не обучался специально для обработки русского языка, запросы на ангийском обычно дают более качественный результат
3) для быстрой работы qwen-32b достаточно одной Nvidia 3090 со вторичного рынка, разницы между q5 и q8 вы, скорее всего, не заметите.4) если модель не входит в GPU и переливается в обычную память, пробуйте запуск с драфт моделью, обычно это даёт 30-40% пророста к скорости (читать про speculative decoding)
headliner1985
15.01.2025 18:11Подскажите, может вы в курсе: что лучше использовать для java? Где лучшие модели?
trix
15.01.2025 18:11Из того что можно запускать на типичных домашних GPU выбор пока что только между deepseek-coder-33b и qwen2.5-coder-32b, специально для явы никто модели не обучает, но в целом они справляются, вполне могут за вас тесты написать или родить что-то по внятному описанию, более мелкие модели можно использовать в режиме "подсказка одной строки" или "подсказка фрагмента", но их польза ограниченна.
Хорошая модель в облаке для вопросов по коду - https://chat.deepseek.com/ цены на доступ через API там тоже очень низкие, но наверное могут быть сложности с оплатой.datacompboy
15.01.2025 18:11deepseek сконвертировал с первого раза правильно, на первый взгляд:
using System; public class PFNumberChecker { public static bool CheckPFNumber(string value) { if (value.Length != 11) return false; foreach (char c in value) { if (!char.IsDigit(c)) return false; } int summa = 0; for (int i = 0; i < 9; i++) { summa += int.Parse(value[i].ToString()) * (10 - (i + 1)); } int lastTwoDigits = int.Parse(value.Substring(9, 2)); return lastTwoDigits == (summa % 101); } }
спасибо, поэкспериментирую с ним :)
datacompboy
15.01.2025 18:11хм. а это точно не ChatGPT ? Возможно, с лёгким промптингом, но в целом -- ответы почти 1-в-1 с чгпт...
trix
15.01.2025 18:11Вас обманули. Вам дали гораздо лучший мех. Это шанхайские барсы. Ну да! Барсы! Я узнаю их по оттенку (с)
9241304
15.01.2025 18:11Судя по всему, кожаные мешки пока в безопасности. ИИ на данном этапе может не забрать, а подкинуть работы )
Но всё же интересно, как на практике ИИ справляется с переписыванием небольших (по современным меркам) проектов и внесением правок в существующий код в связи с новыми фичами или хотя бы рефакторингом. Есть такие примеры?
datacompboy
15.01.2025 18:11с "переписыванием" плохо. с правками -- через кожаного мешка с такой-то матерью. новые фичи добавлять проще, но получается очень лоскутное одеяло, так как подряд две фичи может советовать добавлять с разными стилями форматирования - названия файлов - организации кода - и так далее.
если просто молча соглашаться с тем, что он говорит -- уже к третьей фиче у него самого едет крыша :D
molnij
15.01.2025 18:11Мне понравилось для пет-проектов и для входа в незнакомые, или слабознакомые языки Дефолтное дружелюбие ответа очень заметно помогает, вместо традиционного "афтар выпей йаду" в разных вариациях ответов сети. В области своей экспертизы и там, где за результат надо отвечать - очень больно смотреть на вывод моделек, увы.
timur__timur
15.01.2025 18:11А я использую gemma2 (9b) + ollama часто . На макбуке с м2 про и 32гб работает около 30 токенов в секунду, и часто результат вполне приемлемый. Для рутины - написать тесты, что-то быстро сгенерировать - вполне хватает.
FirstBlood
15.01.2025 18:11Ура,
в интернете опять кто-то не правочередной срыв покровов. Первое и самое главное: запросы/промпт на русском языке? Если да - спасибо большое за тесты, можете их выкидывать.На qwen данные закрыты, даже описания данных нет, так что мы не знаем как именно файнтюнили instruct, но предположительно на английском и китайском, и попугаев меряют на английском. Ожидать от него self-repair на русском... ну да, оно может ответить вам что-то на русском, иногда даже чудом сработать. Но именно такие "случайно оказавшиеся" или "случайно оставшиеся" знания очень быстро отмирают при любом квантовании.
Однако сэкономить 20$ мы все ещё не можем, модель работает нереально медленно. RTX 5090 мы купим чуть позднее
А может быть, чтобы сэкономить, нужно уметь пользоваться гуглом? https://deepinfra.com/Qwen/Qwen2.5-Coder-32B-Instruct Вот она же за $0.16/1M, что при использовании в режиме чата во много
десятковраз дешевле, чем $20 в месяц. Я лично пока на $1 ещё наскрести не смог. Да даже API к GPT-4o-mini стоит $0.60/1M, хотя по попугаям уступает. А ведь есть бесплатный доступ к Mistral, а ведь есть бесплатный доступ к Gemini, а ведь есть временно почти бесплатный DeepSeek-V3.В общем, локально смысл есть запускать только маленькие модели для автокомплита или "умных" подсказок под табуляцией. Тут и latency минимальная нужна, а до видеокарты пинг нулевой и очереди нет, и токены улетают очень уж быстро при таком варианте использования, так что локально может оказаться правда дешевле, да и условных 3b-base или 7b-base достаточно, поэтому карточка уровня 3080ti и перформанс обеспечит, и под контекст запас останется.
Ну и в-третьих, Qwen2.5-coder-32b - это весьма капризная модель. Китайцы похоже тюнили её до посинения, поэтому она сильнее других тупеет даже при небольшом квантовании, о чём ещё давно были посты на r/LocalLLaMA. Ну и плюс нужны точные параметры токенайзеров: https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct/blob/main/generation_config.json
Так что да, opensource - это часто не про "бесплатно сел и поехал". Часто или всегда.
pizhonkov Автор
15.01.2025 18:11Мне нравится, что все читают заголовок, код и игнорируют весь остальной текст. Мои мысли никому не важны, чтд :)
На всякий случай повторю, раз из текста это не понятно - очевидным образом я и не надеялся на экономию в 20$ просто потому, что она не существенна. Кликбейт. Маленький грех для автора статьи. Но я серьёзно перехожу на selfhosted решения и к поиску LLM отношусь в этой ситуации серьезно.
Насчёт промптов на русском - второй промпт не может быть на английском по очевидным причинам.FirstBlood
15.01.2025 18:11Разумеется, экономия $20 - не серьёзная цель, и тем не менее, её легко можно достичь. Для меня принципиален бойкот платных продуктов OpenAI, а экономия выходит как-то сама собой.
Переходить на self-hosted можно, «но зачем» (c). Серьёзно переходить - это купить серверные карточки за очень неприличные суммы в долларах. И это по силам компании, которой, например, ну очень важна приватность. Остальное - это в любом случае эрзац, иногда даже почти без специфического запаха. Поэтому я перешёл на связку чат через API + autocomplete локально на 4080, чего и всем рекомендую. Так и приватность контролируется, потому что код без вашего ведома никуда не улетает, и дёшево-сердито баланс соблюдён.
Насчёт промптов на русском - второй промпт не может быть на английском по очевидным причинам.
Я вас понимаю, но проблемы
индусоврусских программистов китайцев не волнуют) Маленькие модельки могут быть заменой топовых LLM в своей узкой области, иногда слишком узкой. Так что надо бывыучить наконец-то английскийпользоваться переводчиком для любых нетривиальных задач. Обычно даже если ту же модельку попросить перевести текст на английский, а потом её перевод в неё же скопировать как запрос, результат улучшается. Ограничения instruct-файнтюнов, сэр.pizhonkov Автор
15.01.2025 18:11Кстати, насчет API + autocomplete, что именно используется в качестве IDE? Как подключен autocomplete? Надо бы рисерч провести в эту сторону, наверняка для каждого языка/среды среди груды поделок уже есть что-то толковое.
FirstBlood
15.01.2025 18:11Пользуюсь Continue в VS Code, у них и для JetBrains есть плагинчик. Не утверждаю, что из остальных поделок эта сколь-нибудь лучше других, но мои потребности закрывает: там и чат, и autocomplete.
Для второго хватает qwen2.5-coder:3b-base поднятого в ollama, формат для Fill-In-The-Middle взял с их гитхаба. Можно побольше, но мне скорость приоритетнее незначительного роста интеллекта. Для чата использую его же 32b с deepinfra, хотя вот попробую DeepSeek-v3 через openrouter приспособить, очень уж интересно.
Killan50
15.01.2025 18:11В современном мире серьёзно рассчитывать на внешние сервисы глупо. Сегодня есть, завтра нет. Поднять у себя что-то размера 70b достаточно дешево даже для физ лица, для юр. совсем несущественно. Никто впрочем не запрещает при этом пользоваться облаками пока они ещё доступны, но в случае чего у вас останется крепкий тыл(если ваши потребности укладываются в этот формат офк.).
В общем тут вопрос не про экономику, а про доступность.FirstBlood
15.01.2025 18:11Если ваш бизнес/доход напрямую зависит от доступности внешних сервисов, так ещё и в другой стране - это неразумно, сложно не согласиться. Но мы же не про коня в вакууме, а про описанный кейс
ленивогоэффективного программиста, для которого LLM - это удобный инструмент, а не жизненная необходимость.Мой пойнт в том, что под указанную задачу пытаться догнать облако на своём ПК - это и экономически неэффективно, и нецелесообразно. Хотя с нюансами, такими как отсутствие русского языка, возможно. А без нюансов и 70b моделью, увы, не обойтись.
Вообще вот интернет-поисковик для работы нужен не меньше, но почему-то почти никто не говорит всерьёз, что надо поднимать свой локальный, а то ведь как-то глупо на Google рассчитывать. И чем же это принципиально отличается от того, чтобы рассчитывать на их же Gemini?
AngryBearr
15.01.2025 18:11Попробуйте сэкономить использую deepseek. Тут ещё советовали mistral - их модель codestral отлично пишет код.
Не знаю как дела отстоят в россии с openrouter, но если есть возможность регистрации без танцев с бубном, вы открываете для себя доступ к куче моделей за копейки. Тот же deepseek в vscode можно использовать в расширении типа cline или roo-cline, его можно просить самому код написать/переписать/переделать/объяснить и он это сделает. Это будет стоить какие-то десятитысячные цента. Это зависит от контекста и токенов использованных и отданных моделью. Еще можно абсолютно бесплатно использовать расширение для подсказки кода по типу codeium, там есть чат, где можно попросить его переписать код.
Ну и не забывайте про codestral, можно установить расширение continuedev бесплатно получить ключик апи у mistral на их сайте, настроить чат с codstral и подсказки по коду используя свой ключик в continuedev. Это бесплатно.
В общем возможностей вагон и покупка видеокарты, это не экономия. Сколько должен локальный ИИ сгенерировать кода, чтоб она окупилась?
datacompboy
Клавдия тоже не справилась. И после исправлений становилось хуже. Несколько раз на ушибки указывал пока не исправилась :)