利用Pytorch训练自己的网络模型
通过继承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))
定义自己的模型类
- 线性模型
# 只含线性变换的
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)
卷积网络
```pythonCNN模型
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个数据
- 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
- 关于
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
卷积层与全连接层的维度转化
- nn.Linear()是用于设置网络中的全连接层的,需要注意的是全连接层的输入与输出都是
torch.nn.Linear(d_in,d_out)
这里的d_in就设置成size的大小
d_out也代表全连接层的神经元个数
经过该全连接层的形状变为:[batch_size, d_out]
- 而卷积层要求输入输出是**
再看下之前的示例:
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)