Использование метода градиентного спуска в Python3

В этом посте мы рассмотрим программу, написанную на Python3, использующую NumPy в качестве нашей библиотеки обработки данных, чтобы увидеть, как реализована (пакетная) линейная регрессия с использованием метода градиентного спуска.

Я объясню, как работает код по частям, как работает каждая часть кода. В конце я прикреплю ссылку на весь код, размещенный на GitHub, вместе с набором данных, используемым в примере.

Мы собираемся вычислить градиент по этой формуле.

Здесь x(i) вектор - это одна точка данных, где N - размер набора данных. n(eta) - это наша скорость обучения. y(i) вектор - это целевой результат. f(x) вектор - это линейная функция регрессии, определяемая как f(x) = Sum(w*x), здесь сумма - это функция сигма. Также мы собираемся рассмотреть начальное смещение w0 = 0 и перехват x0 = 1. Все веса инициализируются как 0.

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

Вместо того, чтобы минимизировать SSE до нуля, мы собираемся измерять изменение SSE на каждой итерации и сравнивать это с threshold, которое предоставляется перед выполнением программы. Если изменение SSE опускается ниже порогового значения, программа завершает работу.

В программе мы предоставляем три входа из командной строки. Они есть:

  1. порог - порог, ниже которого должно упасть изменение ошибки, прежде чем алгоритм завершится.
  2. данные - расположение файла данных.
  3. LearningRate - скорость обучения метода градиентного спуска.

Следовательно, программа должна запускаться так:

python3 linearregr.py — data random.csv — learningRate 0.0001 — threshold 0.0001

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

iteration_number,weight0,weight1,weight2,...,weightN,sum_of_squared_errors

Программа состоит из 6 частей, и мы рассмотрим их по очереди.

Операторы импорта

import argparse # to read inputs from command line
import csv # to read the input data set file
import numpy as np # to work with the data set

Блок инициализатора выполнения кода

# initialise argument parser and read arguments from command line with the respective flags and then call the main() function
if __name__ == '__main__':    
    parser = argparse.ArgumentParser()
    parser.add_argument("-d", "--data", help="Data File")
    parser.add_argument("-l", "--learningRate", help="Learning Rate")    
    parser.add_argument("-t", "--threshold", help="Threshold")    
    main()

Функция main()

Последовательность выполнения функции main () выглядит так:

  1. Сохраните соответствующие входные данные командной строки в переменных
  2. Прочтите файл CSV, и последний столбец является целевым выходом, он отделяется от входа (сохраняется как X) и сохраняется как Y
  3. Преобразуйте точки данных в число с плавающей запятой и инициализируйте вектор веса с нулями
  4. Рассчитайте прогнозируемое выходное значение с помощью функции calculatePredicatedValue
  5. Рассчитайте начальную SSE с помощью функции calculateSSE
  6. Выходной файл открывается в режиме записи, и данные записываются в формате, указанном в сообщении. После записи первых значений градиент и обновленные веса вычисляются с помощью функции calculateGradient. Переменная итерации поддерживается для отслеживания количества выполнений пакетной линейной регрессии до того, как она упадет ниже порогового значения. В бесконечном цикле while прогнозируемое выходное значение вычисляется снова и вычисляется новое значение SSE. Если абсолютная разница между старым (SSE из предыдущей итерации) и более новым (SSE из текущей итерации) SSE больше порогового значения, то описанный выше процесс повторяется. Итерация увеличивается на 1, и текущая SSE сохраняется в предыдущей SSE. Если абсолютная разница между старым (SSE из предыдущей итерации) и более новым (SSE из текущей итерации) SSE падает ниже порогового значения, цикл прерывается, и последние выходные значения записываются в файл.

Функция calculatePredicatedValue()

Здесь прогнозируемый результат вычисляется путем выполнения скалярного произведения входной матрицы X и весовой матрицы W.

Функция calculateGradient()

Градиент рассчитывается, а веса обновляются с использованием первой формулы, упомянутой в сообщении.

Функция calculateSSE()

SSE рассчитывается по указанной выше формуле.

def calculateSSE(Y, f_x):    
    sse = np.sum(np.square(f_x - Y))     
    return sse

Теперь, когда есть весь код. Давайте посмотрим на выполнение программы.

Вот как выглядит вывод:

Финальная программа

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

Эта программа использовала numpy для обработки данных, но это можно сделать с помощью основ Python без использования numpy, но для этого потребуется вложенный цикл, и, следовательно, сложность возрастет до O(n*n). В любом случае массивы и матрицы, предоставляемые numpy, более эффективны с точки зрения памяти. Кроме того, если вам удобно работать с pandas, рекомендуется использовать это и попытаться реализовать с ним ту же программу.

Я раздаю бесплатную электронную книгу о согласованности. Получите бесплатную электронную книгу здесь .

Надеюсь, вам понравился пост Спасибо за прочтение.

Если вам нравится читать подобные истории и вы хотите поддержать меня как писателя, подумайте о подписке, чтобы стать участником Medium. Это 5 долларов в месяц, что дает вам неограниченный доступ к историям на Medium. Если вы зарегистрируетесь по моей ссылке, я получу небольшую комиссию без каких-либо дополнительных затрат для вас.



Вот список моих рассказов: