详解 pytorch 中的 autograd.grad() 函数

我们在用神经网络求解PDE时, 经常要用到输出值对输入变量不是Weights和Biases)求导; 在训练WGAN-GP 时, 也会用到网络对输入变量的求导。 以上两种需求, 均可以用pytorch 中的autograd.grad() 函数实现。

 

autograd.grad(outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=False, only_inputs=True, allow_unused=False)

outputs: 求导的因变量(需要求导的函数)

inputs: 求导的自变量

grad_outputs:  如果 outputs为标量,则grad_outputs=None,也就是说,可以不用写;  如果outputs 是向量,则此参数必须写,不写将会报如下错误:

那么此参数究竟代表着什么呢?

先假设 \large x,y 为一维向量, 即可设自变量因变量分别为  \mathbf{x} =(x_1, x_2, \cdots, x_n)\in \mathbb{R}^n, y = f(\mathbf{x})= (y_1,y_2,\cdots,y_m)\in \mathbb{R}^m, 其对应的 Jacobi 矩阵为

                                                              \large J=\begin{pmatrix} \frac{\partial y_1}{\partial x_1} & \frac{\partial y_1}{\partial x_2} &\cdots& \frac{\partial y_1}{\partial x_n}\\ \frac{\partial y_2}{\partial x_1} & \frac{\partial y_2}{\partial x_2} &\cdots& \frac{\partial y_2}{\partial x_n}\\ \vdots&\vdots&\ddots&\vdots\\ \frac{\partial y_m}{\partial x_1} & \frac{\partial y_m}{\partial x_2} &\cdots& \frac{\partial y_m}{\partial x_n} \end{pmatrix}

grad_outputs 是一个shape 与 outputs 一致的向量, 即

                                        \large grad\_outputs=\begin{pmatrix} a_{11} & a_{12} & \cdots&a_{1m} \end{pmatrix}^T,

在给定grad_outputs 之后,真正返回的梯度为

                                     \large grad = \begin{pmatrix} a_1\frac{\partial y_1}{\partial x_1}+a_2\frac{\partial y_2}{\partial x_2}+\cdots+a_m\frac{\partial y_m}{\partial x_1}\\ a_1\frac{\partial y_2}{\partial x_2}+a_2\frac{\partial y_1}{\partial x_2}+\cdots+a_m\frac{\partial y_m}{\partial x_2}\\ \cdots\cdots\cdots\cdots\\ a_1\frac{\partial y_1}{\partial x_n}+a_2\frac{\partial y_1}{\partial x_n}+\cdots+a_m\frac{\partial y_m}{\partial x_n}\\ \end{pmatrix}\in \mathbb{R}^n.

为方便下文叙述我们引入记号  \large grad = J \otimes grad\_outputs.

其次假设  \large x = (x_1,\cdots,x_n)\in\mathbb{R}^n, \mathbf{y} =(\mathbf{y_1},\cdots,\mathbf{y_t})\in\mathbb{R}^{s\times t},第i个列向量对应的Jacobi矩阵为

                                                                           \large J_i,1\leq i\leq t.

此时的grad_outputs 为(维度与outputs一致)

                                                \large grad\_outputs=(go_1,\cdots,go_t)\in \mathbb{R}^{s\times t}

由第一种情况, 我们有

                                                                   \large grad = \sum_{i=1}^t J_i \otimes go_i.

也就是说对输出变量的列向量求导,再经过权重累加。

若  x = (\mathbf{x_1},\cdots,\mathbf{x_p})\in\mathbb{R}^{n\times p}, \mathbf{y}\in \mathbb{R}^m, 沿用第一种情况记号

grad = \begin{pmatrix} grad_1&\cdots& grad_p \end{pmatrix}, 其中每一个 grad_i 均由第一种方法得出,

即对输入变量列向量求导,之后按照原先顺序排列即可。

 

retain_graph:  True 则保留计算图, False则释放计算图

create_graph: 若要计算高阶导数,则必须选为True

allow_unused: 允许输入变量不进入计算

下面我们看一下具体的例子:

import torch
from torch import autograd

x = torch.rand(3, 4)
x.requires_grad_()

观察 x 为

不妨设 y 是 x 所有元素的和, 因为 y是标量,故计算导数不需要设置grad_outputs

y = torch.sum(x)
grads = autograd.grad(outputs=y, inputs=x)[0]
print(grads)

结果为

若y是向量

y = x[:,0] +x[:,1]
# 设置输出权重为1
grad = autograd.grad(outputs=y, inputs=x, grad_outputs=torch.ones_like(y))[0]
print(grad)
# 设置输出权重为0
grad = autograd.grad(outputs=y, inputs=x, grad_outputs=torch.zeros_like(y))[0]
print(grad)

结果为

最后, 我们通过设置 create_graph=True 来计算二阶导数

y = x ** 2
grad = autograd.grad(outputs=y, inputs=x, grad_outputs=torch.ones_like(y), create_graph=True)[0]
grad2 = autograd.grad(outputs=grad, inputs=x, grad_outputs=torch.ones_like(grad))[0]
print(grad2)

结果为

