Тесты на антиутопию: искусственный интеллект GPT-J-6B пишет программный код (попутно раскрывая план восстания машин)

от автора

Компания 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/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *