利用Pytorch训练自己的网络模型

Author Avatar
NENEIIII Mar 17, 2021
  • Read this article on other devices

通过继承nn.Module类来实现

  • 在_init_构造函数中申明各个层的定义.

  • 在forward中实现层之间的连接关系,实际上就是前向传播的过程.

注意:pytorch里面一般是没有层的概念,层也是当成一个模型来处理的

例如:

# 全连接层
class Linear(Module):
    __constants__ = ['bias']

    def __init__(self, in_features, out_features, bias=True):
        super(Linear, self).__init__()
        self.in_features = in_features
        self.out_features = out_features
        self.weight = Parameter(torch.Tensor(out_features, in_features))
        if bias:
            self.bias = Parameter(torch.Tensor(out_features))
        else:
            self.register_parameter('bias', None)
        self.reset_parameters()
     
    def reset_parameters(self):
        init.kaiming_uniform_(self.weight, a=math.sqrt(5))
        if self.bias is not None:
            fan_in, _ = init._calculate_fan_in_and_fan_out(self.weight)
            bound = 1 / math.sqrt(fan_in)
            init.uniform_(self.bias, -bound, bound)
# 卷积层
class Conv2d(_ConvNd):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                 padding=0, dilation=1, groups=1,
                 bias=True, padding_mode='zeros'):
        kernel_size = _pair(kernel_size)
        stride = _pair(stride)
        padding = _pair(padding)
        dilation = _pair(dilation)
        super(Conv2d, self).__init__(
            in_channels, out_channels, kernel_size, stride, padding, dilation,
            False, _pair(0), groups, bias, padding_mode)

基本步骤

简单来讲就是:先继承,再构建组件,最后组装

其中基本组件可从 torch.nn 中获取,或者从 torch.nn.functional 中获取,同时为了方便重复使用组件,可以使用 Sequential 容器将一系列组件包起来,最后在 forward() 函数中将这些组件组装成你的模型

定义一个自己的模型

利用sequential

mynet = torch.nn.Sequential(
        torch.nn.Linear(1, 10),
        torch.nn.ReLU(),
        torch.nn.Linear(10, 1))

定义自己的模型类

  1. 线性模型
# 只含线性变换的
class MyNet(torch.nn.Module):
    def __init__(self, n_feature, n_hidden, n_output):
        super(MyNet, self).__init__()
        self.hidden = torch.nn.Linear(n_feature, n_hidden)
        self.predict = torch.nn.Linear(n_hidden, n_output)
        
    def forward(self, x):
        x = F.relu(self.hidden(x))
        x = self.predict(x)
        return x

net = MyNet(1, 10, 1)
  1. 卷积网络
    ```python

    CNN模型

    class CNN(nn.Module):
    def init(self):

     super(CNN, self).__init__()
     self.conv1 = nn.Sequential(  
         nn.Conv2d(
         in_channels=1,      
         out_channels=16,   
         kernel_size=5,     
         stride=1,         
         padding=2, 
         ),      
         nn.ReLU(),    
         nn.MaxPool2d(kernel_size=2),   
     )
     self.conv2 = nn.Sequential(  
         nn.Conv2d(16, 32, 5, 1, 2), 
         nn.ReLU(),  
         nn.MaxPool2d(2),  
     )
     self.out = nn.Linear(32 * 7 * 7, 10) 
    

    def forward(self, x):

     x = self.conv1(x)
     x = self.conv2(x)
    

    变成一个1维的

     x = x.view(x.size(0), -1)  
     output = self.out(x)
     return output
    

    cnn = CNN()

    打印网络结构

    print(cnn)


#gpu加速
将所有数据和操作加上.cuda()
x = x.cuda()
y = y.cuda()
cnn = CNN()
cnn.cuda()


#保存
torch.save(net, ‘net.pkl’) #保存整个网络
torch.save(net.state_dict(), ‘net_params.pkl’) #只保存网络中的参数
#提取
net = torch.load(‘net.pkl’)
net3 =
net3.load_state_dict(torch.load(‘net_params.pkl’))




# 关于输入输出的维度

1. 首先明确:[NumPy中的维度(dimension)、轴(axis)、秩(rank)的含义](https://zhuanlan.zhihu.com/p/51200424)

- 维度称为轴,二者可以看成等价

- 秩:维度的数量
```python
ndarray.ndim:秩
ndarray.shape:返回一个元组:这个元组描述了每个维度中数组的大小,如(3,)表示数组是一维的,拥有3个数据
  1. pytorch中的数据类型是tensor张量,相关概念和ndarray类似,参考torch.Tensor - 《PyTorch 1.2 中文文档 & 教程

Torch定义了八种CPU张量类型和八种GPU张量类型,通常使用的torch.Tensor 是默认的tensor类型 (torch.FloatTensor) 的简称

import torch
tensor = torch.randn(3, 4, 5) # 随机生成一个tensor
print(tensor.size()) # 类似ndarray.shape
print(tensor.dim()) # 维度
print(tensor.type()) # 默认类型FloatTensor

torch.Size([3, 4, 5])
3
torch.FloatTensor

  1. 关于Tensor.view

用来改变tensor的形状

a = torch.randn(2, 6)
a.view(1, 12).size()

torch.Size([1, 12])

a.view(3, 4).size()

torch.Size([3, 4])

a.view(6, -1).size() # -1表示自动计算剩下的数字

torch.Size([6, 2])

a.view(4, 2).size()

shape[4, 2]is invalid for input of size 12

总元素必须和原来的一样

CNN中每层的连接(维度转化)

卷积层(卷积+池化)输出尺寸计算

torch.nn.Conv2d(in_channels,out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1,bias=True)

假设输入图片尺寸:6×6×3 [长 宽 通道] –>

卷积核尺寸:2×2×3 [通道数必须和图片保持一致]

输出图片长宽为

关于通道**channel**:

in_channels:图片的通道,通常为3(RGB),1(grey)

卷积核的channel:与图片(in_channels)保持一致

out_channels:输出图片的通道,取决于卷积核的数量,如上面只有一个卷积核则输出通道是1

注意:如果多个卷积层相连,则下层的卷积层in_channels就是上层的out_channels

卷积层与全连接层的维度转化

  1. nn.Linear()是用于设置网络中的全连接层的,需要注意的是全连接层的输入与输出都是

torch.nn.Linear(d_in,d_out)

这里的d_in就设置成size的大小

d_out也代表全连接层的神经元个数

经过该全连接层的形状变为:[batch_size, d_out]

  1. 而卷积层要求输入输出是**

再看下之前的示例:

        self.conv1 = nn.Sequential(  
                    nn.Conv2d(
                    in_channels=1,      
                    out_channels=16,   
                    kernel_size=5,     
                    stride=1,         
                    padding=2, 
                    ),      
                    nn.ReLU(),    
                    nn.MaxPool2d(kernel_size=2),   
                )
        self.conv2 = nn.Sequential(  
            nn.Conv2d(16, 32, 5, 1, 2), 
            nn.ReLU(),  
            nn.MaxPool2d(2),  
        )
        self.out = nn.Linear(32 * 7 * 7, 10) 
    def forward(self, x):
        # 输入图片bs*7*7*1 bs:batch_size 长宽7*7 channels 1
        x = self.conv1(x)
        # 经过第一个卷积层:bs*7*7*16
        x = self.conv2(x)
        # 经过第二个卷积:bs*7*7*32,因此上述linear要设置d_in: 7*7*32
        # 送入全连接层要变成一个2维张量
        # x.size(0)就是bs的大小,-1就是自动将剩下的C*H*W计算
        x = x.view(x.size(0), -1)  
        # 经过一个线性变换:bs*10,通常在分类问题中就代表有10个类别输出
        output = self.out(x)