В този урок ще научим за PyTorch и как да обучим логистичен регресионен модел с помощта на библиотеката на PyTorch

ВЪВЕДЕНИЕ

Логистичната регресия е популярен алгоритъм за машинно обучение, използван за проблеми с двоичната класификация. Това е вид регресионен анализ, при който променливата на отговора е категорична по природа, с два възможни изхода, обикновено представяни като „0“ и „1“. Основната цел на логистичната регресия е да се предвиди вероятността за настъпване на събитие, като се има предвид набор от независими променливи.

С логистичната регресия вие по същество искате да класифицирате двоичните класове, като използвате линейна линия, която разделя двата класа. Възможно е да има случаи, в които разделянето на класовете може да не е толкова лесно, колкото начертаването на линия и това е мястото, където промяната на архитектурата на модела влиза в картината.

Логистичната регресия се използва за идентифициране дали пациентът има вероятност да получи доброкачествен или злокачествен рак, за установяване дали клиентът ще напусне или не и за прогнозиране дали утре ще вали или не.

Сега има няколко начина, по които можете да приложите логистична регресия, но за целите на тази статия ще използваме PyTorch, която е рамка за машинно обучение, разработена от Meta.

Щракнете върху връзката по-долу, за да научите как да приложите логистична регресия с помощта на градиентно спускане, което е техника за оптимизация, използвана в невронните мрежи за изучаване на параметрите на модела.



PyTorch е библиотека за машинно обучение за Python, която предоставя API на високо ниво за създаване и обучение на модели за дълбоко обучение. PyTorch предоставя модул, наречен „torch.nn“, който предоставя много предварително дефинирани модули за изграждане на модели за дълбоко обучение.

МОДУЛИ В PYTORCH

Модулите PyTorch са предварително дефинирани градивни елементи за създаване на модели за дълбоко обучение. Модулът в PyTorch представлява отделна операция или слой в невронна мрежа. Модулът torch.nn в PyTorch предоставя редица предварително дефинирани модули за изграждане на невронни мрежи.

Някои от най-често използваните модули на PyTorch са:

  1. nn.Linear: Този модул представлява напълно свързан слой в невронна мрежа с тегловна матрица и вектор на отклонение.
  2. nn.Conv2d: Представлява 2D конволюционен слой, често използван при проблеми с класификацията на изображения.
  3. nn.MaxPool2d: Този модул представлява 2D максимален обединяващ слой, използван за намаляване на пространствените размери на тензор.
  4. nn.Dropout: За слоя за отпадане, използван за предотвратяване на пренастройване в невронни мрежи.
  5. nn.BatchNorm2d: Този модул е ​​за пакетния нормализиращ слой, използван за нормализиране на активирането на невронна мрежа.
  6. nn.ReLU: Функция за активиране на коригирана линейна единица (ReLU), използвана за въвеждане на нелинейност в невронна мрежа.
  7. nn.Sigmoid: Означава функция за активиране на Sigmoid, използвана при проблеми с двоична класификация.
  8. Модул Autograd — PyTorch използва техника, известна като автоматично диференциране. За да изчисли градиентите, записващото устройство записва операциите, които са били изпълнени, и след това ги възпроизвежда обратно. Тази техника е особено ефективна за създаване на невронни мрежи, тъй като може да намали времето, прекарано в една епоха, чрез изчисляване на диференциацията на параметрите при преминаване напред.
  9. Optim модул — torch.optim е модул, който реализира различни оптимизационни алгоритми, използвани за изграждане на невронни мрежи. Повечето от често използваните методи вече се поддържат, така че не е необходимо да ги създавате от нулата.

Това са само няколко примера от многото предварително дефинирани модули, налични в модула torch.nn в PyTorch. За да използвате тези модули във вашия модел за дълбоко обучение, просто ги импортирайте от модула torch.nn и ги добавете към дефиницията на персонализирания модел.

КАКВО ПРАВИ PYTORCH ТОЛКОВА ПОПУЛЯРЕН?

В общностите за машинно обучение има толкова много рамки за използване в ежедневните работни потоци за наука за данни и толкова много библиотеки за тестване, но има някои библиотеки, които винаги се открояват и доказват защо са толкова добри за Практици в областта на машинното обучение и науката за данни.

По-долу са някои от уникалните точки за PyTorch, които го правят популярен избор сред практикуващите дълбоко обучение и изследователите.

  1. Динамична изчислителна графика: PyTorch използва динамична изчислителна графика, която позволява повече гъвкавост и лекота на използване в сравнение със статичните изчислителни графики, използвани в други рамки за дълбоко обучение като TensorFlow.
  2. Лесен за използване: PyTorch има удобен за потребителя API, който улеснява разработчиците да създават и обучават модели за дълбоко обучение. PyTorch предоставя функционалността (DataLoader) за зареждане на данните под формата на партиди, тъй като данните за задълбочено обучение могат да станат твърде големи за някои машини и може да има предизвикателства само със зареждането на данните в паметта.
  3. Собствена поддръжка за CUDA: PyTorch има вградена поддръжка за CUDA, паралелната изчислителна платформа и API за графични процесори на Nvidia, което улеснява изпълнението на скъпи изчислителни операции на графични процесори.
  4. Бързо разработване на модели: PyTorch предоставя API на високо ниво, който улеснява бързото експериментиране с различни модели и архитектури на модели.
  5. Добра поддръжка от общността: PyTorch разполага с нарастваща общност от разработчици и потребители, с богатство от ресурси и уроци, достъпни онлайн.
  6. Оперативна съвместимост с други инструменти: PyTorch е проектиран да работи добре с други инструменти за задълбочено обучение, като TensorBoard, което улеснява визуализирането на ефективността на модела и напредъка в обучението. Той поддържа и NumPy, което е градивният елемент на Data Science Community в наши дни, тъй като повечето от библиотеките са изградени върху NumPy.
  7. Поддръжка на обучение при прехвърляне: PyTorch има вградена поддръжка за обучение при прехвърляне, което ви позволява да използвате повторно предварително обучени модели за различни задачи, спестявайки време и ресурси.
  8. Лесно внедряване на модел: Моделите на PyTorch могат лесно да бъдат внедрени на различни платформи, включително мобилни устройства и мрежата, като се използват инструменти като TorchScript и ONNX.

ИЗПЪЛНЕНИЕ

Ще започнем с инсталирането на PyTorch, ако вече не е инсталиран. За да инсталирате PyTorch, изпълнете следната команда във вашия бележник на jupyter:

!pip install torch

След като PyTorch е инсталиран, ще започнем да импортираме необходимите библиотеки.

import numpy as np 
import pandas as pd 
import torch
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
from sklearn.impute import KNNImputer
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from torchmetrics.classification import BinaryConfusionMatrix
from sklearn.metrics import roc_curve,  auc 

Ще работим с космическия кораб Titanic Dataset, наличен в Kaggle.

ЗА КОСМИЧЕСКИЯ КОРАБ ТИТАНИК

През 2912 г. е получено предаване от разстояние четири светлинни години и нещата не изглеждат добре.

Космическият кораб Титаник беше междузвезден пътнически кораб, изстрелян преди месец. С почти 13 000 пътници на борда, корабът се отправи на първото си плаване, транспортирайки емигранти от нашата слънчева система до три нови обитаеми екзопланети, обикалящи около близките звезди.

Докато заобикаляше Алфа Кентавър по пътя към първата си дестинация — горещия 55 Cancri E — непредпазливият Космически кораб Титаник се сблъска с пространствено-времева аномалия, скрита в облак прах. За съжаление, той срещна подобна съдба като съименника си от преди 1000 години. Въпреки че корабът остана непокътнат, почти половината от пътниците бяха транспортирани до алтернативно измерение!

За да помогнем на спасителните екипажи и да извлечем изгубените пътници, от нас се изисква да предвидим кои пътници са били транспортирани от аномалията, използвайки записи, възстановени от повредената компютърна система на космическия кораб.

Нека прочетем нашите данни.

train_df = pd.read_csv('train.csv')

Ето как изглежда рамката с данни:-

Нека да разгледаме стойностите на броя на целевия клас, който е колоната Transported

sns.countplot(train_df.Transported)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.title('Target Class Countplot', fontsize=20)
plt.show()

Нека също да разгледаме възрастовото разпределение за всеки клас в целевата променлива. Ще използваме библиотеката Seaborn, за да начертаем хистограма

colors = plt.rcParams["axes.prop_cycle"]()
a = 1
b = 2
c = 1
fig = plt.figure()
for i in train_df.Transported.unique():
    color = next(colors)["color"]
    plt.subplot(a,b,c)
    sns.histplot(train_df[train_df.Transported==i]['Age'], color=color)
    plt.gca().spines['top'].set_visible(False)
    plt.gca().spines['right'].set_visible(False)
    plt.title(f'Age Spread where Transported = {i}')
    c =  c+1
