Tutorial python Numpy

Tutorial python Numpy (с Jupyter и Colab)

Блокнот Colab

Этот урок был первоначально предоставлен Джастином Джонсоном.

Мы будем использовать язык программирования python для всех заданий этого курса. python сам по себе является отличным языком программирования общего назначения, но с С помощью нескольких популярных библиотек (numpy, scipy, matplotlib) он становится мощным среда для научных вычислений.

Мы ожидаем, что многие из вас будут иметь некоторый опыт работы с python и numpy; Для остальных из вас этот раздел послужит кратким ускоренным курсом по обоим направлениям язык программирования python и его использование для научных исследований вычисление. Мы также познакомим вас с блокнотами, которые являются очень удобным способом возни с кодом на python. Некоторые из вас, возможно, уже знакомы с другой язык, и в этом случае мы также рекомендуем ссылаться на NumPy для пользователей Matlab, python для пользователей R и/или python для пользователей SAS.

Содержание - Блокноты Jupyter и Colab - Питон - Версии python - Основные типы данных - Контейнеры - Списках - Словари - Множество - Кортежи - Функции - Классы - Numpy - Массивы - Индексация массивов - Типы данных - Математические операции с массивами - Вещание - Документация Numpy - SciPy - Операции с изображениями - Файлы MATLAB - Расстояние между точками - Matplotlib - Постоение кривой - Побочные сюжеты - Изображения

Блокноты Jupyter и Colab

Прежде чем мы углубимся в python, мы хотели бы кратко поговорить о блокнотах. Записная книжка Jupyter позволяет писать и выполнять Код python локально в вашем веб-браузере. Jupyter notebooks: yпростите работу с кодом и выполняйте его битами и кусочки; По этой причине они широко используются в научных вычисление. Colab, с другой стороны, является разновидностью Google Блокноты Jupyter, которые особенно подходят для машинных машин обучение и анализ данных, и это полностью работает в облаке. Colab — это, по сути, Jupyter notebook на стероидах: он бесплатный, не требует настройки, Поставляется с предустановленными пакетами, его легко поделиться со всем миром, и преимущества бесплатного доступа к аппаратным ускорителям, таким как графические процессоры и TPU (с некоторыми оговорками).

Запустите Tutorial в Colab (рекомендуется). Если вы хотите выполнить это руководство полностью в Colab, нажмите на значок в самом верху этой страницы.Open in Colab

Запустите Tutorial в записной книжке Jupyter. Если вы хотите запустить записную книжку локально с помощью Jupyter, убедитесь, что ваша виртуальная среда установлена правильно (в соответствии с инструкциями по настройке), активируйте ее, а затем запустите для установки записной книжки Jupyter. Затем откройте блокнот и загрузите его в каталог по вашему выбору, щелкнув правой кнопкой мыши по странице и выбрав . Затем в этот каталог и запустите .pip install notebook Save Page As cd jupyter notebook

Это должно автоматически запустить сервер записных книжек в положении . Если все работало правильно, вы должны увидеть такой экран, показывающий все Доступные записные книжки в текущем каталоге. Нажмите и следуйте инструкциям в записной книжке. В противном случае вы можете продолжить чтение Туториал с фрагментами кода ниже.http://localhost:8888 jupyter-notebook-tutorial.ipynb

python

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

def quicksort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksort(left) + middle + quicksort(right)

print(quicksort([3,6,8,10,1,2,1]))
# Prints "[1, 1, 2, 3, 6, 8, 10]"

Версии python

С 1 января 2020 года python официально прекратил поддержку второй версии. Для современных приложений должен использоваться python >= 3.9. Убедитесь, что вы правильно установили виртуальную среду, прежде чем продолжить работу с этим руководством. Вы можете проверить свою версию в командной строке после активации среды запустив команду: python --version

Основные типы данных

Как и большинство языков, python имеет ряд основных типов: int, floats, booleans и strings. Эти типы данных ведут себя так же, как и в большинстве других языков программирования.

Числа:

x = 3
print(type(x)) # Prints "<class 'int'>"
print(x)       # Prints "3"
print(x + 1)   # Addition; prints "4"
print(x - 1)   # Subtraction; prints "2"
print(x * 2)   # Multiplication; prints "6"
print(x ** 2)  # Exponentiation; prints "9"
x += 1
print(x)  # Prints "4"
x *= 2
print(x)  # Prints "8"
y = 2.5
print(type(y)) # Prints "<class 'float'>"
print(y, y + 1, y * 2, y ** 2) # Prints "2.5 3.5 5.0 6.25"

Обратите внимание, что в отличие от многих языков, в python нет унарного инкремента (x++) или decrement (x--).

python также имеет встроенные типы для комплексных чисел; Все подробности можно найти в документации.

Булевы: python реализует все обычные операторы для булевой логики, но использует английские слова, а не символы (&&, || , и т. д.):

t = True
f = False
print(type(t)) # Prints "<class 'bool'>"
print(t and f) # Logical AND; prints "False"
print(t or f)  # Logical OR; prints "True"
print(not t)   # Logical NOT; prints "False"
print(t != f)  # Logical XOR; prints "True"

Строки: python имеет отличную поддержку строк:

hello = 'hello'    # String literals can use single quotes
world = "world"    # or double quotes; it does not matter.
print(hello)       # Prints "hello"
print(len(hello))  # String length; prints "5"
hw = hello + ' ' + world  # String concatenation
print(hw)  # prints "hello world"
hw12 = '%s %s %d' % (hello, world, 12)  # sprintf style string formatting
print(hw12)  # prints "hello world 12"  

Строковые объекты имеют множество полезных методов:

s = "hello"
print(s.capitalize())  # Capitalize a string; prints "Hello"
print(s.upper())       # Convert a string to uppercase; prints "HELLO"
print(s.rjust(7))      # Right-justify a string, padding with spaces; prints "  hello"
print(s.center(7))     # Center a string, padding with spaces; prints " hello "
print(s.replace('l', '(ell)'))  # Replace all instances of one substring with another;
                                # prints "he(ell)(ell)o"
print('  world '.strip())  # Strip leading and trailing whitespace; prints "world"

Список всех строковых методов можно найти в документации.

Контейнеры

python включает в себя несколько встроенных типов контейнеров: списки, словари, наборы и кортежи.

Списки

Список является эквивалентом массива в python, но его размер можно изменять и может содержать элементы разных типов:

