3深度学习模型
1.模型构造
(1)继承Module类
Module类是nn模块里提供的一个模型构造类,是所有神经网络模块的基类,我们可以继承它来定义我们想要的模型。这里定义的类重载了Module类的__init__函数和forward函数。它们分别用于创建模型参数和定义前向计算。前向计算也即正向传播。
class my_module(nn.Module):
def __init__(self):
super().__init__()
self.hidden=nn.Linear(784,256)
self.act=nn.ReLU()
self.output=nn.Linear(256,10)
def forward(self,x):
a=self.act(self.hidden(x))
return self.output(a)
上面的类无需定义反向传播函数,系统将通过自动求梯度而自动生成反向传播所需的backward函数
#两个样本,每个样本784列的矩阵
x=torch.rand(2,784)
net=my_module()
print(net)
print(net(x))
net(x)会调用my_module继承自Module类的__call__函数,这个函数将调用my_module类的forward函数
输出:
my_module(
(hidden): Linear(in_features=784, out_features=256, bias=True)
(act): ReLU()
(output): Linear(in_features=256, out_features=10, bias=True)
)
tensor([[ 0.1251, -0.0191, 0.2413, -0.1530, 0.1385, 0.0641, 0.0340, -0.0722,
-0.0172, -0.0353],
[ 0.0679, -0.0019, 0.2419, -0.0127, 0.1081, 0.1001, -0.0356, -0.1995,
0.0957, 0.0618]], grad_fn=<AddmmBackward0>)
(2)Module的子类
Sequential类:它可以接收一个子模块的有序字典或者一系列子模块作为参数来逐一添加Module的实例,而模型的前向计算就是将这些实例按添加的顺序逐一计算
net=nn.Sequential(
nn.Linear(784,256),
nn.ReLU(),
nn.Linear(256.10)
)
ModuleList类:接收一个子模块的列表作为输入,然后也可以类似List那样进行append和extend操作:
net=nn.ModuleList([nn.Linear(784,256),nn.ReLU()])
net.append(nn.Linear(256,10))
net.extend([
nn.Linear(10,3),
nn.ReLU()
])
#类似于List的索引访问
print(net[-1])
ModuleList仅仅是一个储存各种模块的列表,这些模块之间没有联系也没有顺序(所以不用保证相邻层的输入输出维度匹配),而且没有实现forward功能需要自己实现;而Sequential内的模块需要按照顺序排列,要保证相邻层的输入输出大小相匹配,内部forward功能已经实现。
ModuleDict类:接收一个子模块的字典作为输入, 然后也可以类似字典那样进行添加访问操作:
net = nn.ModuleDict({
'linear': nn.Linear(784, 256),
'act': nn.ReLU(),
})
net['output'] = nn.Linear(256, 10)
print(net['linear'])
print(net.output)
2.模型参数
先定义一个含单隐藏层的多层感知机:
net=nn.Sequential(nn.Linear(4,3),
nn.ReLU(),
nn.Linear(3,1))
(1)参数访问
我们可以通过Module类的parameters()或者named_parameters方法来访问所有参数(以迭代器的形式返回),后者除了返回参数Tensor外还会返回其名字
for name,params in net.named_parameters():
print(name,params.size())
输出:
#这块输出自动加上了层数的索引
0.weight torch.Size([3, 4])
0.bias torch.Size([3])
2.weight torch.Size([1, 3])
2.bias torch.Size([1])
(2)初始化模型参数
PyTorch的
init模块里提供了多种预设的初始化方法
权重参数初始化为均值为0,标准差为0.01的正态分布随机数:
for name,param in net.named_parameters():
if 'weight' in name:
init.normal_(param,mean=0,std=0.01)
print(name,param.data)
常数初始化权重参数:
for name,param in net.named_parameters():
if 'bias' in name:
init.constant_(param,val=0)
print(name,param.data)
(3)自定义初始化方法
在下面的例子里,我们令权重有一半概率初始化为0,有另一半概率初始化为[−10,−5][−10,−5]和[5,10][5,10]两个区间里均匀分布的随机数
def init_(tensor):
with torch.no_grad():
tensor.uniform_(-10,10)
tensor*=(tensor.abs()>=5).float()
(4)共享模型参数
Module类的forward函数里多次调用同一个层。此外,如果我们传入Sequential的模块是同一个Module实例的话参数也是共享的
linear=nn.Linear(1,1,bias=False)
net=nn.Sequential(linear,linear)
print(net)
print(id(net[0])==id(net[1]))
输出:
Sequential(
(0): Linear(in_features=1, out_features=1, bias=False)
(1): Linear(in_features=1, out_features=1, bias=False)
)
True
内存中,这两个线性层其实是一个对象
3.自定义层
(1)不含模型参数的自定义层
class Layer(nn.Module):
def __init__(self):
super(Layer,self).__init__()
def forward(self,x):
return x-x.mean()
实例化后进行计算
layer=Layer()
print(layer(torch.tensor([1,2,3,4,5],dtype=torch.float)))
也可以嵌套到其他的模型
net=nn.Sequential(nn.Linear(8,128),Layer())
y=net(torch.rand(4,8))
print(y)
(2)含模型参数的自定义层
Parameter类其实是Tensor的子类,如果一个Tensor是Parameter,那么它会自动被添加到模型的参数列表里。所以在自定义含模型参数的层时,我们应该将参数定义成Parameter,除了直接定义成Parameter类外,还可以使用ParameterList和ParameterDict分别定义参数的列表和字典。
ParameterList接收一个Parameter实例的列表作为输入然后得到一个参数列表,使用的时候可以用索引来访问某个参数,另外也可以使用append和extend在列表后面新增参数。
class MyModule(nn.Module):
def __init__(self):
super(MyModule,self).__init__()
#生成3个4×40可训练矩阵的参数列表
self.params=nn.ParameterList([nn.Parameter(torch.randn(4,4)) for i in range(3)])
self.params.append(nn.Parameter(torch.randn(4,1)))
def forward(self,x):
for i in range(len(self.params)):
x=torch.mm(x,self.params[i])
return x
net=MyModule()
print(net)
输出:
MyModule(
(params): ParameterList(
(0): Parameter containing: [torch.float32 of size 4x4]
(1): Parameter containing: [torch.float32 of size 4x4]
(2): Parameter containing: [torch.float32 of size 4x4]
(3): Parameter containing: [torch.float32 of size 4x1]
)
)
ParameterDict接收一个Parameter实例的字典作为输入然后得到一个参数字典,然后可以按照字典的规则使用了。例如使用update()新增参数,使用keys()返回所有键值,使用items()返回所有键值对等等
class MyModule(nn.Module):
def __init__(self):
super(MyModule,self).__init__()
self.params=nn.ParameterDict({
'linear1':nn.Parameter(torch.randn(4,4)),
'linear2':nn.Parameter(torch.randn(4,1))
})
#新增
self.params.update({'linear3':nn.Parameter(torch.randn(4,2))})
def forward(self,x,choice='linear1'):
return torch.mm(x,self.params[choice])
传入不同键值进行不同前向传播
net=MyModule()
x=torch.ones(1,4)
print(net(x,'linear1'))
print(net(x,'linear2'))
print(net(x,'linear3'))
输出:
tensor([[-1.5421, -0.7143, 0.4266, -1.4878]], grad_fn=<MmBackward0>)
tensor([[-1.8164]], grad_fn=<MmBackward0>)
tensor([[0.3059, 0.2883]], grad_fn=<MmBackward0>)
4.读取和存储
(1)读写Tensor
可以直接使用save函数和load函数分别存储和读取Tensor。save使用Python的pickle实用程序将对象进行序列化,然后将序列化的对象保存到disk,使用save可以保存各种对象,包括模型、张量和字典等。而load使用pickle unpickle工具将pickle的对象文件反序列化为内存。
x=torch.ones(3)
#保存Tensor
torch.save(x,'x.pt')
#读取Tensor
x2=torch.load('x.pt')
print(x2)
存储并读取一个字符串映射到Tensor的字典
torch.save({'x':x,'y':y},'dict.pt')
xy=torch.load('dict.pt')
print(xy)
(2)读写模型
Module的可学习参数(即权重和偏差),模块模型包含在参数中(通过model.parameters()访问)了,state_dict是一个从参数名称隐射到参数Tesnor的字典对象
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.hidden=nn.Linear(3,2)
self.act=nn.ReLU()
self.output=nn.Linear(2,1)
def forward(self,x):
a=self.act(self.hidden(x))
return self.output(a)
net=Net()
net.state_dict()
输出:
OrderedDict([('hidden.weight', tensor([[ 0.5434, -0.4373, -0.0586],
[ 0.4214, 0.5489, 0.0186]])),
('hidden.bias', tensor([-0.3037, 0.0326])),
('output.weight', tensor([[-0.0588, 0.3124]])),
('output.bias', tensor([0.1242]))])
(3)保存和加载模型
仅保存和加载模型参数
#保存
torch.save(net.state_dict(),PATH)
#加载
net1=Net()
net1.load_state_dict(torch.load(PATH))
保存和加载整个模型
torch.save(model,PATH)
net=torch.load(PATH)
5.GPU计算
(1)查看显卡信息
!nvidia-smi # 对Linux/macOS用户有效
(2)计算设备
查看GPU是否可用
torch.cuda.is_available()
查看GPU数量
torch.cuda.device_count()
查看当前GPU索引号
torch.cuda.current_device()
根据索引查看GPU名字
torch.cuda.get_device_name(0)
使用.cuda()可以将CPU上的Tensor转换(复制)到GPU上
x=x.cuda(0)
x = torch.tensor([1, 2, 3], device=device)
x = torch.tensor([1, 2, 3]).to(device)
(3)模型的GPU计算
PyTorch模型也可以通过.cuda转换到GPU上
net.cuda()
list(net.parameters())[0].device
更多推荐

所有评论(0)