plt.suptitle('Age Distribution', fontsize=20, y=1.02)
plt.tight_layout()    
plt.show()

Можем да наблюдаваме, че възрастта и за двата класа е между 20 и 30 години. Сега нека разберем колко липсващи стойности присъстват в нашите данни. Можем да направим това, като използваме функцията isnullв Pandas или можем да напишем малък цикъл, излагащ повече подробности.

for i in train_df.columns:
    if train_df[i].isnull().sum() != 0:
        dtype = train_df[i].dtype
        percent = round(train_df[i].isnull().sum()/train_df.shape[0],2)*100
        print(f'{i} : {percent}% missing,    Dtype : {dtype}')

Тъй като в нашите данни има някои примеси, ще напишем функция за почистване на данните и връщане на рамката с данни

def clean(df):
    '''
    Takes a dataframe, imputes the missing values, encodes the categorical features, 
     drops na values and returns the dataframe
    '''
    imputer = KNNImputer(n_neighbors=2)
    encoder= LabelEncoder()
    df[df.select_dtypes('float64').columns] = imputer.fit_transform(df.select_dtypes('float64'))
    df.drop(['PassengerId', 'Cabin', 'Name'], axis=1, inplace=True)
    cols = ['CryoSleep', 'VIP', 'Transported']
    for i in cols:
        df[i] = encoder.fit_transform(df[i])        
    df = df.dropna(subset=['HomePlanet', 'Destination'])
    obj_cols = list(df.select_dtypes('object'))
    for i in obj_cols:
        df[i] = encoder.fit_transform(df[i])
    return df

Рамката с данни вече се оформя и започва да изглежда така:-

Тъй като нашите данни имат различни мащаби за всяка колона, най-добрата практика е да мащабирате колоните, така че алгоритъмът да се сближава по-бързо.

input_cols = cleaned_train.columns[:-1]
scaler = StandardScaler()
scaler.fit(cleaned_train[input_cols])
cleaned_train[input_cols] = scaler.transform(cleaned_train[input_cols])

След това ще продължим и ще разделим данните на независими и зависими променливи.

y = cleaned_train.Transported.values
X = cleaned_train[input_cols].values

За разделянето на данните в комплект за обучение и валидиране ще напишем изящна малка функция, която връща тези набори под формата на тензори

def split(X,y, test_size=0.10):
    '''
    Takes X and y arrays, splits them into training and test set. 
    The function then converts all the sets into tensors only to be returned
    by the function.
    '''
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=1, shuffle=True)
    X_train=torch.from_numpy(X_train.astype(np.float32))
    X_test=torch.from_numpy(X_test.astype(np.float32))
    y_train=torch.from_numpy(y_train.astype(np.float32))
    y_test=torch.from_numpy(y_test.astype(np.float32))
    return X_train, X_test, y_train, y_test


#Calling the function we just created to split the data
X_train, X_test, y_train, y_test = split(X,y)

#Reshaping the y_train and y_test 
y_train=y_train.view(y_train.shape[0],1)
y_test=y_test.view(y_test.shape[0],1)

Нека създадем нашия модел сега, когато имаме готови данни. Ще напишем клас, който използва 2 невронни мрежови слоя, ReLU функция за активиране и сигмоидна функция

class LogisticRegression(torch.nn.Module):
    def __init__(self,no_input_features):
        super(LogisticRegression,self).__init__()
        self.layer1=torch.nn.Linear(no_input_features,20)
        self.relu = nn.ReLU()
        self.layer2=torch.nn.Linear(20,1)
        
    def forward(self,x):
        y_predicted=self.relu(self.layer1(x))
        y_predicted=torch.sigmoid(self.layer2(y_predicted))
        return y_predicted

PyTorch ни позволява да разширим съществуващия модул, който е nn, и ние правим точно това, като създаваме персонализиран клас за себе си. Първо инициираме конструктора, който се извиква всеки път, когато се създава обект от класа и след това слоевете се дефинират. Предната функция на класа определя как ще се изчислява изчислението на тегла и отклонения.

Да продължим напред и да използваме класа, за да дефинираме нашия модел. Чувствайте се свободни да продължите напред и да си поиграете със слоевете на мрежата, за да подобрите допълнително архитектурата и производителността на мрежата.

n_features = 10
model=LogisticRegression(n_features)

#Setting up Loss criteria and the optimizer
criterion=torch.nn.BCELoss()
optimizer=torch.optim.SGD(model.parameters(),lr=0.1, momentum = 0.5, weight_decay=0.1)