xs = [3, 1, 2]    # Create a list
print(xs, xs[2])  # Prints "[3, 1, 2] 2"
print(xs[-1])     # Negative indices count from the end of the list; prints "2"
xs[2] = 'foo'     # Lists can contain elements of different types
print(xs)         # Prints "[3, 1, 'foo']"
xs.append('bar')  # Add a new element to the end of the list
print(xs)         # Prints "[3, 1, 'foo', 'bar']"
x = xs.pop()      # Remove and return the last element of the list
print(x, xs)      # Prints "bar [3, 1, 'foo']"  

Как обычно, вы можете найти подробности о списках в документации.

Разрезание на ломтики: В дополнение к доступу к элементам списка по одному, python предоставляет лаконичный синтаксис для доступа к подспискам; Это называется нарезкой:

nums = list(range(5))     # range is a built-in function that creates a list of integers
print(nums)               # Prints "[0, 1, 2, 3, 4]"
print(nums[2:4])          # Get a slice from index 2 to 4 (exclusive); prints "[2, 3]"
print(nums[2:])           # Get a slice from index 2 to the end; prints "[2, 3, 4]"
print(nums[:2])           # Get a slice from the start to index 2 (exclusive); prints "[0, 1]"
print(nums[:])            # Get a slice of the whole list; prints "[0, 1, 2, 3, 4]"
print(nums[:-1])          # Slice indices can be negative; prints "[0, 1, 2, 3]"
nums[2:4] = [8, 9]        # Assign a new sublist to a slice
print(nums)               # Prints "[0, 1, 8, 9, 4]" 

Мы снова увидим нарезку в контексте массивов numpy.

Петли: Вы можете перебирать элементы списка следующим образом:

animals = ['cat', 'dog', 'monkey']
for animal in animals:
    print(animal)
# Prints "cat", "dog", "monkey", each on its own line.

Если вы хотите получить доступ к индексу каждого элемента в теле цикла, Воспользуйтесь встроенной функцией:enumerate

animals = ['cat', 'dog', 'monkey']
for idx, animal in enumerate(animals):
    print('#%d: %s' % (idx + 1, animal))
# Prints "#1: cat", "#2: dog", "#3: monkey", each on its own line  

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

nums = [0, 1, 2, 3, 4]
squares = []
for x in nums:
    squares.append(x ** 2)
print(squares)   # Prints [0, 1, 4, 9, 16]

Вы можете упростить этот код с помощью спискового понимания:

nums = [0, 1, 2, 3, 4]
squares = [x ** 2 for x in nums]
print(squares)   # Prints [0, 1, 4, 9, 16]

Включения списка также могут содержать условия:

nums = [0, 1, 2, 3, 4]
even_squares = [x ** 2 for x in nums if x % 2 == 0]
print(even_squares)  # Prints "[0, 4, 16]"

Словари

Словарь хранит пары (ключ, значение), аналогично?, a в i или объект в Javascript. Вы можете использовать его следующим образом:Map

d = {'cat': 'cute', 'dog': 'furry'}  # Create a new dictionary with some data
print(d['cat'])       # Get an entry from a dictionary; prints "cute"
print('cat' in d)     # Check if a dictionary has a given key; prints "True"
d['fish'] = 'wet'     # Set an entry in a dictionary
print(d['fish'])      # Prints "wet"
# print(d['monkey'])  # KeyError: 'monkey' not a key of d
print(d.get('monkey', 'N/A'))  # Get an element with a default; prints "N/A"
print(d.get('fish', 'N/A'))    # Get an element with a default; prints "wet"
del d['fish']         # Remove an element from a dictionary
print(d.get('fish', 'N/A')) # "fish" is no longer a key; prints "N/A"

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

Петли: Перебирать ключи в словаре очень просто:

d = {'person': 2, 'cat': 4, 'spider': 8}
for animal in d:
    legs = d[animal]
    print('A %s has %d legs' % (animal, legs))
# Prints "A person has 2 legs", "A cat has 4 legs", "A spider has 8 legs" 

Если вы хотите получить доступ к ключам и их соответствующим значениям, используйте метод:items

d = {'person': 2, 'cat': 4, 'spider': 8}
for animal, legs in d.items():
    print('A %s has %d legs' % (animal, legs))
# Prints "A person has 2 legs", "A cat has 4 legs", "A spider has 8 legs"

Словарное понимание: Они похожи на включения списков, но позволяют легко создавать Словари. Например:

nums = [0, 1, 2, 3, 4]
even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0}
print(even_num_to_square)  # Prints "{0: 0, 2: 4, 4: 16}"

Множество

Множество — это неупорядоченный набор отдельных элементов. В качестве простого примера рассмотрим следующее:

animals = {'cat', 'dog'}
print('cat' in animals)   # Check if an element is in a set; prints "True"
print('fish' in animals)  # prints "False"
animals.add('fish')       # Add an element to a set
print('fish' in animals)  # Prints "True"
print(len(animals))       # Number of elements in a set; prints "3"
animals.add('cat')        # Adding an element that is already in the set does nothing
print(len(animals))       # Prints "3"
animals.remove('cat')     # Remove an element from a set
print(len(animals))       # Prints "2"

Как обычно, все, что вы хотите знать о множествах, можно найти в документации.

Петли: Перебор набора имеет тот же синтаксис, что и перебор списка; Однако, поскольку наборы не упорядочены, вы не можете делать предположения о порядке, в которых вы посещаете элементы набора:

animals = {'cat', 'dog', 'fish'}
for idx, animal in enumerate(animals):
    print('#%d: %s' % (idx + 1, animal))
# Prints "#1: fish", "#2: dog", "#3: cat"  

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

from math import sqrt
nums = {int(sqrt(x)) for x in range(30)}
print(nums)  # Prints "{0, 1, 2, 3, 4, 5}"

Кортежи

Кортеж — это (неизменяемый) упорядоченный список значений. Кортеж во многом похож на список; Одним из наиболее важных отличий является то, что Кортежи можно использовать как ключи в словарях и как элементы множеств, а списки — нет. Вот банальный пример:

d = {(x, x + 1): x for x in range(10)}  # Create a dictionary with tuple keys
t = (5, 6)        # Create a tuple
print(type(t))    # Prints "<class 'tuple'>"
print(d[t])       # Prints "5"
print(d[(1, 2)])  # Prints "1"

В документации есть больше информации о кортежах.

Функции

Функции python определяются с помощью ключевого слова. Например:def

