Производная нейронной сети в Pytorch

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

external_grad = torch.tensor([1., 1.])
Q.backward(gradient=external_grad)

Но как мне это сделать с обученной нейронной сетью вместо функции Q?

Заранее спасибо.

#!/usr/bin/env python
# coding: utf-8

# In[1]:


import numpy as np
from scipy.stats import norm
from numpy import linalg as la
import numpy.random as npr
from tabulate import tabulate
from matplotlib import pyplot as plt
import random
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
#from torchvision import datasets, transforms
from torch.autograd import Variable


# In[2]:


import numpy as np
from scipy.stats import norm
from numpy import linalg as la
import numpy.random as npr
from tabulate import tabulate
from matplotlib import pyplot as plt
import random
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
#from torchvision import datasets, transforms
from torch.autograd import Variable
from torch import optim


# In[3]:


nSimul = 32768
T1 = 1.0
T2 = 2.0
K = 110.0

spot = 100.0
vol = 0.2
vol0 = 0.5 # vol is increased over the 1st period so we have more points in the wings


# simulate all Gaussian returns (N1, N2) first
# returns: matrix of shape [nSimul, TimeSteps=2]
returns = np.random.normal(size=[nSimul,2])

# generate paths, step by step, and not path by path as customary
# this is to avoid slow Python loops, using NumPy's optimized vector functions instead

# generate the vector of all scenarios for S1, of shape [nSimul]
S1 = spot * np.exp(-0.5*vol0*vol0*T1 + vol0*np.sqrt(T1)*returns[:,0])

# generate the vector of all scenarios for S2, of shape [nSimul]
S2 = S1 * np.exp(-0.5*vol*vol*(T2-T1) + vol*np.sqrt(T2-T1)*returns[:,1])

# training set, X and Y are both vectors of shape [nSimul]
X = S1
Y = np.maximum(0, S2 - K)
xAxis = np.linspace(20, 200, 100)

xAxis=xAxis.reshape(-1,1)


# In[4]:


#Normalization of the simulated data:

meanX = np.mean(X)
stdX = np.std(X)
meanY = np.mean(Y)
stdY = np.std(Y)

normX = (X - meanX) / stdX
normY = (Y - meanY) / stdY


normX=normX.reshape(-1,1)

normY=normY.reshape(-1,1)


# In[5]:


class NeuralNetwork(nn.Module):
    def __init__(self,inputsize,outputsize):
        super(NeuralNetwork, self).__init__()
        #self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(inputsize,3),
            nn.ELU(),
            nn.Linear(3, 5),
            nn.ELU(),
            nn.Linear(5,3), 
            nn.ELU(),
            nn.Linear(3,outputsize),
        )
        w = torch.empty(0,1)
        nn.init.normal_(w)
    
    def forward(self, x):
        #x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits


# In[6]:


inputDim = 1       # takes variable 'x' 
outputDim = 1       # takes variable 'y'
learningRate = 0.05
epochs = 10000
#weight=torch.empty(3)
model = NeuralNetwork(inputDim, outputDim)
##### For GPU #######
if torch.cuda.is_available():
    model.cuda()
    


# In[7]:


#criterion = torch.nn.MSELoss() 
#optimizer = torch.optim.SGD(model.parameters(), lr=learningRate)


# In[ ]:


def ridge_loss(outputs,labels):
    torch.mean((outputs-labels)**2)
    
    
    
    
    
    
    


# In[ ]:





# In[9]:


#Adam optmization
criterion = torch.nn.MSELoss() 
#optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam(model.parameters(), lr=0.05)


# In[10]:


