Как стать автором
Обновить
2683.31
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Код, который пишет себя сам

Время на прочтение10 мин
Количество просмотров65K
Источник

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

Строго говоря, мы все уже достаточно давно используем различной степени интеллектуальности среды разработки, которые подсказывают, корректируют процесс написания кода, облегчая жизнь программиста. Однако, так или иначе, в этом процессе центральной фигурой всё равно остаётся программист. В каждой сфере есть свой «Святой Грааль», и если в области дизайна, — это поиск волшебной кнопки «сделать красиво», то в области программирования, — поиск способа, чтобы код «делался сам собой».

Хотя, для этого вовсе не обязательно привлечение высоких технологий:-) В своё время на хабре наделал шума пост, когда топовый разработчик числился на хорошем счету, ничего не делал и отправлял свою работу на аутсорсинг в Китай, выплачивая китайским работникам пятую часть от своей годовой зарплаты. Хотя статья вовсе не об этом, это просто к слову :-)
Ответы на вопросы в конце статьи:
1-машина, 2-человек, 3-человек

▍ CodeWhisperer


Выше мы уже обмолвились об интеллектуальных функциях сред разработки, однако кое-кто пошёл ещё дальше и в 2022 году Amazon запустил свой сервис, под названием CodeWhisperer, базирующийся на нейросетях и обученный на базе огромного количества строк кода. Благодаря этому, движок сервиса позволяет не просто рекомендовать небольшие участки кода, но он может и генерировать этот код за программиста.

Например, программист может написать оператор for, а сервис порекомендует всё тело цикла прямо внутри самого редактора кода IDE:

image
Источник

Либо же, разработчик может в комментарии описать свою задачу (поддерживается только английский язык), естественным языком, а сервис порекомендует нужный для него фрагмент кода, который позволит решить задачу разработчика. Например: «как загрузить файл с шифрованием на стороне сервера?». При выдаче соответствующих рекомендаций, сервис будет максимально использовать ресурсы Amazon для решения этой задачи (то есть решение будет базироваться на существующих библиотеках, кодовой базе, сервисах, и т.д. и т.п.).

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

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

Схематично, работа с сервисом построена следующим образом:

image
Источник

Сервис можно интегрировать со следующими средами разработки: Intellij IDEA, PyCharm, We storm, Visual Studio Code, AWS Cloud9, AWS Lambda.

Поддерживается система рекомендаций для разработки приложений на языках Java, Javascript и Python.

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

Задaча на языке Python:

image
Источник

Задача на языке Java:

image
Источник

Задача на языке JavaScript:

image
Картинка aws.amazon.com

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

▍ Copilot


Аналогичный описанному выше сервис был запущен Microsoft в прошлом, 2021 году, и получил название Copilot. Задача сервиса также заключается в автоматическом анализе кода разработчика и рекомендациях по дописыванию участков кода.

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

Проект позволяет помочь программистам в написании кода на языках: JavaScript, Python, TypeScript, Ruby, Go, C#, C++.

Система может быть подключена в виде расширения для сред разработки: Visual Studio Code, Visual Studio, Neovim, набора IDE от JetBrains.
Например, если вы используете среду разработки от JetBrains, рекомендации выглядят следующим образом: вы можете набрать в коде, например, class Test, а система сама предложит вам дописать тело класса. Предложение будет окрашено в серый цвет:

image
Источник

Если вы согласны с этим предложением, то вам останется только нажать на клавишу Tab, чтобы принять его.