def evaluate(preds, target):
    '''
    Function to evaluate the performance of the model. 
    Takes model predictions and targets to return the accuracy of the model.
    '''
    metric = BinaryAccuracy()
    accuracy = metric(preds, target)
    return accuracy

Забележете, че ние използваме Binary Cross Entropy Loss за наблюдение на загубата и Stochastic Gradient Descent за оптимизатора. Ще продължим и ще напишем тренировъчен цикъл, където моделът ще научи параметрите:

Loss = []
Accuracy = []
number_of_epochs=500
for epoch in range(number_of_epochs):
    y_prediction=model(X_train)
    loss=criterion(y_prediction,y_train)
    accuracy = evaluate(y_prediction, y_train)
    Loss.append(loss)
    Accuracy.append(accuracy)
    loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    if (epoch+1)%100 == 0:
        print(f'Epoch: {epoch+1}, Loss : {loss.item()}, val_acc: {accuracy.item()}')

Сега, след като моделът научи параметрите, нека да визуализираме загубата и точността за продължителността на епохите с помощта на Matplotlib.

plt.plot([i.item() for i in Loss], marker='o', markersize = 6,markerfacecolor = 'red',markeredgecolor = 'red',markevery=100)
plt.title('Logistic Regression Model Loss Plot', fontsize=18)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.show()

plt.plot([i.item() for i in Accuracy], color='orange', marker='o', markersize = 6,markerfacecolor = 'C0',
         markeredgecolor = 'C0',markevery=100)
plt.title('Logistic Regression Model Accuracy Plot', fontsize=18)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.xlabel('Epochs')
plt.ylabel('Validation Accuracy')
plt.show()

УРА!!! Ние успешно обучихме модела на логистична регресия в PyTorch. Преди да приключим статията, нека направим още нещо и да разгледаме различните показатели за класификация, като напишем функция: -

def plot_classification_metrics(y_pred, y_test):
    """
    This function takes y_true and y_pred values to print the Classification metrics
    """
    from torchmetrics.classification import BinaryConfusionMatrix
    bcm = BinaryConfusionMatrix()
    target = torch.tensor(y_test)
    y_pred = torch.tensor([1 if i > 0.5 else 0 for i in y_pred])
    y_pred = y_pred.reshape(y_pred.shape[0], 1)
    matrix = bcm(y_pred, target )
    TP = matrix[0][0]
    FP = matrix[0][1]
    FN = matrix[1][0]
    TN = matrix[1][1]
    Accuracy = (TP + TN) / (TP + TN + FP + FN)
    print('== CLASSIFICATION METRICS ==')
    print(f'Accuracy :  {np.around(Accuracy,4)}')
    Precision = (TP) / (TP + FP)
    print(f'Precision :  {np.around(Precision,4)}')
    Recall = (TP) / (TP + FN)
    print(f'Recall : {np.around(Recall,4)}')
    F1_Score = 2 * (Precision*Recall/Precision+Recall)
    print(f'F1 Score : {np.around(F1_Score,4)}')
    Classification_Error = (FP+FN)/ (TP+FP+FN+TN)
    print(f'Classification Error : {np.around(Classification_Error,4)}')
    sensitivity =  TP/(TP+FN)
    print(f'Sensitivity / TPR: {np.around(sensitivity,4)}')
    specificity =  TN/(TP+FN)
    print(f'Specificity / TNR : {np.around(specificity,4)}')

#Calling the function
plot_classification_metrics(X_preds, y_train)

Като разгледаме показателите, можем да кажем, че моделът е приблизително 75% добър и има безкрайни възможности какво може да се направи в бъдеще. Ще ви приветствам да опитате и да ги проучите, ако искате.

ЗАКЛЮЧЕНИЕ

  1. Логистичната регресия е класически алгоритъм за машинно обучение, който класифицира двоичните класове с помощта на линейна линия, която разделя двата класа.
  2. PyTorch е библиотека за машинно обучение за Python, която предоставя API на високо ниво за създаване и обучение на модели за дълбоко обучение. Той е лесен за използване поради динамична изчислителна графика, оперативна съвместимост с други инструменти, добро, поддръжка от общността, бързо разработване на модели, лесен за използване и много други функции.
  3. След това ще покрия повече рамки, които ще помогнат с вашите работни потоци за наука за данни и са лесни за внедряване.

Ако сте харесали съдържанието на статията, ще бъда благодарен, ако можете да я аплодирате и да ме последвате за още. Чувствайте се свободни да се свържете с мен тук.