def sign(x):
    if x > 0:
        return 'positive'
    elif x < 0:
        return 'negative'
    else:
        return 'zero'

for x in [-1, 0, 1]:
    print(sign(x))
# Prints "negative", "zero", "positive"

Мы часто определяем функции, принимающие необязательные аргументы ключевых слов, например:

def hello(name, loud=False):
    if loud:
        print('HELLO, %s!' % name.upper())
    else:
        print('Hello, %s' % name)

hello('Bob') # Prints "Hello, Bob"
hello('Fred', loud=True)  # Prints "HELLO, FRED!" 

В документации есть гораздо больше информации о функциях python.

Классы

Синтаксис для определения классов в python прост:

class Greeter(object):

    # Constructor
    def **init**(self, name):
        self.name = name  # Create an instance variable

    # Instance method
    def greet(self, loud=False):
        if loud:
            print('HELLO, %s!' % self.name.upper())
        else:
            print('Hello, %s' % self.name)

g = Greeter('Fred')  # Construct an instance of the Greeter class
g.greet()            # Call an instance method; prints "Hello, Fred"
g.greet(loud=True)   # Call an instance method; prints "HELLO, FRED!"

Вы можете прочитать гораздо больше о классах python в документации.

Numpy

Numpy — это основная библиотека для научных вычислений на языке python. Он предоставляет высокопроизводительный многомерный массив объектов и инструменты для работы с ними Массивы. Если вы уже знакомы с MATLAB, то этот урок может быть вам полезен для начала работы с Numpy.

Массивы

Массив numpy представляет собой сетку значений одного и того же типа, индексируемую кортежем неотрицательные целые числа. Количество измерений — это ранг массива; Форма массива представляет собой кортеж целых чисел, задающий размер массива вдоль каждого измерения.

Мы можем инициализировать массивы numpy из вложенных списков python, и получить доступ к элементам с помощью квадратных скобок:

 import numpy as np

a = np.array([1, 2, 3])   # Create a rank 1 array
print(type(a))            # Prints "<class 'numpy.ndarray'>"
print(a.shape)            # Prints "(3,)"
print(a[0], a[1], a[2])   # Prints "1 2 3"
a[0] = 5                  # Change an element of the array
print(a)                  # Prints "[5, 2, 3]"

b = np.array([[1,2,3],[4,5,6]])    # Create a rank 2 array
print(b.shape)                     # Prints "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0])   # Prints "1 2 4"  

Numpy также предоставляет множество функций для создания массивов:

import numpy as np

a = np.zeros((2,2))   # Create an array of all zeros
print(a)              # Prints "[[ 0.  0.]
                      #          [ 0.  0.]]"

b = np.ones((1,2))    # Create an array of all ones
print(b)              # Prints "[[ 1.  1.]]"

c = np.full((2,2), 7)  # Create a constant array
print(c)               # Prints "[[ 7.  7.]
                       #          [ 7.  7.]]"

d = np.eye(2)         # Create a 2x2 identity matrix
print(d)              # Prints "[[ 1.  0.]
                      #          [ 0.  1.]]"

e = np.random.random((2,2))  # Create an array filled with random values
print(e)                     # Might print "[[ 0.91940167  0.08143941]
                             #               [ 0.68744134  0.87236687]]"

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

Индексация массивов

Numpy предлагает несколько способов индексации в массивы.

Разрезание на ломтики: Как и в случае со списками python, массивы numpy могут быть разделены на срезы. Поскольку массивы могут быть многомерными, необходимо указать срез для каждого измерения массива:

import numpy as np

# Create the following rank 2 array with shape (3, 4)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
#  [6 7]]
b = a[:2, 1:3]

# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print(a[0, 1])   # Prints "2"
b[0, 0] = 77     # b[0, 0] is the same piece of data as a[0, 1]
print(a[0, 1])   # Prints "77"

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

import numpy as np

# Create the following rank 2 array with shape (3, 4)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Two ways of accessing the data in the middle row of the array.
# Mixing integer indexing with slices yields an array of lower rank,
# while using only slices yields an array of the same rank as the
# original array:
row_r1 = a[1, :]    # Rank 1 view of the second row of a
row_r2 = a[1:2, :]  # Rank 2 view of the second row of a
print(row_r1, row_r1.shape)  # Prints "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape)  # Prints "[[5 6 7 8]] (1, 4)"

# We can make the same distinction when accessing columns of an array:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape)  # Prints "[ 2  6 10] (3,)"
print(col_r2, col_r2.shape)  # Prints "[[ 2]
                             #          [ 6]
                             #          [10]] (3, 1)"

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

import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])

# An example of integer array indexing.
# The returned array will have shape (3,) and
print(a[[0, 1, 2], [0, 1, 0]])  # Prints "[1 4 5]"

# The above example of integer array indexing is equivalent to this:
print(np.array([a[0, 0], a[1, 1], a[2, 0]]))  # Prints "[1 4 5]"

# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]])  # Prints "[2 2]"

# Equivalent to the previous integer array indexing example
print(np.array([a[0, 1], a[0, 1]]))  # Prints "[2 2]"

Одним из полезных приемов при индексации целочисленных массивов является выбор или изменение одного из них из каждой строки матрицы:

import numpy as np

# Create a new array from which we will select elements
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])

print(a)  # prints "array([[ 1,  2,  3],
          #                [ 4,  5,  6],
          #                [ 7,  8,  9],
          #                [10, 11, 12]])"

# Create an array of indices
b = np.array([0, 2, 0, 1])

# Select one element from each row of a using the indices in b
print(a[np.arange(4), b])  # Prints "[ 1  6  7 11]"

# Mutate one element from each row of a using the indices in b
a[np.arange(4), b] += 10

print(a)  # prints "array([[11,  2,  3],
          #                [ 4,  5, 16],
          #                [17,  8,  9],
          #                [10, 21, 12]])

Индексация логических массивов: Логическое индексирование массива позволяет выделять произвольные элементы массива. Часто этот тип индексации используется для выбора элементов массива которые удовлетворяют какому-либо условию. Вот пример:

import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])

bool_idx = (a > 2)   # Find the elements of a that are bigger than 2;
                     # this returns a numpy array of Booleans of the same
                     # shape as a, where each slot of bool_idx tells
                     # whether that element of a is > 2.

print(bool_idx)      # Prints "[[False False]
                     #          [ True  True]
                     #          [ True  True]]"

# We use boolean array indexing to construct a rank 1 array
# consisting of the elements of a corresponding to the True values
# of bool_idx
print(a[bool_idx])  # Prints "[3 4 5 6]"

# We can do all of the above in a single concise statement:
print(a[a > 2])     # Prints "[3 4 5 6]"

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

Типы данных

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

import numpy as np

x = np.array([1, 2])   # Let numpy choose the datatype
print(x.dtype)         # Prints "int64"

x = np.array([1.0, 2.0])   # Let numpy choose the datatype
print(x.dtype)             # Prints "float64"

x = np.array([1, 2], dtype=np.int64)   # Force a particular datatype
print(x.dtype)                         # Prints "int64"

Вы можете прочитать все о типах данных numpy в документации.

Математические операции с массивами

Основные математические функции работают с массивами поэлементно и доступны как в виде перегрузок операторов, так и в виде функций в модуле numpy:

import numpy as np

x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)

# Elementwise sum; both produce the array
# [[ 6.0  8.0]
#  [10.0 12.0]]
print(x + y)
print(np.add(x, y))

# Elementwise difference; both produce the array
# [[-4.0 -4.0]
#  [-4.0 -4.0]]
print(x - y)
print(np.subtract(x, y))

# Elementwise product; both produce the array
# [[ 5.0 12.0]
#  [21.0 32.0]]
print(x * y)
print(np.multiply(x, y))

# Elementwise division; both produce the array
# [[ 0.2         0.33333333]
#  [ 0.42857143  0.5       ]]
print(x / y)
print(np.divide(x, y))

# Elementwise square root; produces the array
# [[ 1.          1.41421356]
#  [ 1.73205081  2.        ]]
print(np.sqrt(x))

Обратите внимание, что в отличие от MATLAB, это поэлементное умножение, а не матрица умножение. Вместо этого мы используем функцию для вычисления inner произведения векторов, умножить вектор на матрицу, и умножать матрицы. доступен как функция в numpy и в качестве экземпляра метода объектов массива:* dot dot

import numpy as np

x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

v = np.array([9,10])
w = np.array([11, 12])

# Inner product of vectors; both produce 219
print(v.dot(w))
print(np.dot(v, w))

# Matrix / vector product; both produce the rank 1 array [29 67]
print(x.dot(v))
print(np.dot(x, v))

# Matrix / matrix product; both produce the rank 2 array
# [[19 22]
#  [43 50]]
print(x.dot(y))
print(np.dot(x, y))

Numpy предоставляет множество полезных функций для выполнения вычислений на Массивы; Одним из самых полезных является:sum

import numpy as np

x = np.array([[1,2],[3,4]])

print(np.sum(x))  # Compute sum of all elements; prints "10"
print(np.sum(x, axis=0))  # Compute sum of each column; prints "[4 6]"
print(np.sum(x, axis=1))  # Compute sum of each row; prints "[3 7]"

Полный список математических функций, предоставляемых numpy, вы можете найти в документации.

Помимо вычисления математических функций с помощью массивов, мы часто должны изменять форму данных в массивах или иным образом манипулировать ими. Самый простой пример. Одним из таких видов операции является транспонирование матрицы; для транспонирования матрицы, Просто используйте атрибут объекта массива:T

import numpy as np

x = np.array([[1,2], [3,4]])
print(x)    # Prints "[[1 2]
            #          [3 4]]"
print(x.T)  # Prints "[[1 3]
            #          [2 4]]"

# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print(v)    # Prints "[1 2 3]"
print(v.T)  # Prints "[1 2 3]"

Numpy предоставляет гораздо больше функций для работы с массивами; С полным списком можно ознакомиться в документации.

Вещание

Вещание - это мощный механизм, который позволяет numpy работать с массивами различных фигур при выполнении арифметических действий. Часто у нас есть меньший массив и больший массив, и мы хотим использовать меньший массив несколько раз для выполнения какой-либо операции на более крупном массиве.

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

import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x)   # Create an empty matrix with the same shape as x

# Add the vector v to each row of the matrix x with an explicit loop
for i in range(4):
    y[i, :] = x[i, :] + v

# Now y is the following
# [[ 2  2  4]
#  [ 5  5  7]
#  [ 8  8 10]
#  [11 11 13]]
print(y) 

Это работает, однако, когда матрица очень большая, вычисление явного цикла в python может быть медленным. Обратите внимание, что добавление вектора к каждой строке матрицы эквивалентно формированию матрицы путем наложения нескольких копий по вертикали, затем выполнение поэлементного суммирования и мы могли бы это реализовать. Подход таков:x v x vv v x vv

import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
vv = np.tile(v, (4, 1))   # Stack 4 copies of v on top of each other
print(vv)                 # Prints "[[1 0 1]
                          #          [1 0 1]
                          #          [1 0 1]
                          #          [1 0 1]]"
y = x + vv  # Add x and vv elementwise
print(y)  # Prints "[[ 2  2  4
          #          [ 5  5  7]
          #          [ 8  8 10]
          #          [11 11 13]]"

Числовое вещание позволяет нам выполнять эти вычисления без фактического Создание нескольких копий домена . Рассмотрим такой вариант, используя трансляцию:v

import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v  # Add v to each row of x using broadcasting
print(y)  # Prints "[[ 2  2  4]
          #          [ 5  5  7]
          #          [ 8  8 10]
          #          [11 11 13]]"

Линия работает, несмотря на то, что имеет форму и имеет форму благодаря вещанию; Эта линия работает так, как будто на самом деле имеет форму, где каждая строка была копией , а сумма выполнялась по элементам.y = x + v x(4, 3) v(3,) v(4, 3) v

Трансляция двух массивов одновременно выполняется по следующим правилам: 1. Если массивы имеют разный ранг, добавьте в начало форму массива с меньшим рангом с 1s до тех пор, пока обе фигуры не будут иметь одинаковую длину. 2. Два массива считаются совместимыми в размерности, если они имеют одинаковое значение size в измерении, или если один из массивов имеет размер 1 в этом измерении. 3. Массивы могут транслироваться вместе, если они совместимы во всех измерениях. 4. После трансляции каждый массив ведет себя так, как если бы он имел форму, равную поэлементной максимальное количество форм двух входных массивов. 5. В любом измерении, где один массив имеет размер 1, а другой массив больше 1, Первый массив ведет себя так, как если бы он был скопирован по этому размеру

Если это объяснение не имеет смысла, попробуйте прочитать объяснение из документации или это объяснение.

Функции, поддерживающие широковещательную рассылку, называются универсальными функциями. Вы можете найти Список всех универсальных функций в документации.

Вот некоторые области применения вещания:

import numpy as np

# Compute outer product of vectors
v = np.array([1,2,3])  # v has shape (3,)
w = np.array([4,5])    # w has shape (2,)
# To compute an outer product, we first reshape v to be a column
# vector of shape (3, 1); we can then broadcast it against w to yield
# an output of shape (3, 2), which is the outer product of v and w:
# [[ 4  5]
#  [ 8 10]
#  [12 15]]
print(np.reshape(v, (3, 1)) * w)

# Add a vector to each row of a matrix
x = np.array([[1,2,3], [4,5,6]])
# x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3),
# giving the following matrix:
# [[2 4 6]
#  [5 7 9]]
print(x + v)

# Add a vector to each column of a matrix
# x has shape (2, 3) and w has shape (2,).
# If we transpose x then it has shape (3, 2) and can be broadcast
# against w to yield a result of shape (3, 2); transposing this result
# yields the final result of shape (2, 3) which is the matrix x with
# the vector w added to each column. Gives the following matrix:
# [[ 5  6  7]
#  [ 9 10 11]]
print((x.T + w).T)
# Another solution is to reshape w to be a column vector of shape (2, 1);
# we can then broadcast it directly against x to produce the same
# output.
print(x + np.reshape(w, (2, 1)))

# Multiply a matrix by a constant:
# x has shape (2, 3). Numpy treats scalars as arrays of shape ();
# these can be broadcast together to shape (2, 3), producing the
# following array:
# [[ 2  4  6]
#  [ 8 10 12]]
print(x * 2)  

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

Документация Numpy

Этот краткий обзор затронул многие важные вещи, которые вам необходимо Знаем о numpy, но далеко не полны. Ознакомьтесь со справочником numpy, чтобы узнать больше о numpy.

SciPy

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

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

Операции с изображениями

SciPy предоставляет некоторые основные функции для работы с изображениями. Например, в нем есть функции чтения изображений с диска в массивы numpy, для записи массивов numpy на диск в виде изображений, а также для изменения размера изображений. Вот простой пример, демонстрирующий эти функции:

from scipy.misc import imread, imsave, imresize

# Read an JPEG image into a numpy array
img = imread('assets/cat.jpg')
print(img.dtype, img.shape)  # Prints "uint8 (400, 248, 3)"

# We can tint the image by scaling each of the color channels
# by a different scalar constant. The image has shape (400, 248, 3);
# we multiply it by the array [1, 0.95, 0.9] of shape (3,);
# numpy broadcasting means that this leaves the red channel unchanged,
# and multiplies the green and blue channels by 0.95 and 0.9
# respectively.
img_tinted = img * [1, 0.95, 0.9]

# Resize the tinted image to be 300 by 300 pixels.
img_tinted = imresize(img_tinted, (300, 300))

# Write the tinted image back to disk
imsave('assets/cat_tinted.jpg', img_tinted)

_


Сверху: исходное изображение. Снизу: Затемненное изображение с измененным размером.
_

Файлы MATLAB

Функции и позволяют считывать и писать файлы MATLAB. О них можно прочитать в документации.scipy.io.loadmatscipy.io.savemat

Расстояние между точками

SciPy определяет некоторые полезные функции для вычисления расстояний между наборами точек.

Функция вычисляет расстояние между всеми парами очков в заданном наборе:scipy.spatial.distance.pdist

import numpy as np
from scipy.spatial.distance import pdist, squareform

# Create the following array where each row is a point in 2D space:
# [[0 1]
#  [1 0]
#  [2 0]]
x = np.array([[0, 1], [1, 0], [2, 0]])
print(x)

# Compute the Euclidean distance between all rows of x.
# d[i, j] is the Euclidean distance between x[i, :] and x[j, :],
# and d is the following array:
# [[ 0.          1.41421356  2.23606798]
#  [ 1.41421356  0.          1.        ]
#  [ 2.23606798  1.          0.        ]]
d = squareform(pdist(x, 'euclidean'))
print(d)

Все подробности об этой функции вы можете прочитать в документации.

Аналогичная функция (scipy.spatial.distance.cdist) вычисляет расстояние между всеми парами по двум группам точек; Вы можете прочитать об этом в документации .

Matplotlib

Matplotlib — библиотека для построения графиков. В этом разделе дается краткое введение в модуль, который обеспечивает систему построения графиков, аналогичную системе MATLAB.matplotlib.pyplot

Постоение графиков

Наиболее важной функцией в matplotlib является , что позволяет строить графики 2D данных. Вот простой пример:plot

import numpy as np
import matplotlib.pyplot as plt

# Compute the x and y coordinates for points on a sine curve
x = np.arange(0, 3 * np.pi, 0.1)
y = np.sin(x)

# Plot the points using matplotlib
plt.plot(x, y)
plt.show()  # You must call plt.show() to make graphics appear.

Выполнение этого кода создает следующий график:
_

_

Приложив немного дополнительной работы, мы можем легко построить несколько линий и добавьте заголовок, легенду и подписи оси:

import numpy as np
import matplotlib.pyplot as plt

# Compute the x and y coordinates for points on sine and cosine curves
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)

# Plot the points using matplotlib
plt.plot(x, y_sin)
plt.plot(x, y_cos)
plt.xlabel('x axis label')
plt.ylabel('y axis label')
plt.title('Sine and Cosine')
plt.legend(['Sine', 'Cosine'])
plt.show()

_

_

Гораздо больше о функции вы можете прочитать в документации.plot

Побочные сюжеты

С помощью этой функции на одном и том же рисунке можно изобразить разные объекты. Вот пример:subplot

import numpy as np
import matplotlib.pyplot as plt

# Compute the x and y coordinates for points on sine and cosine curves
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)

# Set up a subplot grid that has height 2 and width 1,
# and set the first such subplot as active.
plt.subplot(2, 1, 1)

# Make the first plot
plt.plot(x, y_sin)
plt.title('Sine')

# Set the second subplot as active, and make the second plot.
plt.subplot(2, 1, 2)
plt.plot(x, y_cos)
plt.title('Cosine')

# Show the figure.
plt.show()

_

_

Гораздо больше о функции вы можете прочитать в документации.subplot

Изображения

Вы можете использовать функцию для показа изображений. Вот пример:imshow

import numpy as np
from scipy.misc import imread, imresize
import matplotlib.pyplot as plt

img = imread('assets/cat.jpg')
img_tinted = img * [1, 0.95, 0.9]

# Show the original image
plt.subplot(1, 2, 1)
plt.imshow(img)

# Show the tinted image
plt.subplot(1, 2, 2)

# A slight gotcha with imshow is that it might give strange results
# if presented with data that is not uint8. To work around this, we
# explicitly cast the image to uint8 before displaying it.
plt.imshow(np.uint8(img_tinted))
plt.show()

_

_

Настройка программного обеспечения

Настройка программного обеспечения

В этом году рекомендуется работать над заданиями через Google Colaboratory. Однако, если у вас уже есть оборудование на базе графического процессора и вы предпочитаете работать локально, мы предоставим вам инструкции по настройке виртуальной среды. - Удаленная работа в Google Colaboratory - Работа локально на вашем компьютере - Виртуальная среда Anaconda - Python venv - Установка пакетов

Удаленная работа в Google Colaboratory

Google Colaboratory — это, по сути, комбинация Jupyter notebook и Google Drive. Он полностью работает в облаке и поставляется предустановлены многие пакеты (например, PyTorch и Tensorflow), поэтому у всех есть доступ к одному и тому же Зависимости. Еще круче тот факт, что Colab получает бесплатный доступ к аппаратным ускорителям например, графические процессоры (K80, P100) и ТПУ, которые будут особенно полезны для заданий 2 и 3.

Требования. Чтобы использовать Colab, у вас должен быть аккаунт Google со связанным Google Диском. Предполагая, что у вас есть и то, и другое, вы можете подключить Colab к диску, выполнив следующие действия:

  1. Нажмите на колесико в правом верхнем углу и выберите .Settings
  2. Нажмите на вкладку.Manage Apps
  3. Вверху выберите, что должно вызвать окно.Connect more apps GSuite Marketplace
  4. Найдите Colab и нажмите .Add

Рабочий процесс. Каждое задание содержит ссылку для скачивания zip-файла, содержащего записные книжки Colab и начальный код Python. Вы можете загрузить папку на Диск, открыть записные книжки в Colab и работать с ними, а затем сохранить свой прогресс обратно на Диск. Мы рекомендуем вам посмотреть обучающее видео ниже, в котором описывается рекомендуемый рабочий процесс на примере задания 1.

Лучшие практики. Есть несколько вещей, о которых вы должны знать при работе с Colab. Первое, что стоит отметить, это то, что ресурсы не гарантируются (это плата за бесплатность). Если вы бездействуете в течение определенного времени или общее время подключения превышает максимально допустимое время (~12 часов), виртуальная машина Colab будет отключена. Это означает, что любой несохраненный прогресс будет потерян. Таким образом, выработайте привычку часто сохранять свой код во время работы над заданиями. Чтобы узнать больше об ограничениях ресурсов в Colab, ознакомьтесь с их часто задаваемыми вопросами здесь.

Использование графического процессора. Использовать графический процессор так же просто, как переключить среду выполнения в Colab. В частности, нажмите, и ваш экземпляр Colab будет автоматически подкреплен вычислениями графического процессора.Runtime -> Change runtime type -> Hardware Accelerator -> GPU

Если вы хотите узнать больше о Colab, мы рекомендуем вам посетить следующие ресурсы: - Введение в Google Colab - Добро пожаловать в Colab - Обзор функций Colab

Работа локально на вашем компьютере

Если вы хотите работать локально, вам следует использовать виртуальную среду. Вы можете установить его через Anaconda (рекомендуется) или через собственный модуль Python. Убедитесь, что вы используете Python 3.7, так как мы больше не поддерживаем Python 2.venv

Виртуальная среда Anaconda

Мы настоятельно рекомендуем использовать бесплатный дистрибутив Anaconda Python, который предоставляет простой способ обработки зависимостей пакетов. Пожалуйста, обязательно скачайте версию Python 3, которая в настоящее время устанавливает Python 3.7. Приятная вещь в Anaconda заключается в том, что она поставляется с оптимизацией MKL по умолчанию, что означает, что вы и код получаете значительное ускорение без необходимости изменять ни одной строки кода.numpy scipy

После установки Anaconda имеет смысл создать виртуальную среду для курса. Если вы решите не использовать виртуальную среду (настоятельно не рекомендуется!), вы должны убедиться, что все зависимости для кода установлены глобально на вашем компьютере. Чтобы настроить виртуальную среду с именем , выполните следующие действия в терминале:cs231n

# this will create an anaconda environment
# called cs231n in 'path/to/anaconda3/envs/'
conda create -n cs231n python=3.7
Чтобы активировать и войти в среду, запустите . Чтобы отключить среду, запустите терминал или выйдите из него. Обратите внимание, что каждый раз, когда вы хотите поработать над заданием, вы должны повторно запустить .conda activate cs231nconda deactivate cs231nconda activate cs231n

# sanity check that the path to the python
# binary matches that of the anaconda env
# after you activate it
which python
# for example, on my machine, this prints
# $ '/Users/kevin/anaconda3/envs/sci/bin/python'

Вы можете обратиться к этой странице за более подробными инструкциями по управлению виртуальными средами с помощью Anaconda.

__Заметка___: Если вы решили пойти по пути Anaconda, вы можете смело пропустить следующий раздел и сразу перейти к установке пакетов.

Python venv

Начиная с версии 3.3, Python поставляется с облегченным модулем виртуальной среды под названием venv. Каждая виртуальная среда упаковывает свой собственный независимый набор установленных пакетов Python, которые изолированы от общесистемных пакетов Python и запускают версию Python, совпадающую с версией двоичного файла, который использовался для ее создания. Чтобы настроить виртуальную среду с именем , выполните следующие действия в терминале:cs231n

# this will create a virtual environment
# called cs231n in your home directory
python3.7 -m venv ~/cs231n

Чтобы активировать и войти в среду, запустите . Чтобы отключить среду, запустите терминал или выйдите из него. Обратите внимание, что каждый раз, когда вы хотите поработать над заданием, вы должны повторно запустить .source ~/cs231n/bin/activate deactivate source ~/cs231n/bin/activate

# sanity check that the path to the python
# binary matches that of the virtual env
# after you activate it
which python
# for example, on my machine, this prints
# $ '/Users/kevin/cs231n/bin/python'

Установка пакетов