Точно так же выглядит дописывание функции. В примере ниже было написано только начало функции «int calculateDaysBetweenDates (», и система предложила дописать всё тело:

image
Источник

Так же, как и рассмотренная выше система CodeWhisperer — Copilot предлагает свои рекомендации, базируясь на стиле программирования конкретного разработчика.

Более подробно о системе можно почитать на ресурсе с документами по ней.

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

▍ Tabnine


Ещё одним альтернативным проектом, который позволяет ускорить процесс разработки кода, является система Tabnine, которая так же предназначена для дописывания кода за программистом:

На сайте компании приводится цифра, что 43% кода разработчика может быть дописано с помощью Tabnine Pro.

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

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

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

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

▍ OpenAI Codex


Некоторое время назад компанией OpenAI была представлена система Codex, базирующаяся на языковой модели GPT-3, которая может генерировать рабочий код, получая команды на английском языке. Система поддерживает работу с множеством языков, среди которых можно перечислить такие как: JavaScript, Go, Perl, PHP, Ruby, Swift, TypeScript, Shell. Создатели системы отмечают, что она продемонстрировала хорошую эффективность для рефакторинга кода, однако это далеко не всё что может система.

Авторы записали достаточно забавное видео с демонстрацией её работы, которое можно посмотреть ниже:

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

▍ AlphaCode


Ещё в феврале этого года Alphabet, дочерняя компания Google, анонсировала нейросеть, которая может писать программы с нуля. Проект получил название AlphaCode.

Причём эффективность системы была настолько высока, что сами разработчики характеризуют её, как способную писать код на уровне среднего программиста!

Тестирование системы проводилось на соревновательной платформе Codeforces, предназначенной для проведения соревнований по программированию. В процессе тестов система продемонстрировала впечатляющую эффективность, достигающую 54,3% при соревновании с количеством участников в 5000 человек.

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

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

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

image
Источник

▍ Doesnotexist


Ну и напоследок, в 2021 году был запущен любопытный проект по генерации программного кода с помощью нейросетей, — Doesnotexist.codes.

Проект базируется на языковой модели GPT-2 и может генерировать программный код на языках C и C++.

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

Забавность этого проекта заключается в том, что каждый может испытать свои силы в угадывании — код, показанный на экране, написан живым человеком или же это продукт нейросети? Ответ на этот вопрос не так однозначен, как может показаться на первый взгляд. И вы сами можете попробовать свои силы в подобном угадывании на сайте проекта или изучив примеры ниже которые мы специально сохранили для вас. Ответы на эти загадки мы разместили в начале статьи ;-).

Итак, человек или машина:

Пример 1
 * Copyright 2012 Wojciech Treter (juzefwt@gmail.com)
 * Copyright 2013, 2014 Bartosz Brachaczek (b.brachaczek@gmail.com)
 * Copied from linux kernel sources (/include/linux/module.h)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

#include <asm/unaligned.h>

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/io.h>

#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>

#include "toshared.h"

#define TOSH_MAX_REGIONS			16
#define TOSH_COMMAND_WAIT_TIME		(2 * HZ)
#define TOSH_SHORT_INFO_RESPONSE_TIME	(2 * HZ)
#define TOSH_LONG_INFO_RESPONSE_TIME	(2 * HZ)
#define TOSH_SHORT_BLOCK_COMMAND_TIME	(10 * HZ)
#define TOSH_LONG_BLOCK_COMMAND_TIME	(20 * HZ)
#define TOSH_STATISTICS_STATUS_TIME	(10 * HZ)

/* Copied from linux kernel sources (/include/linux/rc_defs.h) */
static int tosh_cfg_get_val(unsigned char *val, int val_size, unsigned char *buf,
			    int buf_size)
{
	unsigned char num = buf[0];
	unsigned char ret;

	if (num == TOSH_REPLY_CTRL)
		return -EINVAL;

	if (num == TOSH_EEPROM_READ_CODE) {
		/* Read code */
		num = buf[1];
		ret = buf[2];
	} else if (num == TOSH_EEPROM_WRITE_CODE) {
		/* Write code */
		num = buf[1];
		ret = buf[2];
	} else {
		printk(KERN_ERR "%s: Unsupported tosh register %d\n", TOSHIERE_NAME,
		       num);
		ret = -EINVAL;
	}
	/* Sanity check */
	if (ret > (buf_size - 3)) {
		printk(KERN_ERR "%s: Can't read tosh register %d, return %d\n", TOSHIERE_NAME,
		       num, ret);
		return -EINVAL;
	}
	ret = (buf[3] << 8) | buf[4];
	if (ret >= val_size)
		return -EINVAL;
	if (ret < 0)
		val[ret] = 0;
	else
		val[ret] = num;
	return ret;
}

