Мой самописный алгоритм градиентного спуска ведет себя иначе, чем pytorch. Чем я отличаюсь в своей реализации?Python

Программы на Python
Ответить
Anonymous
 Мой самописный алгоритм градиентного спуска ведет себя иначе, чем pytorch. Чем я отличаюсь в своей реализации?

Сообщение Anonymous »

Я пишу свою собственную реализацию нейронной сети на C++ (я приложил то, что, по моему мнению, может вызывать ошибки), чтобы лучше понимать нейронные сети и градиентный спуск.
Я тестирую свою реализацию на pytorch ( см. ниже) и посмотреть, насколько хорошо они справляются друг с другом в прогнозировании цен на жилье с помощью набора данных о жилье в Калифорнии.
Я столкнулся с проблемой, над которой застрял уже неделю. Моя реализация хорошо работает со стохастическим градиентным спуском, но при использовании пакетного градиентного спуска градиенты взрываются уже через 1 эпоху. Я пробовал использовать дырявый Relu на случай, если причина в этом, но безуспешно. При использовании pytorch и пакетного градиентного спуска эта проблема не возникает. Мне интересно, чем отличается моя реализация градиентного спуска/потери mse от реализации pytorch, и что я могу изменить в своей реализации, чтобы предотвратить взрывные градиенты.
Другие примечания о моей реализации:
  • Я использую инициализацию He для своих весов.
Функции, связанные с градиентом спуск и функция потерь:
#include "optimiser.h"
#include

pair mse_loss(matrix &estimated, matrix &actual){
//defined for a 1d horizontal vectors
// defined as 1/(2N) * sum((pred - actual)^2). 1/N is calculated in forwards function defined below;
// Note: replacing 1/M with 1/2 for ease w/ backpropogation algorithm
if(estimated.rows != 1 || estimated.columns != actual.columns|| actual.rows != 1){
throw std::invalid_argument( "y_estimated and y_actual are not of same dimensions!" );
}

matrix error = estimated-actual;

// want to return gradient: only defined for 1 output -> can probably change by returning matrix and having error as a matrix
return make_pair(error, (error*error.transpose())[0][0]); // returns (pred-y), error

}

void backpropogate(model &myModel, double learningRate){
for(int i = 0; i < myModel.structure.size(); i++){
reluLayer &currLayer = myModel.structure;
currLayer.updateWeights(learningRate);
}
}

double forward(model &myModel, matrix &x, matrix &y, double batchNum){
matrix prediction = myModel.forwardPass(x);
matrix errorGrad; //will maintain invariant that errorGrad is always of shape 1x(num_inputs_for_layer);
double error;

tie(errorGrad, error) = mse_loss(prediction, y);

//backpropagation mathematics
error = error / batchNum; // 1/N for actual error
errorGrad = errorGrad/batchNum; // d(estimate-output)^2 / d(estimate-output)

for(int i = myModel.structure.size()-1; i >= 0; i--){
reluLayer& currLayer = myModel.structure;

if(errorGrad.columns != currLayer.lastOutput.columns){
throw std::invalid_argument( "there is an error in my backpropogation code" );
}
if(myModel.structure.isRelu){
for(int j = 0; j < errorGrad.columns; j++){
errorGrad[0][j] = (currLayer.lastOutput[0][j] > 0) ? errorGrad[0][j] : 0.01*errorGrad[0][j];//// d relu(wx+b) / d(wx+b);
}
}

currLayer.weightsGrad = currLayer.weightsGrad + currLayer.lastInput.transpose() * errorGrad; // d(wx+b) / d(w)
currLayer.biasesGrad = currLayer.biasesGrad + errorGrad;

errorGrad = errorGrad * currLayer.weights.transpose(); // d(wx+b) / d(x);
}

return error;
}

double forward_notrain(model &myModel, matrix &x, matrix &y, double batchNum){
matrix prediction = myModel.forwardPass(x);
matrix errorGrad; //will maintain invariant that errorGrad is always 1x(num_inputs_for_layer);
double error;

tie(errorGrad, error) = mse_loss(prediction, y);
error = error/batchNum;

return error;
}

Я понимаю, что существуют методы, позволяющие избежать или обрабатывать взрывные градиенты, такие как пакетная нормализация или отсечение градиента. Но я считаю, что pytorch не использует эти методы по умолчанию. Я повторил то, что пытаюсь сделать, с помощью pytorch, и не вижу этих взрывающихся градиентов. См. ниже:
import os
import torch
from torch import nn
from torch.utils.data import DataLoader, Dataset
from torchvision import datasets, transforms
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_california_housing
import matplotlib.pyplot as plt

data = fetch_california_housing()
print(data.feature_names)

X, y = data.data, data.target

#train-test split of the dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, shuffle=True)

X_train = torch.tensor(X_train, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32).reshape(-1, 1)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_test = torch.tensor(y_test, dtype=torch.float32).reshape(-1, 1)

myData = {
"train": torch.utils.data.TensorDataset(X_train, y_train),
"test": torch.utils.data.TensorDataset(X_test, y_test),
}

myLoader = {x: DataLoader(myData[x], batch_size=1) for x in ["train", "test"]}

device = (
"cuda"
if torch.cuda.is_available()
else "mps"
if torch.backends.mps.is_available()
else "cpu"
)
print(f"Using {device} device")

class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.linear_relu_stack = nn.Sequential(
nn.Linear(8, 24),
nn.ReLU(),
nn.Linear(24, 12),
nn.ReLU(),
nn.Linear(12, 6),
nn.ReLU(),
nn.Linear(6, 1)
)

def forward(self, x):
output = self.linear_relu_stack(x)
return output

def train_model(model, criterion, optimizer, num_epochs=25):
# Create a temporary directory to save training checkpoints
hist = []

for epoch in range(num_epochs):
print(f'Epoch {epoch}/{num_epochs - 1}')
print('-' * 10)

# Each epoch has a training and validation phase
for phase in ['train', 'test']:
if phase == 'train':
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode

running_loss = 0.0
running_corrects = 0

# Iterate over data.
for inputs, labels in myLoader[phase]:
inputs = inputs.to(device)
labels = labels.to(device)

# zero the parameter gradients
optimizer.zero_grad()

# forward
# track history if only in train
with torch.set_grad_enabled(phase == 'train'):
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)

# backward + optimize only if in training phase
if phase == 'train':
loss.backward()

# statistics
running_loss += loss.item() * inputs.size(0)
if phase == 'train':
optimizer.step() # batch grad descent (after going through all data)

epoch_loss = running_loss / 50
if phase == 'test':
hist.append(epoch_loss)

print(f'{phase} Loss: {epoch_loss:.4f}')

print()
return hist

model_ft = NeuralNetwork()
model_ft = model_ft.to(device)

criterion = nn.MSELoss()

#Observe that all parameters are being optimized
optimizer_ft = torch.optim.SGD(model_ft.parameters(), lr=0.001)

#Decay LR by a factor of 0.1 every 7 epochs
hist = train_model(model_ft, criterion, optimizer_ft,
num_epochs=25)



Подробнее здесь: https://stackoverflow.com/questions/792 ... to-pytorch
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»