for epoch in range(epochs):
    # Converting inputs and labels to Variable
    if torch.cuda.is_available():
        inputs = Variable(torch.from_numpy(normX).cuda().float())
        labels = Variable(torch.from_numpy(normY).cuda().float())
    else:
        inputs = Variable(torch.from_numpy(normX).float())
        labels = Variable(torch.from_numpy(normY).float())

    # Clear gradient buffers because we don't want any gradient from previous epoch to carry forward, dont want to cummulate gradients
    optimizer.zero_grad()

    # get output from the model, given the inputs
    outputs = model(inputs)

    # get loss for the predicted output
    loss = criterion(outputs, labels)
    print(loss)
    # get gradients w.r.t to parameters
    loss.backward()

    # update parameters
    optimizer.step()

    print('epoch {}, loss {}'.format(epoch, loss.item()))


# In[11]:


def predict(xs):
    # first, normalize
    nxs = (xs - meanX) / stdX
    # forward feed through ANN
    # we don't need gradients in the testing phase
    with torch.no_grad():
        if torch.cuda.is_available():
            nys = model(Variable(torch.from_numpy(nxs.rehape(-1,1)).cuda().float())).cpu().data.numpy()
        else:
            nys = model(Variable(torch.from_numpy(nxs.reshape(-1,1))).float()).data.numpy()
    
    # de-normalize output
    ys = meanY + stdY * nys
    # we get a matrix of shape [size of xs][1], which we reshape as vector [size of xs]
    return np.reshape(ys, [-1])


# In[13]:


def BlackScholes(S0,r,sigma,T,K):
    d1 =  1 / (sigma * np.sqrt(T)) * (np.log(S0/K) + (r+sigma**2/2)*T)
    d2 = d1 - sigma * np.sqrt(T)
    return norm.cdf(d1) * S0 - norm.cdf(d2) * K * np.exp(-r*T)

def BlackScholesCallDelta(S0,r,sigma,T,K):
    d1 =  1 / (sigma * np.sqrt(T)) * (np.log(S0/K) + (r+sigma**2/2)*T)
    return norm.cdf(d1)

BlackScholes_vec=np.vectorize(BlackScholes)

BlackScholesCallDelta_vec=np.vectorize(BlackScholesCallDelta)


# In[14]:


BS_price=BS_prices=BlackScholes_vec(S0=xAxis,r=0,sigma=0.2,T=1.0,K=110.0)
predicted=predict(xAxis)

S1=1
#line_learn = plt.plot(Sval,y,label = "Deep Neural Net")
line_learn = plt.plot(xAxis,predicted,label = "Neural Regression")
line_BS = plt.plot(xAxis,BS_price, label = "Black-Scholes")

plt.xlabel("Spot Price")
plt.ylabel("Option Price")
#plt.title(r'Time: %1.1f' % time, loc='left', fontsize=11)
plt.title(r'Strike: %1.2f' % K, loc='right', fontsize=11)
plt.title(r'Initial price: %1.2f' % S1, loc='center', fontsize=11)
plt.legend()
plt.show()
#plt.savefig("deephedge.png", dpi=150)
plt.savefig("deephedge.pdf")


# In[15]:


Prices_rg_mc_diff=[]

for i in range(len(xAxis)-1):
    delta=(predicted[i+1]-predicted[i])/(xAxis[i+1]-xAxis[i])
    Prices_rg_mc_diff.append(delta) 


# In[16]:


BS_delta=BlackScholesCallDelta(S0=xAxis,r=0,sigma=0.2,T=1.0,K=110.0)
predicted=predict(xAxis)

S1=1
#line_learn = plt.plot(Sval,y,label = "Deep Neural Net")
line_learn = plt.plot(xAxis[1:],Prices_rg_mc_diff,label = "Neural Regression")
line_BS = plt.plot(xAxis[1:],BS_delta[1:], label = "Black-Scholes")

plt.xlabel("Spot Price")
plt.ylabel("Option Price")
#plt.title(r'Time: %1.1f' % time, loc='left', fontsize=11)
plt.title(r'Strike: %1.2f' % K, loc='right', fontsize=11)
plt.title(r'Initial price: %1.2f' % S1, loc='center', fontsize=11)
plt.legend()
plt.show()
#plt.savefig("deephedge.png", dpi=150)
plt.savefig("deephedge.pdf")


# In[17]:


model.backward(retain_graph=True)


