Я реализовал и обучил нейронную сеть в 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()






Вам нужно явно использовать 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.])
Я могу найти такую функцию, как f(x)=x^2, но я не знаю, как применить ее к обученной сети nural.
Ваша сеть реализована с помощью pytorch? и вы оборачиваете свой слой Sequential ?
@MagnusMoller Здесь я отредактировал и добавил пример простой нейронной сети.
Большое спасибо за ваш вклад.
У меня проблема, так как «AttributeError: модуль« torch.nn.functional »не имеет атрибута« критерий »». «критерий» — моя функция потерь.
criterion используется как функциональная переменная, она не включена в библиотеку pytorch. Обычно мы используем criterion= nn.CrossEntropyLoss() для задачи классификации и рассчитываем потери, вызывая вот так loss = criterion(y_hat, y). В моем примере вы можете использовать criterion = nn.MSELoss(), а затем вызвать loss = criterion(y_hat, y).
loss = criterion(torch.from_numpy(predicted.reshape(-1,1)), torch.from_numpy(xAxis)) # calculating loss loss.backward() Я сделал это. Затем я запустил и получил теперь эту ошибку: ошибка времени выполнения: элемент 0 тензоров не требует градиента и не имеет grad_fn
Тензоры не равны нулю. Я их распечатал.
Вы не можете использовать такие массивы NumPy torch.from_numpy(predicted.reshape(-1,1). Сначала вам нужно инициализировать все значения в torch.Tensor.
Что вы подразумеваете под инициализацией значений?
Сделайте это torch.from_numpy(predicted.reshape(-1,1) в начале. Потому что когда вы инициализируете тензор, он также имеет переменную градиента. Который использует один способ расчета материалов, а затем использует град для обратного распространения. Но вы использовали их после передачи в сети.
c3=torch.from_numpy(predicted.reshape(-1,1)) c4=torch.from_numpy(xAxis) loss = criterion(c3,c4) # calculating loss loss.backward() Это так не работает. Как бы я написал это?
Я пытался сделать также это 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() Но я получаю то же сообщение об ошибке.
torch.tensor(predicted.reshape(-1,1), requires_grad=True)После запуска 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, если вам нужно вернуться назад по графику во второй раз или если вам нужно получить доступ к сохраненным тензорам после обратного вызова.
Можете ли вы показать мне код?
Я использую код, который у меня есть на сером в предыдущем комментарии.
Или вам нужен весь код?
Поместите его в colab и поделитесь блокнотом.
Я наклеил это на ваш ответ, раз я не умею работать с колабом
Я также вставил его в свой вопрос.
Проверьте последнее редактирование.
Я изменил его на следующее: criterion(torch.tensor(predict(xAxis).reshape(-1,1), requires_grad=True),torch.tensor(xAxis)) loss.backward()
Но это не работает.
Вы нашли способ заставить его работать?
Я не вижу, чем ваше редактирование отличается. Как это исправляет мою реализацию?
Возможно, что-то связано с формой или значением predicted.reshape(-1,1) и xAxis.
Я пробовал разные формы. Возникает та же ошибка.
Пожалуйста, делайте их отдельно от основного кода. Используйте мой следующий код из последнего блока и редактируйте оттуда.
Моя проблема в том, что я хочу применить его к обученной нейросети, а не к базовой функции. Как бы Вы это сделали?