# 1.3神经网络

```python
import torch
# 神经网络的包,仅支持小批量样本的训练,不支持单个样本(可以input.unsqueeze(0)来模拟批量[1])
import torch.nn as nn 
import torch.nn.functional as F # 一些常用的函数


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 3) # 卷积核
        self.conv2 = nn.Conv2d(6, 16, 3) # 卷积核
        # Linear是简单的映射函数,第一个参数w的维度,第二个参数b的维度
        self.fc1 = nn.Linear(16 * 6 * 6, 120) # 6*6是图片的长宽
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10) # 最后输出10个分类

    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # 最大二维池化层:2*2格子内取最大
        x = F.max_pool2d(F.relu(self.conv2(x)), 2) # 第一个参数的结果是笔直的向量
        x = x.view(-1, self.num_flat_features(x)) # -1表示自动计算,view是改变形状
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x


    def num_flat_features(self, x): # 每个输入变平后的数量大小
        size = x.size()[1:] # 获得除了批量大小的所有维度
        num_features = 1
        for s in size:
            num_features *= s
        return num_features


net = Net()
print(net) # 获取当前模型的数据
```

```
Net(
  (conv1): Conv2d(1, 6, kernel_size=(3, 3), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(3, 3), stride=(1, 1))
  (fc1): Linear(in_features=576, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)
```

```python
params = list(net.parameters())
print(len(params)) # 自动学习参数的数量
print(params[0].size()) # 6*1*3*3 ,conv1的权重
```

```
10
torch.Size([6, 1, 3, 3])
```

```python
print(params[1]) # conv1的偏移
```

```
Parameter containing:
tensor([ 0.0176,  0.2514,  0.1497,  0.1647, -0.2829,  0.0409],
       requires_grad=True)
```

```python
input = torch.randn(1,1,32,32)
out = net(input)
print(out) # 输出,数值最大的是正确分类,但一开始没有训练是随机的
```

```
tensor([[ 6.9398e-03, -6.6113e-05, -6.9214e-02, -7.6395e-02,  3.9166e-02,
         -7.0978e-02,  1.2993e-02, -1.7690e-02, -1.4292e-02, -4.7204e-02]],
       grad_fn=<AddmmBackward>)
```

```python
net.zero_grad() # 设置所有梯度为0
out.backward(torch.randn(1,10)) # 设置随机数为梯度
```

```python
output = net(input)
target = torch.randn(10) # 假设一个假的结果
target = target.view(1, -1) # 变为[1,10]形状
criterion = nn.MSELoss() # 均方误差

loss = criterion(output, target)
print(loss)
```

```
tensor(0.7828, grad_fn=<MseLossBackward>)
```

```python
"""
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
      -> view -> linear -> relu -> linear -> relu(3) -> linear(2)
      -> MSELoss(1)
      -> loss
"""
print(loss.grad_fn)  # MSELoss
print(loss.grad_fn.next_functions[0][0])  # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU
```

```
<MseLossBackward object at 0x7fefaac1c8d0>
<AddmmBackward object at 0x7fefaac1ca90>
<AccumulateGrad object at 0x7fefaac1c8d0>
```

```python
net.zero_grad()

print('conv1.bias.grad before backward') # 反向传播之前
print(net.conv1.bias.grad)

loss.backward()

print('conv1.bias.grad after backward') # 反向传播后
print(net.conv1.bias.grad)
```

```
conv1.bias.grad before backward
tensor([0., 0., 0., 0., 0., 0.])
conv1.bias.grad after backward
tensor([-0.0158, -0.0015, -0.0017,  0.0073,  0.0074, -0.0123])
```

```python
# 更新权重
learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate) # sub_是减等于
```

```python
import torch.optim as optim # 优化算法包

optimizer = optim.SGD(net.parameters(), lr=0.01) # 创建优化算法器

optimizer.zero_grad() # 初始化梯度为0
output = net(input) # 前向传播
loss = criterion(output, target) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新权重
```

```python
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://iamfxz.gitbook.io/ai/xz/pytorch/1.3.torch_net.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