# In[ ]:


print(NeuralNetwork.weight.grad)


# In[ ]:


def predict(xs):
    # first, normalize
    nxs = (xs - meanX) / stdX
    # forward feed through ANN
    # we don't need gradients in the testing phase
    with torch.no_grad():
        if torch.cuda.is_available():
            nys = model(Variable(torch.from_numpy(nxs.rehape(-1,1)).cuda().float())).cpu().data.numpy()
        else:
            nys = model(Variable(torch.from_numpy(nxs.reshape(-1,1))).float()).data.numpy()
    
    # de-normalize output
    ys = meanY + stdY * nys
    # we get a matrix of shape [size of xs][1], which we reshape as vector [size of xs]
    return np.reshape(ys, [-1])


# In[21]:


c3=torch.from_numpy((predicted.reshape(-1,1)), requires_grad=True) 
c4=torch.from_numpy(xAxis, requires_grad=True) 
#c5=torch.Tensor(c3) 
#c6=torch.Tensor(c4)  
loss = criterion(c3,c4) # calculating loss   

loss.backward()


# In[28]:


torch.tensor(predicted.reshape(-1,1), requires_grad=True)
torch.tensor(xAxis, requires_grad=True)

criterion(torch.tensor(predicted.reshape(-1,1), requires_grad=True),torch.tensor(xAxis, requires_grad=True))


loss.backward()

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно явно использовать requires_grad = True при создании тензора. И чтобы вычислить градиент, вам сначала нужно применить некоторую операцию к тензору.

Вот пример:

import torch

x = torch.rand(2, 2, requires_grad=True)
y = x + 2
z = y * y * 3
out = z.mean()

out.backward()

print(x.grad)

Вывод:

tensor([[3.3720, 3.4302],
        [3.4030, 3.3605]])

Таким образом, вы используете torch.autograd для вычисления градиента для тензора x. Смотрите автоград, чтобы узнать больше.

А для нейронной сети вы можете просто использовать сеть, а затем откатить ее назад.

Пример нейронной сети:

import torch
import torch.nn as nn
import torch.nn.functional as f

x = torch.rand(2, 2)

# define a neural network
network = nn.Sequential(
nn.Linear(2,100),
nn.Linear(100,2)
)

pred = network(x)

loss = f.mae_loss(pred, x) # calculating loss 

loss.backward()

# Update weights with gradients
network[0].weight = 0.1 * network[0].weight.grad
network[1].weight = 0.1 * network[1].weight.grad

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

Пример backward() с использованием torch.nn.MSELoss():

import torch
from torch.nn import MSELoss

criterion = MSELoss()

a = torch.tensor([1.,2.], requires_grad=True)
b = a**2

loss = criterion(b, a)

loss.backward()

print(a.grad)

Вывод:

tensor([0., 6.])

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

Magnus Moller 18.10.2022 18:58

Я могу найти такую ​​функцию, как f(x)=x^2, но я не знаю, как применить ее к обученной сети nural.

Magnus Moller 18.10.2022 18:59

Ваша сеть реализована с помощью pytorch? и вы оборачиваете свой слой Sequential ?

rafathasan 18.10.2022 19:01

@MagnusMoller Здесь я отредактировал и добавил пример простой нейронной сети.

rafathasan 18.10.2022 19:20

Большое спасибо за ваш вклад.

Magnus Moller 18.10.2022 19:45

У меня проблема, так как «AttributeError: модуль« torch.nn.functional »не имеет атрибута« критерий »». «критерий» — моя функция потерь.

Magnus Moller 19.10.2022 16:34
criterion используется как функциональная переменная, она не включена в библиотеку pytorch. Обычно мы используем criterion= nn.CrossEntropyLoss() для задачи классификации и рассчитываем потери, вызывая вот так loss = criterion(y_hat, y). В моем примере вы можете использовать criterion = nn.MSELoss(), а затем вызвать loss = criterion(y_hat, y).
rafathasan 19.10.2022 16:42
loss = criterion(torch.from_numpy(predicted.reshape(-1,1)), torch.from_numpy(xAxis)) # calculating loss loss.backward() Я сделал это. Затем я запустил и получил теперь эту ошибку: ошибка времени выполнения: элемент 0 тензоров не требует градиента и не имеет grad_fn
Magnus Moller 19.10.2022 16:51

Тензоры не равны нулю. Я их распечатал.

Magnus Moller 19.10.2022 16:52

Вы не можете использовать такие массивы NumPy torch.from_numpy(predicted.reshape(-1,1). Сначала вам нужно инициализировать все значения в torch.Tensor.

rafathasan 19.10.2022 17:05

Что вы подразумеваете под инициализацией значений?

Magnus Moller 19.10.2022 21:20

Сделайте это torch.from_numpy(predicted.reshape(-1,1) в начале. Потому что когда вы инициализируете тензор, он также имеет переменную градиента. Который использует один способ расчета материалов, а затем использует град для обратного распространения. Но вы использовали их после передачи в сети.

rafathasan 19.10.2022 21:25
c3=torch.from_numpy(predicted.reshape(-1,1)) c4=torch.from_numpy(xAxis) loss = criterion(c3,c4) # calculating loss loss.backward() Это так не работает. Как бы я написал это?
Magnus Moller 19.10.2022 22:00

Я пытался сделать также это c3=torch.from_numpy(predicted.reshape(-1,1)) c4=torch.from_numpy(xAxis) c5=torch.Tensor(c3) c6=torch.Tensor(c4) loss = criterion(c5,c6) # calculating loss loss.backward() Но я получаю то же сообщение об ошибке.

Magnus Moller 19.10.2022 22:16
torch.tensor(predicted.reshape(-1,1), requires_grad=True)
rafathasan 20.10.2022 07:44

После запуска criterion(torch.tensor(predicted.reshape(-1,1), requires_grad=True),torch.tensor(xAxis, requires_grad=True)) loss.backward() я получаю следующую ошибку времени выполнения: RuntimeError: Попытка вернуться назад по графику во второй раз (или получить прямой доступ к сохраненным тензорам после того, как они уже были освобождены). Сохраненные промежуточные значения графика освобождаются при вызове .backward() или autograd.grad(). Укажите keep_graph=True, если вам нужно вернуться назад по графику во второй раз или если вам нужно получить доступ к сохраненным тензорам после обратного вызова.

Magnus Moller 20.10.2022 16:25

Можете ли вы показать мне код?

rafathasan 20.10.2022 16:26

Я использую код, который у меня есть на сером в предыдущем комментарии.

Magnus Moller 20.10.2022 16:29

Или вам нужен весь код?

Magnus Moller 20.10.2022 16:31

Поместите его в colab и поделитесь блокнотом.

rafathasan 20.10.2022 16:35

Я наклеил это на ваш ответ, раз я не умею работать с колабом

Magnus Moller 20.10.2022 16:40

Я также вставил его в свой вопрос.

Magnus Moller 20.10.2022 16:42

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

rafathasan 20.10.2022 16:56

Я изменил его на следующее: criterion(torch.tensor(predict(xAxis).reshape(-1,1), requires_grad=True),torch.tensor(xAxis)) loss.backward()

Magnus Moller 20.10.2022 17:11

Но это не работает.

Magnus Moller 20.10.2022 17:11

Вы нашли способ заставить его работать?

Magnus Moller 20.10.2022 17:11

Я не вижу, чем ваше редактирование отличается. Как это исправляет мою реализацию?

Magnus Moller 20.10.2022 18:34

Возможно, что-то связано с формой или значением predicted.reshape(-1,1) и xAxis.

rafathasan 20.10.2022 18:43

Я пробовал разные формы. Возникает та же ошибка.

Magnus Moller 20.10.2022 19:33

Пожалуйста, делайте их отдельно от основного кода. Используйте мой следующий код из последнего блока и редактируйте оттуда.

rafathasan 20.10.2022 19:35

Другие вопросы по теме