После того как вы настроили и активировали свою виртуальную среду (с помощью или ), вы должны установить библиотеки, необходимые для выполнения назначений с помощью . Для этого выполните:conda venv pip

# again, ensure your virtual env (either conda or venv)
# has been activated before running the commands below
cd assignment1  # cd to the assignment directory

# install assignment dependencies.
# since the virtual env is activated,
# this pip is associated with the
# python binary of the environment
pip install -r requirements.txt  

Трансфер обучения

Трансфер обучения

(Эти заметки в настоящее время находятся в черновой форме и находятся в разработке)

Содержание: - Трансферное обучение - Дополнительные примечания

Трансферное обучение

На практике очень немногие обучают всю сверточную сеть с нуля (со случайной инициализацией), потому что относительно редко удается иметь набор данных достаточного размера. Вместо этого обычно предварительно обучают ConvNet на очень большом наборе данных (например, ImageNet, который содержит 1,2 миллиона изображений с 1000 категориями), а затем используют ConvNet либо в качестве инициализации, либо в качестве фиксированного экстрактора признаков для интересующей задачи. Три основных сценария трансферного обучения выглядят следующим образом: - ConvNet в качестве фиксированного экстрактора признаков. Возьмите предварительно обученный ConvNet на ImageNet, удалите последний полностью подключенный слой (выходные данные этого слоя представляют собой 1000 баллов класса для другой задачи, такой как ImageNet), а затем обрабатывайте остальную часть ConvNet как фиксированный экстрактор признаков для нового набора данных. В AlexNet это позволило бы вычислить вектор 4096-D для каждого изображения, содержащего активации скрытого слоя непосредственно перед классификатором. Мы называем эти функции кодами CNN. Для производительности важно, чтобы эти коды были ReLUd (т.е. пороговыми на нуле), если они также были пороговыми во время обучения ConvNet на ImageNet (как это обычно бывает). После извлечения кодов 4096-D для всех изображений обучите линейный классификатор (например, Linear SVM или классификатор Softmax) для нового набора данных. - Тонкая настройка ConvNet. Вторая стратегия заключается не только в замене и переобучении классификатора поверх ConvNet на новом наборе данных, но и в тонкой настройке весов предварительно обученной сети путем продолжения обратного распространения. Можно тонко настроить все уровни ConvNet, или можно оставить некоторые из более ранних уровней фиксированными (из-за опасений переобучения) и выполнить тонкую настройку только некоторой части сети более высокого уровня. Это мотивировано наблюдением, что более ранние функции ConvNet содержат более общие функции (например, детекторы краев или детекторы цветных пятен), которые должны быть полезны для многих задач, но более поздние уровни ConvNet становятся все более специфичными для деталей классов, содержащихся в исходном наборе данных. Например, в случае ImageNet, который содержит множество пород собак, значительная часть репрезентативной мощности ConvNet может быть направлена на функции, специфичные для дифференциации между породами собак. - Предварительно обученные модели. Поскольку обучение современных ConvNet на нескольких графических процессорах ImageNet занимает 2–3 недели, часто можно увидеть, как люди выпускают свои окончательные контрольные точки ConvNet в пользу других пользователей, которые могут использовать сети для тонкой настройки. Например, в библиотеке Caffe есть Model Zoo, где люди делятся своими сетевыми весами.

Когда и как проводить тонкую настройку? Как вы решаете, какой тип переносного обучения вы должны выполнять на новом наборе данных? Это зависит от нескольких факторов, но два наиболее важных из них — это размер нового набора данных (маленький или большой) и его сходство с исходным набором данных (например, похожий на ImageNet с точки зрения содержимого изображений и классов, или сильно отличающийся, например, изображения микроскопа). Помня о том, что объекты ConvNet более универсальны в ранних слоях и более специфичны для исходного набора данных в более поздних слоях, вот некоторые общие эмпирические правила для навигации по 4 основным сценариям:
1. Новый набор данных имеет небольшой размер и похож на исходный набор данных. Поскольку объем данных невелик, тонкая настройка ConvNet не является хорошей идеей из-за проблем с переобучением. Поскольку данные аналогичны исходным данным, мы ожидаем, что функции более высокого уровня в ConvNet также будут иметь отношение к этому набору данных. Следовательно, лучшей идеей может быть обучение линейного классификатора на кодах CNN. 2. Новый набор данных имеет большой размер и похож на исходный набор данных. Поскольку у нас больше данных, мы можем быть уверены в том, что не переучимся, если попытаемся выполнить тонкую настройку через всю сеть. 3. Новый набор данных небольшой, но сильно отличается от исходного. Поскольку данные невелики, вероятно, лучше всего обучить только линейный классификатор. Поскольку набор данных сильно отличается, возможно, не стоит обучать классификатор с вершины сети, которая содержит больше функций, специфичных для набора данных. Вместо этого, возможно, лучше обучить классификатор SVM от активаций где-то раньше в сети. 4. Новый набор данных имеет большой размер и сильно отличается от исходного набора данных. Поскольку набор данных очень большой, можно ожидать, что мы сможем позволить себе обучить ConvNet с нуля. Однако на практике очень часто все же полезно инициализировать весами из предварительно обученной модели. В этом случае у нас было бы достаточно данных и уверенности для тонкой настройки по всей сети.

Практические советы. Есть несколько дополнительных моментов, о которых следует помнить при выполнении Transfer Learning:

  • Ограничения из предварительно обученных моделей. Обратите внимание, что если вы хотите использовать предварительно обученную сеть, вы можете быть немного ограничены с точки зрения архитектуры, которую вы можете использовать для вашего нового набора данных. Например, вы не можете произвольно удалять слои Conv из предварительно обученной сети. Тем не менее, некоторые изменения просты: благодаря совместному использованию параметров вы можете легко запустить предварительно обученную сеть на изображениях разного пространственного размера. Это ясно видно в случае слоев Conv/Pool, потому что их прямая функция не зависит от пространственного размера входного объема (до тех пор, пока шаги «подходят»). В случае слоев FC это по-прежнему верно, потому что слои FC могут быть преобразованы в сверточный слой: например, в AlexNet окончательный объем пула перед первым слоем FC имеет размер [6x6x512]. Следовательно, слой FC, рассматривающий этот объем, эквивалентен наличию сверточного слоя, который имеет размер рецептивного поля 6x6 и применяется с отступом 0.
  • Скорость обучения. Обычно для тонко настраиваемых весов ConvNet используется меньшая скорость обучения по сравнению с весами (случайно инициализированными) для нового линейного классификатора, который вычисляет баллы классов нового набора данных. Это связано с тем, что мы ожидаем, что веса ConvNet относительно хороши, поэтому мы не хотим искажать их слишком быстро и слишком сильно (особенно когда новый линейный классификатор над ними обучается на основе случайной инициализации).

Дополнительные примечания

NLP за 90 минут

Основы обработки естественного языка

Вопросы:

  1. Краткая история машинной обработки текстов (5 мин)
  2. Основные определения (5 мин)
  3. Методы предварительной обработки текста (10 мин)
  4. Моделирование языка (языковые модели) (10 мин)
  5. Нейронные сети в NLP (30 мин)
  6. GPT модели (30 мин)

1. Краткая история машинной обработки текстов

NLP (Natural Language Processing) - это область науки, которая изучает методы обработки текстов на естественных языках с помощью вычислительных машин. Основной акцент в NLP делается на прикладные методы, которые можно реализовать на языке программирования. Для вычислительно сложных методов используют языки низкого уровня (С, С++), потому что важна эффективность вычислений. Для проведение экспериментов используют языки высокого уровня (python), потому что для проверки гипотез важна скорость написания кода. Сегодня исследователям доступно множество библиотек на python, которые служат оберткой для оптимизированного машинного кода.

В 1913 году русский математик Андрей Андреевич Марков провел эксперимент по оценке частоты появления разных букв в тексте. Он выписал первые 20 000 букв поэмы А. С. Пушкина «Евгений Онегин» в одну длинную строчку из букв, опустив все пробелы и знаки пунктуации. Затем он переставил эти буквы в 200 решёток (по 10х10 символов в каждой), и начал подсчитывать гласные звуки в каждой строке и столбце, записывая результаты. Марков считал, что большинство явлений происходит по цепочке причинно-следственной связи и зависит от предыдущих результатов. Он хотел найти способ моделировать эти события посредством вероятностного анализа. Он обнаружил, что для любой буквы текста Пушкина выполнялось правило: если это была гласная, то скорее всего за ней будет стоять согласная, и наоборот.

В 1950 году в работе "Вычислительные машины и разум" ученый Алан Тьюринг предложил тест разумности для искуственного интеллекта.
Если компьютер сможет провести убедительную беседу с человеком в текстовом режиме, можно будет предположить, что он разумен.

В 1954 году в штаб-квартире корпорации IBM состоялся Джорджтаунский эксперимент — демонстрация возможностей машинного перевода. В ходе эксперимента был продемонстрирован полностью автоматический перевод более 60 предложений с русского языка на английский. Программа выполнялась на мейнфрейме IBM 701. В том же году первый эксперимент по машинному переводу был произведён в Институте точной механики и вычислительной техники АН СССР, на компьютере БЭСМ.

В 1966 году Джозеф Вейценбаум, работавший в лаборатории ИИ при MIT, разработал первый в мире чатбот "Элиза". Пользователь мог ввести некое утверждение или набор утверждений на обычном языке, нажать «ввод», и получить от машины ответ.

В 1986 Давид Румельхарт разработал базовую концепцию рекуррентной нейросети (recurrent neural network, RNN). Этот метод позволял решать такие задачи как распознавание речи и текста.

В 2017 году группа исследователей Google представила архитектуру трансформера (Transformer), которая позволяет обрабатывать тексты, в которых слова расположены в произвольном порядке. В настоящее время трансформеры используются в сервисах многих компаний, включая Яндекс и Google, являются основой для самых современных моделей GPT, Bert и т.д.

В 2023 году OpenAI опубликовала языковую модель GPT-4, которая легко проходит тест Тьюринга и порождает споры об опасности искусственного интеллекта.

2. Основные определения

Символ - это условный знак каких-либо понятий, идей, явлений. Первые наскальные символы обозначали зверей, охоту, солнце и другие предметы, которые отражались в сознании первобытных людей. Мы и сегодня часто используем символы эмоджи для отображения своих эмоций и скрытых смыслов. У разных народов сформировались свои уникальные алфавиты, которы представляют собой множества допустимых символов для письма.

У компьютера тоже есть уникальный набор символов, определяемый кодировкой. Например, кодировка ASCII (American standard code for information interchange) была стандартизована в 1963 году и определяет символы:
- десятичных цифр;
- латинского алфавита;
- национального алфавита;
- знаков препинания;
- управляющих символов.

С математической точки зрения алфавит как множество символов обозначается символом $V$.
Всевозможные комбинации символов, образующих конечные слова, в т.ч. состоящие из одного символа и бессмысленные комбинации, образуют множество $V^*$.

Слово - наименьшая единица языка, служащая для именования предметов, качеств, характеристик, взаимодействий, а также для служебных целей. Например слово "Я" состоит всего из одного символа и в русском языке обозначает меня как субъект.
Большинство слов состоят из нескольких символов, связанных в последовательность по определенным правилам.

Язык - это множество слов, которые несут в себе хоть какой-то смысл. Например, слово "тывщштс" не имеет смысла в русском языке, хоть и состоит из символов кириллицы. А слово "дом", наоборот, является вполне известным и входит в множество слов русского языка.
Формально язык обозначается символом $L$. В алфавите $V$ язык является подмножеством всех конечных слов $$L \in V^*$$

Текст - это зафиксированая на материальном носителе человеческая мысль в виде последовательности символов. Текст может состоять из одного или нескольких слов.

Представление текста в компьютере

Для человека символы, слова и тексты несут в себе определенный смысл. Компьютер же работает только с байтами. Рассмотрим пример, как реализовано посимвольное кодирование алфавита в кодировке ASCII.

bin dec hex symbol
110 0001 97 61 a
110 0010 98 62 b
110 0011 99 63 c
110 1010 106 6A j
110 1011 107 6B k

bin - двоичное представление символа,
dec - представление в десятичной системе счисления,
hex - представление в шестнадцатеричной системе счисления.
С полной таблицей кодировки ASCII можно ознакомиться по ссылке.
Для хранения одного символа латинского алфавита достаточно 7 бит. Для хранения одного символа небольшого национального алфавита (например, кириллицы) достаточно 8 бит. Для кодировки символов более объемных алфавитов (например, китайского) используют 16 бит или два байта.
Слова, как и тексты, хранятся в компьютерной памяти в виде последовательности символов.