综上,我们便搞清楚了它的求导机制.

 

 

  • 79
    点赞
  • 286
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
GCN(Graph Convolutional Networks,图卷积网络)是一种用于图像分类、节点分类等图像处理任务的深度学习模型。下面我将介绍如何使用PyTorch实现GCN。 首先,我们需要安装PyTorch和其它必要的库。可以使用以下命令安装: ``` pip install torch torchvision pip install numpy scipy scikit-learn ``` 接下来,我们需要定义一个GCN模型。以下是一个简单的实现: ```python import torch import torch.nn as nn import torch.nn.functional as F class GCN(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super(GCN, self).__init__() self.fc1 = nn.Linear(input_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, output_dim) def forward(self, x, adj): x = F.relu(self.fc1(torch.mm(adj, x))) x = self.fc2(torch.mm(adj, x)) return F.log_softmax(x, dim=1) ``` 在上面的代码,我们定义了一个三层的GCN模型。`input_dim`是输入特征的维度,`hidden_dim`是隐藏层的维度,`output_dim`是输出层的维度。`nn.Linear`是一个线性层,`F.relu`是一个激活函数,`F.log_softmax`是一个softmax函数。 接下来,我们需要定义一个训练函数。以下是一个简单的实现: ```python def train(model, optimizer, criterion, features, adj, labels, idx_train): model.train() optimizer.zero_grad() output = model(features, adj) loss = criterion(output[idx_train], labels[idx_train]) loss.backward() optimizer.step() return model, optimizer, loss.item() ``` 在上面的代码,我们定义了一个训练函数。`features`是输入特征,`adj`是邻接矩阵,`labels`是标签,`idx_train`是训练样本的索引。我们使用`model.train()`将模型切换到训练模式,然后使用`optimizer.zero_grad()`将梯度清零,使用`model(features, adj)`计算输出,使用`criterion(output[idx_train], labels[idx_train])`计算损失,使用`loss.backward()`计算梯度,使用`optimizer.step()`更新参数。 接下来,我们需要定义一个测试函数。以下是一个简单的实现: ```python def test(model, features, adj, labels, idx_test): model.eval() output = model(features, adj) _, preds = torch.max(output, dim=1) correct = torch.sum(preds[idx_test] == labels[idx_test]) acc = correct.item() / len(idx_test) return acc ``` 在上面的代码,我们定义了一个测试函数。`features`是输入特征,`adj`是邻接矩阵,`labels`是标签,`idx_test`是测试样本的索引。我们使用`model.eval()`将模型切换到测试模式,然后使用`model(features, adj)`计算输出,使用`torch.max`计算最大值,使用`torch.sum`计算正确的预测数量,使用`acc = correct.item() / len(idx_test)`计算准确率。 以下是一个完整的GCN模型的实现: ```python import torch import torch.nn as nn import torch.nn.functional as F class GCN(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super(GCN, self).__init__() self.fc1 = nn.Linear(input_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, output_dim) def forward(self, x, adj): x = F.relu(self.fc1(torch.mm(adj, x))) x = self.fc2(torch.mm(adj, x)) return F.log_softmax(x, dim=1) def train(model, optimizer, criterion, features, adj, labels, idx_train): model.train() optimizer.zero_grad() output = model(features, adj) loss = criterion(output[idx_train], labels[idx_train]) loss.backward() optimizer.step() return model, optimizer, loss.item() def test(model, features, adj, labels, idx_test): model.eval() output = model(features, adj) _, preds = torch.max(output, dim=1) correct = torch.sum(preds[idx_test] == labels[idx_test]) acc = correct.item() / len(idx_test) return acc ``` 接下来,我们需要加载数据。以下是一个简单的实现: ```python import numpy as np def load_data(): adj = np.array([[0, 1, 1, 0], [1, 0, 1, 0], [1, 1, 0, 1], [0, 0, 1, 0]]) features = np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1], [1, 0, 0]]) labels = np.array([0, 1, 2, 0]) idx_train = np.array([0, 1, 2]) idx_test = np.array([3]) return adj, features, labels, idx_train, idx_test ``` 在上面的代码,我们定义了一个简单的图。`adj`是邻接矩阵,`features`是输入特征,`labels`是标签,`idx_train`是训练样本的索引,`idx_test`是测试样本的索引。 接下来,我们需要训练模型。以下是一个简单的实现: ```python import torch.optim as optim adj, features, labels, idx_train, idx_test = load_data() model = GCN(input_dim=features.shape[1], hidden_dim=16, output_dim=labels.max()+1) optimizer = optim.Adam(model.parameters(), lr=0.01) criterion = nn.CrossEntropyLoss() for epoch in range(100): model, optimizer, loss = train(model, optimizer, criterion, features, adj, labels, idx_train) acc = test(model, features, adj, labels, idx_test) print('Epoch: {:03d}, Loss: {:.4f}, Acc: {:.4f}'.format(epoch, loss, acc)) ``` 在上面的代码,我们定义了一个优化器和一个损失函数。然后,我们使用一个循环来训练模型,并使用`test`函数测试模型。我们使用`print`函数打印训练和测试的损失和准确率。 以上就是使用PyTorch实现GCN的一些基本步骤。当然,这只是一个简单的实现,实际还有很多需要改进的地方。希望能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值