static void tosh_rx_short_block_status(struct timer_list *t)
{
	struct tosh_msg_hdr *msg;
	struct tosh_msg_trl_status *trl;
	struct tosh_ee_status *stat;
	struct tosh_cmd_hdr *cmd;
	int resp_count = 0;
	int short_count = 0;
	int i;

	if (time_after(jiffies, t->expires + TOSH_SHORT_INFO_RESPONSE_TIME))
		mod_timer(t, jiffies + TOSH_SHORT_INFO_RESPONSE_TIME);

	for (i = 0; i < TOSHI_MAX



Пример 2
double *deltat, **data;
{
    FILE *refdata, *fopen();
    int i, npts = -6, fclose();
    extern double *makevector();
    double temp;
    char *fgets(), tmpstr[81];

    /*
     * Open reference data file.  Count data points and allocate storage for
     * data
     */

    if ((refdata = fopen(filename, "r")) == NULL)
	return (0);
    while (fgets(tmpstr, 80, refdata) != NULL)
	npts++;
    *data = makevector(npts);
    rewind(refdata);

    for (i = 0; i < 7; i++)
	assert(fgets(tmpstr, 80, refdata));
    sscanf(tmpstr, "%lf %lf", &temp, *data);
    assert(fgets(tmpstr, 80, refdata));
    sscanf(tmpstr, "%lf %lf", deltat, *data + 1);
    *deltat -= temp;
    for (i = 2; i < npts; i++)
    {
	assert(fgets(tmpstr, 80, refdata));
	sscanf(tmpstr, "%lf %lf", &temp, *data + i);
    }

    fclose(refdata);
    return (npts);
}

/*--------------------------------------------------------------------------
 *  testfit()
 *
 *    Rejects exponentials whose amplitudes are less than the standard error
 *    of estimate
 *
 *  Calling sequence:
 *	testfit(ndata, data, terms, amplitude, lambda, h, errfit)
 *
 *  Arguments:
 *    Input:
 *	ndata		int *		number of data points
 *	data		double *	array of ordinate values for curve to be
 *					decomposed into exponentials
 *	terms		double*		negative of number of exponential terms
 *	amplitude	double*		array of amplitudes of exponentials
 *	lambda		double*		array of decay constants of exponentials
 *	h		double		spacing of data points
 *    Output:
 *	terms		double*		number of exponential terms with
 *					amplitudes > standard error of estimate
 *	errfit		double*		standard error of estimate
 *
 * Returns:
 *
 * Functions called: exp(), sqrt(), fabs()
 *
 * Files accessed:
 *------------------------------------------------------------------------*/

int testfit(ndata, data, terms, amplitude, lambda, h, errfit)
int ndata;
double *terms, data[], amplitude[], lambda[], h, *errfit;
{
    int n, i, j;
    double temp;

    /* Compute standard error of estimate of the fit to the data */

    n = (int) -(*terms - 0.1);
    *errfit = 0.0;
    for (i = 0; i < ndata; i++)
    {
	temp = 0.0;
	for (j = 0; j < n; j++)
	    temp += amplitude[j] * exp(lambda[j] * i * h);
	temp -= data[i];
	*errfit += temp * temp;
    }
    *errfit = sqrt(*errfit / (ndata - n - 1));

    /* Reject any exponential with an amplitude less than the standard error */

    for (i = 0; i < n; i++)
    {
	if (fabs(amplitude[i]) < *errfit)
	    amplitude[i] = 0.0;
	if (fabs(amplitude[i]) <= ZERO)
	{
	    /* Ripple down rest of amplitude and lambda arrays */
	    for (j = i; j < n; j++)
	    {
		amplitude[j] = amplitude[j + 1];
		lambda[j] = lambda[j + 1];
	    }
	    amplitude[n] = 0.0;
	    lambda[n] = 0.0;
	    n--;
	}
    }
    *terms = (double) n;
    return 0;
}



Пример 3
RpcWriter::RpcWriter(
    const char* host, int port, bool fatal, bool binary
) :
    _server(new rpcstream),
    _delete(true),
    _host(nil)
{
    server().verbose(fatal);
    server().connect(host, port);
    server().negotiate(binary);

    if (!server() && fatal) {
	abort();
    }
}

RpcWriter::RpcWriter(int fd, bool fatal, bool binary) :
    _server(new rpcstream),
    _delete(true),
    _host(nil)
{
    server().verbose(fatal);
    server().attach(fd);
    server().negotiate(binary);

    if (!server() && fatal) {
	abort();
    }
}

RpcWriter::RpcWriter(rpcstream* server) :
    _server(server),
    _delete(false),
    _host(nil) {}

// Close the connection to the server, although the file number won't
// be closed if we attached the connection to it.  Free any storage
// allocated by RpcRegistry::find for the host name.

RpcWriter::~RpcWriter() {
    if (_delete) {
	delete _server;
    }
    delete _host;
}

// Use a member function to open a connection to an RPC service at its
// registered host name and port number so that a derived class's
// constructor can retry the attempt if necessary.

void RpcWriter::open(const char* path, bool fatal, bool binary) {
    int port;

    if (RpcRegistry::find(path, _host, port)) {
	server().verbose(fatal);
	server().connect(_host, port);
	server().negotiate(binary);
    } else {
	server().clear(ios::failbit | ios::badbit);
    }

    if (!server() && fatal) {
	cerr << "RpcWriter::open: service " << path << " not found" << "\n";
	cerr.flush();
	abort();
    }
}


RUVDS | Community в telegram и уютный чат
Теги:
Хабы:
+47
Комментарии46

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds