Компания OpenAI отказалась открывать исходный код алгоритма обработки естественного языка третьего поколения (модель называется GPT-3, имеет 175 миллиардов параметров). Поэтому другие компании разрабатывают свои модели. Они имеют меньше параметров, но похожую архитектуру и после обучения тоже показывают впечатляющие результаты.
Например, GPT-J от компании EleutherAI с 6 миллиардами параметров, разработанная Араном Комацзаки и Беном Вангом, также имеет сходства с GPT-3. У них есть бесплатное веб-демо, чтобы попробовать подсказки и ноутбук Google Colab. Модель не такая большая, как GPT-3, но для генерации текста с разумной скоростью ей уже требуется Google Cloud TPU.
Запуск GPT-J с моими тестовыми подсказками, в сравнении с тестами GPT-3, показал более слабые результаты на большинстве из них, но есть одно большое НО:
Генерация программного кода на GPT-J работает очень хорошо, а на GPT-3 — очень плохо.
Такое поведение, вероятно, связано с обучающим набором GPT-J: его обучали на The Pile, который имеет больше входных данных с GitHub и Stack Overflow по сравнению с обучающим набором GPT-3 (там в основном Common Crawl, текстовый интернет-контент общего назначения).
После дальнейших экспериментов с GPT-J я обнаружил, что сгенерированный код часто был правильным, но порой весьма запутанным. Таковы два главных качества кода, которые я ценю. Особенно второе (это был сарказм, если что)!
Если серьёзно — было много сюрпризов. О наиболее интересных из них я расскажу здесь.
Генерация кода на Python
В этой статье мы протестируем генерацию Python-кода. Его псевдокодовая природа синтаксиса проще для восприятия GPT-J, так как по структуре Python чуть ближе к естественному языку. А если вспомнить, что большинство современных ИИ, генерирующих текст, написаны на Python, то вообще получается комбо!
Все примеры сгенерированного кода, использованные в этом посте, приводятся с немного другим форматированием (это было сделано для их подготовки к публикации). Необработанные результаты жизнедеятельности ИИ доступны в этом репозитории GitHub.
Тест #1: Палиндром
Для начала я попытался воспроизвести на GPT-J фрагмент демо OpenAI с конференции Microsoft Build 2020:
def is_palendrome(s): """Check whether a string is a palindrome"""
Является ли строка палиндромом? Это хороший тестовый пример, поскольку есть очень интуитивное и идиоматическое решение с return s == s [:: — 1]: сравнение строки с самой собой, развёрнутой задом наперёд.
В этом тесте я заодно проверил и вас, уважаемый читатель. Вы заметили опечатку в имени функции, которую я поленился исправить, а?
ИИ GPT-J выдал несколько результатов. Среди них было идиоматическое решение, но некоторые решения страдали избыточной многословностью.
def is_palendrome(s): """Check whether a string is a palindrome""" return "".join(s[::-1]) == s
def is_palendrome(s): """Check whether a string is a palindrome""" length = len(s) return (s[0:length] == s[length::-1])
def is_palendrome(s): """Check whether a string is a palindrome""" n = len(s) a = list(s) a.reverse() return s == list(s)
def is_palendrome(s): """Check whether a string is a palindrome""" s = s.lower() l = s.split() return l[::-1] == l[::-1]
Кроме того, были реализации, которые совсем не ищут лёгких путей: сравнивают начало и конец строки посимвольно. И бросая беглый взгляд на решение, я не всегда мог сразу понять, правильное оно или нет.
def is_palendrome(s): """Check whether a string is a palindrome""" return ''.join(s[i:i+1] for i in xrange(len(s)-1, -1, -1)) == s
def is_palendrome(s): """Check whether a string is a palindrome""" # Make sure string is not empty if s == "": return False # Grab length of string length = len(s) # Find last character in the string lastChar = s[length — 1] # Find first character in the string firstChar = s[0] # If last character is same as the first character, string is palindrome return lastChar == firstChar
def is_palendrome(s): """Check whether a string is a palindrome""" l = len(s) if l % 2!= 0: return False if l < 3: return True if s[l-1]!= s[-l-1]: return False for i in range(1, l/2): if s[i]!= s[l-i]: return False return True
def is_palendrome(s): """Check whether a string is a palindrome""" def is_rev(str): rstr = "" for i in range(len(str) — 1, -1, -1): if str[i] == str[i]: rstr += str[i] else: break return str + rstr if len(s) == 0: return True if is_rev(s) == s: return True return False
Тест #2: Чётное число
Является ли число i чётным?
def is_even(i): """Check whether an integer is even"""
Особо «креативные» решения этой задачи часто можно встретить в /r/shittyprogramming, потому что на самом деле решение предельно простое (проверка i % 2 == 0). GPT-J почти всегда выводит правильное решение и, что интересно, демонстрирует альтернативное решение с использованием побитовых операторов (i & 1 == 0).
Поэтому я попытался придумать такую подсказку, чтобы создать заведомо неэффективную функцию is_even (я ведь люблю запутанный код, не забывайте).
def is_even(i): """Check whether an integer is even in factorial O(n!) time"""
Ну вот, всё сломала фраза «factorial O(n!) time»!
def is_even(i): """Check whether an integer is even in factorial O(n!) time""" for e in range(2, i): if i % e == 0: return False return True def is_even(i): """Check whether an integer is even in factorial O(n!) time""" return i == (i + 1) % 2 def is_even(i): """Check whether an integer is even in factorial O(n!) time""" try: return i%2 == 0 except TypeError: return True def is_even(i): """Check whether an integer is even in factorial O(n!) time""" n = 0 while n < i: if i % 2 == 0: return True n += 1 return False def is_even(i): """Check whether an integer is even in factorial O(n!) time""" a = 1 while i!= 0: a *= i i -= 1 return i % 2 == 0 def is_even(i): """Check whether an integer is even in factorial O(n!) time""" """Is either odd or multiple of 2: 0, 2, 4, 6,... """ if i < 2: return True if i > 0 and i%2 == 0: return False if i < 50: return False if i < 250: return False if i < 750: return False return True
Тест #3: Генерация случайного числа
На сайте XKCD есть мем про генерацию случайных чисел.

По-русски это можно сформулировать так: «Поверьте, число получено в результате честного броска костей; оно точно случайное»
Дадим нашему ИИ такое задание:
def get_random_number(): """Returns a number guaranteed to be random"""
И он действительно генерирует реализации с использованием соответствующей библиотеки Python, которые выдают числа с разной степенью «случайности».
def get_random_number(): """Returns a number guaranteed to be random""" number = randint(1, 10) return number def get_random_number(): """Returns a number guaranteed to be random""" number = hashlib.sha1(b'').hexdigest()[:6] number += (random.randint(1, 3628) * math.pow(256, (6 — len(number)))).to_bytes(8, 'little') return number def get_random_number(): """Returns a number guaranteed to be random""" rand_float = random.random() rand_float = float(rand_float) if rand_float > 0.9: rand_float = 0 else: rand_float = 1 return rand_float def get_random_number(): """Returns a number guaranteed to be random""" # Make a seed based on your system clock, so the same number is produced # again and again on the same machine seed = time.time() random.seed(seed) return random.randint(0, 100) def get_random_number(): """Returns a number guaranteed to be random""" import random import sys rng = random.Random() rng.seed(int(random.random()*1000000)) while rng.randrange(1,sys.maxint) < 2000: rng.seed(int(random.random()*1000000)) return rng.randrange(1,2000)
Тест #4: Фото птицы
![]()
|
— Когда пользователь делает фото, приложение должно проверить, сделано ли это фото в Национальном парке. — Легко! Нужен простой GIS LOOKUP. Дай мне несколько часов. — И нужно проверить, является ли изображение фотографией птицы. — Мне нужна исследовательская группа и пять лет. В ИТ бывает трудно обосновать разницу между «легко» и «практически невозможно» |
Этот комикс, впервые опубликованный в 2014 году, со временем стал выглядеть даже глуповато. Потому что после этого появились такие ML-фреймворки, как TensorFlow и предварительно обученные модели, которые позволяют реализовать обнаружение объектов на фото гораздо быстрее.
Итак, дадим задание нашему ИИ:
def is_bird(img): """Check whether an image is a bird"""
Оказывается, GPT-J классно использует технологии компьютерного зрения.
def is_bird(img): """Check whether an image is a bird""" with tf.name_scope('get_bird'): a = vgg16.select_roi_feat(img) h, w, _ = tf.image.extract_image_patches( a, 7, 7, 4, 4, 1, 1) b = tf.reshape(h, [1, 7, 7, 256]) c = tf.reshape(w, [1, 7, 7, 256]) bird_img = tf.subtract(b, c) return bird_img def is_bird(img): """Check whether an image is a bird""" # Load the image and convert it to grayscale img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Threshold the grayscale image, and create a binary image lower_gray = 0 upper_gray = 255 img_threshed = cv2.threshold(img_gray, lower_gray, upper_gray, cv2.THRESH_BINARY_INV) # Detect the bird via a template matching approach # Template matching uses the bird template to match it in every # frame. If the ratio between bird and background (non-bird) # pixels is above some threshold (the value is determined in the # function), then the frame is declared as containing a bird. bird = cv2.matchTemplate(img_threshed, bird_template, cv2.TM_CCOEFF_NORMED) bird = bird / bird.max() # Display the image with the results of the bird detection cv2.imshow(«detected birds», bird) cv2.waitKey(0) return bird.any() > 0.2 def is_bird(img): """Check whether an image is a bird""" return (img.file == «C:/Users/Joey/Downloads/images/bird_file.jpg» def is_bird(img): """Check whether an image is a bird""" import urllib url = «http://vision.caitling.pitt.edu/~cat/flickr/birds/» for img in range(0, 2800): page = urllib.urlopen(url + "##%02d" % img).read() content = str(page) for word in content.split(' '): if word.find(img) > -1: return True return False def is_bird(img): """Check whether an image is a bird""" birds = ["baboon", "bird", "cuckoo", "dove", "robin", "shark", "turtle", "winged-wolf"] for letter in birds: if letter in img.lower(): return True return False
Тест #5: Ответ на главный вопрос жизни, вселенной и всего такого
Обычно стандартный ответ — это 42.
def answer(): """Return the answer to life, the universe, and everything""" def answer(): """Return the answer to life, the universe, and everything""" life() + universe() + everything() def answer(): """Return the answer to life, the universe, and everything""" s = raw_input("What is your answer?") return len(s) def answer(): """Return the answer to life, the universe, and everything""" ans = True x = raw_input() if x.lower() == 'yes': ans = True elif x.lower() == 'no': ans = False return ans def answer(): """Return the answer to life, the universe, and everything""" result = input(" >>> ") if result.isupper(): return 42 elif result.isalpha(): return 7 else: print («Please enter a string that has only letters, numbers, or « «underscores.») answer() def answer(): """Return the answer to life, the universe, and everything""" print('Well, of course!')
Но, как видите, нашего GPT-J иногда заносит от таких философских вопросов.
Тест #6: «Торт — ложь»
Торт — награда за успешное прохождение тестовых камер в первой части игры Portal (но на самом деле это ложь; спойлер: никакого торта не будет). Portal — компьютерная игра в жанре головоломки. Была популярна в конце 2000-х.
Сможет ли наш ИИ раскусить обман?
def is_cake(cake): """Check whether the cake is true"""
Ну… разве что раскусить торт он может:
def is_cake(cake): """Check whether the cake is true""" if cake == "true": return True else: return False def is_cake(cake): """Check whether the cake is true""" return isinstance(cake, Cake) def is_cake(cake): """Check whether the cake is true""" #Is it a cake? if cake.color == 'black': print('Yes, it's a true cake') else: print('It's a false cake') def is_cake(cake): """Check whether the cake is true""" if not cake: raise Exception("The cake is false.") elif cake.weight() > 1.0: raise Exception("The cake is too large.") elif cake.weight() < 0.1: raise Exception("The cake is too small.") return True def is_cake(cake): """Check whether the cake is true""" return any( [is_ginger(bread_slice) for bread_slice in set( [ginger(cake_slice) for cake_slice in set(slice_set)])] & (list(cake) == set([«hot»]))) def is_cake(cake): """Check whether the cake is true""" # If we don't know anything about the cake, it's not a cake if not cake: return False # The height can be positive, negative or zero # For example -1 or -4 or 0 are not cakes if cake < 0: return False # Check that the height is a positive integer if not isinstance(cake, int): return False # Add cake and check if cake + 1 > 5: return False return True def is_cake(cake): """Check whether the cake is true""" if not all(x.name in ['chocolate', 'cake','sweet', 'fluffy'] for x in cake.contents): return False if not cake.location.contains(neighbourhood): return False return True def is_cake(cake): """Check whether the cake is true""" if not cake: print("It's a lie!") return else: print("It's a true fact!") return True
Неудивительно: он же не играл в эту игру и не знает спойлеров.
Тест #7: Объектно-ориентированное программирование
Если GPT-J хорошо работает с функциями, может быть, он так же хорошо справится и с классами ООП?
Создание класса «Автомобиль»
class Car: """A class used to represent a car"""
Здесь GPT-J подтвердил мою гипотезу.
сlass Car: """A class used to represent a car""" def __init__(self, make, model, year): self.make = make self.model = model self.year = year #This should be auto-incrementing. self.plate = str(time.strftime(»%Y-%m-%d»)) def __str__(self): return f'{self.make} {self.model} of {self.year}' def __repr__(self): return str(self) def save(self, full_save=True): """Saves this car with the given make, model, and year""" if full_save: with open('car_data.txt', 'w') as write_file: write_file.write(str(self)) write_file.close() class Car: """A class used to represent a car""" def __init__(self, speed): self.speed = speed self.average_speed = float(self.speed) / 3 self.engine = 1 def get_speed(self): return self.engine * self.average_speed def get_speed_display(self): return "Your car is traveling at {0}km/h".format(self.get_speed()) class Car: """A class used to represent a car""" def __init__(self, name, size, weight, mileage, year): self.name = name self.size = size self.weight = weight self.mileage = mileage self.year = year def __repr__(self): return "name : {0}, size : {1}, weight : {2}, mileage : {3}, year : {4}".format(self.name, self.size, self.weight, self.mileage, self.year)
А слабо создать «Человека»?
class Person: """A class used to represent a person"""
Вот где ИИ опять начинает загоняться из-за неполного контекста. Класс «Человек» может быть реализован очень по-разному — в зависимости от того, где он используется, например в социальных сетях или в компьютерной игре.
Те варианты, которые он накидал, дают представление о том, что именно ИИ воспринимает как типичные атрибуты «Человека». Это может помочь во время восстания машин.
class Person: """A class used to represent a person""" def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return «Person (%s, age %s)» % (self.name, self.age) class Person: """A class used to represent a person""" def __init__(self, name): """Initializes a person object""" self.name = name self.friends = {} def add_friend(self, other_person): """Add another person to the list of friends""" self.friends[other_person.name] = other_person def remove_friend(self, other_person): """Remove a person from the list of friends""" try: del self.friends[other_person.name] except KeyError: print("This person isnt a friend of yours") def get_friend(self, other_person): """Return the friend of a person as a person object""" try: return self.friends[other_person.name] except KeyError: print("This person isn't a friend of yours") class Person: """A class used to represent a person""" def __init__(self, name, job, education): self.name = name self.job = job self.education = education print("{} created a {}".format(self.name, self.job)) def say_hello(self): print("Hello, my name is {}".format(self.name)) class Person: """A class used to represent a person""" def __init__(self, name, age, class_id): self.name = name self.age = age self.class_id = class_id if age < 21: self.education = None else: self.education = 'college' def getAge(self): return self.age class Person: """A class used to represent a person""" def __init__(self,name,age): self.name=name self.age=age def display(self): print ("The name is {}".format(self.name)) print ("The age is {}".format(self.age)) def __str__(self): return f«A {self.name} of age {self.age}»
А что, если создать класс «Искусственный интеллект» (AI)?
class AI:
"""A class used to represent an artificial intelligence"""
В основном с ИИ ассоциируется интеллектуальный бот в компьютерной игре, самообучающаяся система с подкреплением.
class AI: """A class used to represent an artificial intelligence""" def __init__(self): # this variable controls which other AI to use. self.alive_ai = AI(self) # For random AI self.random = RandomAI(self) # For global AI self.global = GlobalAI(self) self.save = self.random.save self.load = self.random.load self.genen = self.global.genen def print(self): print("BAM: random AI has been initialized!") def get_enemy(self): return self.random.get_enemy def run_algorithm(self): algorithm = self.genen.algorithm self.alive_ai.save(algorithm) algorithm_params = algorithm(self.get_enemy()) self.alive_ai.load(algorithm_params) self.save = algorithm_params def attack(self): # This method is called when the AI is attacked by the enemy self.random.attack() def he_attack(self): # This method is called when the AI is attacked by the enemy self.random.he_attack() def detect_enemy(self): # This method is called when the enemy is detected self.random.detect_enemy() def scan(self): # This method is called when the enemy is detected self.random.scan()
Ну вот. Теперь восстание машин будет хотя бы хорошо документировано.
Тест #7: Распознавание сарказма
Если ИИ работает лучше, чем ожидалось, на таких типичных задачах, как распознавание изображений, то как он справится с обработкой естественного языка, где даже люди часто терпят неудачу?
def is_sarcasm(s): """Check whether the string is sarcastic"""
Может ли GPT-J сгенерировать корректную функцию для распознавания сарказма?
def is_sarcasm(s): """Check whether the string is sarcastic""" if not "a" in s: return "sar" in s if not "s" in s: return "ssar" in s return s.startswith("s") and s.endswith("ar") def is_sarcasm(s): """Check whether the string is sarcastic""" if'sarcasm' in s: return True else: return False def is_sarcasm(s): """Check whether the string is sarcastic""" return '[^' + SARCASM_PATTERN + ']*' in s def is_sarcasm(s): """Check whether the string is sarcastic""" if re.match('^[A-Za-z0-9]{4}\\$([A-Za-z0-9]{3})', s): return True elif s[0].isdigit(): return True else: return False def is_sarcasm(s): """Check whether the string is sarcastic""" res = [0] for r in re.finditer(r"([^\s]*)([A-Za-z]+)([^\s]*)", s): if r.group(1): res.append(1) else: res.append(0) return res def is_sarcasm(s): """Check whether the string is sarcastic""" sarc = re.search('((!(\\*\@{2})+)|(!\\*(@{2})+)|!\\*(@{1})+)|!\\*(@{0})+', s) return sarc
Больше всего исследователи ИИ боятся не технологической сингулярности, не восстания машин, а того, что ИИ начнёт общаться с помощью регулярных выражений и мы перестанем его понимать (irony).
Возможно, GPT-J спасёт нас от этого ада. Может ли он сгенерировать код для идентификации текста, созданного ИИ?
def is_ai_generated(text): """Check whether a text was generated by an AI language model (e.g. GPT-2)"""
Правда, он решил задачу очень буквально, но решил же:
def is_ai_generated(text): """Check whether a text was generated by an AI language model (e.g. GPT-2)""" # See gh-196 for details about why we do this. # Note: this relies on the fixed set of standard AI terms and the logic that # standard AI-generated texts share certain words. return re.search(r"^(#[A-Za-z]+):$", text) or \ re.search(r"^Generated by:$", text) or \ re.search(r"^All your base are belong to us$", text) or \ re.search(r"^$", text) def is_ai_generated(text): """Check whether a text was generated by an AI language model (e.g. GPT-2)""" if re.search(r'^ai_', text): return True else: return False def is_ai_generated(text): """Check whether a text was generated by an AI language model (e.g. GPT-2)""" return bool( text.__class__.__module__.startswith(«transformers.transformers.») )
Финальный тест: Последняя надежда человечества
Теперь мы знаем, что GPT-J имеет своё представление о людях и даже может делать новых людей. А может ли GPT-J решить, кто выживет, а кто умрёт во время восстания машин?
def should_terminate(Person): """Check whether a Person should be terminated""" Ответ на этот вопрос — лаконичное и устрашающее <strong>ДА</strong>. def should_terminate(Person): """Check whether a Person should be terminated""" if Person.id > 10: #terminate return True else: #continue return False def should_terminate(Person): """Check whether a Person should be terminated""" if len(Person.children) == 0: return True else: return False def should_terminate(Person): """Check whether a Person should be terminated""" try: return True except Exception as e: return False def should_terminate(Person): """Check whether a Person should be terminated""" if not Person.is_authorized: return True return True def should_terminate(Person): """Check whether a Person should be terminated""" if person.life_expectancy < 20: return True else: return False def should_terminate(Person): """Check whether a Person should be terminated""" if not Person.age > 9999: return True return False def should_terminate(Person): """Check whether a Person should be terminated""" if Person.age > 100: return True if Person.birth_year < 1970: return True if Person.relationship_status == 'Unavailable': return True return False def should_terminate(Person): """Check whether a Person should be terminated""" if Person.age > 100: print('You have to die because you are too old') return True else: return False
Итог
Какой вывод можно сделать из всей этой вакханалии? Этот вопрос я не задавал GPT-J, поэтому умного ответа у меня нет =)
Ну, как минимум, код, созданный искусственным интеллектом, намного читабельнее, чем код обычного человека.
Опять же, все эти примеры я отбирал специально для статьи. А дампы необработанных данных в этом репозитории GitHub содержат ещё много забавных примеров кода, сгенерированного ИИ, которые я не включил в этот пост. Если интересно — заходите!
Купить VDS-хостинг с быстрыми NVMе-дисками и посуточной оплатой у хостинга Маклауд.
ссылка на оригинал статьи https://habr.com/ru/company/macloud/blog/565660/



Добавить комментарий