深度学习笔记014神经网络基础之——模型搭建、参数管理、自定义层、读写文件等内容014_1PytorchModelBuilding&014_2ParameterManagement.py


今天写了两版代码,相关问题也都放在注释里了,Q&A部分在这里。

1、将变量转换成伪变量(one-hot encoding)时内存炸了怎么办?

  1.用稀疏矩阵。

  2.对于一段话,我们独立热编码的时候切词用单个的词语做特征维度。

  3.离散化离散类别太多以至于无法处理,只能丢掉了……

2、模型,可以理解为一个多元函数。

1.014_1PytorchModelBuilding.py

  1 import torch
  2 from torch import nn
  3 from torch.nn import functional as F
  4 
  5 net = nn.Sequential(nn.Linear(20,256),nn.ReLU(),nn.Linear(256,10)) # 第一层,输入20输出256,激活函数,第二层
  6 
  7 X=torch.rand(2,20) # 随机输入
  8 print(net(X))
  9 
 10 # nn.Sequential定义的是一个Module类,所有模型都是这个Module的子类
 11 # 自定义一个MLP:
 12 class MLP(nn.Module):
 13     def __init__(self): #定义参数
 14         super().__init__()
 15         self.hiddenOhYe=nn.Linear(20,256)
 16         self.outOhye=nn.Linear(256,10)
 17 
 18     def forward(self,X):
 19         return self.outOhye(F.relu(self.hiddenOhYe(X)))
 20 
 21 net=MLP()
 22 print(net(X))
 23 
 24 print("------------------------------------------------------------------------")
 25 
 26 # 手搓一个MySequential
 27 class Sequential(nn.Module):
 28     def __init__(self,*args):
 29         super().__init__()
 30         for block in args:
 31             self._modules[block]=block  # 对于每一个子类,放入_modules结构中,是一个按顺序的字典
 32 
 33     def forward(self,X):
 34         for block in self._modules.values():
 35             X=block(X)
 36         return X
 37 
 38 net = Sequential(nn.Linear(20,256),nn.ReLU(),nn.Linear(256,10)) # 第一层,输入20输出256,激活函数,第二层
 39 print(net(X))
 40 
 41 print("------------------------------------------------------------------------")
 42 
 43 # 我们可以随心所欲地写我们的MLP
 44 # 情景:给一个30*50的随机矩阵,首先让他进入50-256的线性回归层,输出的256层统一加上50,进入SIGMOD层,随后
 45 # 进入256-256的线性回归层,随后进入relu,随后统一+1,随后进入256-16的liner,随后进行relu,随后求绝对值的和,
 46 # 每一层加上绝对值的和,随后进入16-1的liner,输出这个结果
 47 X=torch.rand(5,50) # 随机输入
 48 class FixedHiddenMLP(nn.Module):
 49     def __init__(self):
 50         super().__init__()
 51         self.rand_weight=torch.rand((5,50),requires_grad=False)# 不记录梯度,瞎几把算
 52         self.liner50_256=nn.Linear(50,256)
 53         self.liner256_256 = nn.Linear(256, 256)
 54         self.liner256_16 = nn.Linear(256, 16)
 55         self.liner16_1 = nn.Linear(16, 1)
 56         # self.relu=F.relu()
 57         # self.sigmod=F.sigmoid()
 58 
 59     def forward(self,X):
 60         print("正在装填X:",X)
 61         X=self.liner50_256(X)
 62         print("正在50-》256X,X:", X)
 63         X=X+50
 64         print("正在加上50,X:", X)
 65         X=torch.sigmoid(X)
 66         print("正在sigmoid,X:", X)
 67         X=self.liner256_256(X)
 68         print("正在256-256,X:", X)
 69         X=F.relu(X)+1
 70         print("正在relu+1,X:", X)
 71         X=self.liner256_16(X)
 72         print("正在256-16,X:", X)
 73         X=F.relu(X)
 74         print("正在relu,X:", X)
 75         sumX=X.abs().sum()
 76         print("正在求绝对值的和,sumX:", sumX)
 77         while sumX > 1:
 78             X=X+sumX
 79             sumX=sumX-1
 80         print("求完和的X:", X)
 81         X=self.liner16_1(X)
 82         print("最终的X:",X)
 83         return X
 84 
 85 # 我们可以随心所欲地写我们的MLP
 86 # 情景:给一个30*50的随机矩阵,首先让他进入50-256的线性回归层,输出的256层统一加上50,进入SIGMOD层,随后
 87 # 进入256-256的线性回归层,随后进入relu,随后统一+1,随后进入256-16的liner,随后进行relu,随后求绝对值的和,
 88 # 每一层加上绝对值和次绝对值的和,随后进入16-1的liner,输出这个结果
 89 net = FixedHiddenMLP()
 90 print(net(X))
 91 
 92 print("--------------------------------------------------------------")
 93 # 上面介绍的方法我们可以灵活地搭配和嵌套,比如咱们随便写一个
 94 class NestMLP(nn.Module):
 95     def __init__(self):
 96         super().__init__()
 97         self.net = nn.Sequential(nn.Linear(50, 64), nn.ReLU(),
 98                                  nn.Linear(64, 32), nn.ReLU())
 99         self.linear = nn.Linear(32, 16)
100     def forward(self, X):
101         return self.linear(self.net(X))
102 chimera = nn.Sequential(NestMLP(), nn.Linear(16, 50), FixedHiddenMLP())
103 print("---------------------------------------------------------------")
104 print(chimera(X))

2.014_2ParameterManagement.py

  1 import torch
  2 from torch import nn
  3 
  4 net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
  5 X = torch.rand(size=(2, 4))
  6 print(net(X))
  7 # Sequential类似一个list,每一层都是一个元素
  8 for i in range(len(net)):
  9     print(net[i].state_dict())  # 输出:
 10 '''
 11 OrderedDict([('weight', tensor([[ 0.1588, -0.0134, -0.0438,  0.2997, -0.1211,  0.0501, -0.3201,  0.2290]])), ('bias', tensor([0.3376]))])
 12 前面是权重矩阵w ,后面是偏移
 13 '''
 14 
 15 print(type(net[2].bias))  # Parameter类型,即可优化的变量
 16 print(net[2].bias)
 17 print(net[2].bias.data)
 18 print(net[2].weight.grad)  # 暂时没有计算梯度,所以梯度是None
 19 
 20 print(*[(name, param.shape) for name, param in net[0].named_parameters()])
 21 print("--------------------------------------------------------------------------")
 22 print(*[(name, param.shape) for name, param in net.named_parameters()])
 23 
 24 print(net.state_dict()['2.bias'].data)
 25 print(*[(name, param.data) for name, param in net.named_parameters()])
 26 print(*[(name, param) for name, param in net.named_parameters()])
 27 
 28 
 29 def block1():
 30     return nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 4), nn.ReLU())
 31 
 32 
 33 def block2():
 34     net = nn.Sequential()
 35     for i in range(4):
 36         net.add_module(f'block {i}', block1())
 37     return net
 38 
 39 
 40 rgnet = nn.Sequential(block2(), nn.Linear(4, 1))
 41 print(rgnet(X))
 42 print("\n\n\n")
 43 print(rgnet)  # 将这个套娃的网络打印出来
 44 
 45 
 46 def init_normal(m):  # 把所有线性的权重矩阵做成正态分布,同时偏移赋值为0
 47     if type(m) == nn.Linear:
 48         nn.init.normal_(m.weight, mean=0, std=0.01)
 49         nn.init.zeros_(m.bias)  # 偏移赋值为0
 50 
 51 
 52 net.apply(init_normal)  # 对于所有net里面的layer,我们用for循环遍历调用初始化函数
 53 print(net[0].weight.data[0], '\n', net[0].bias.data[0])
 54 
 55 
 56 # 不能把weight全部初始化成同样的,否则所有神经元都一样
 57 def init_constant(m):
 58     if type(m) == nn.Linear:
 59         nn.init.constant_(m.weight, 1)  # weight全部变成1
 60         nn.init.zeros_(m.bias)
 61 
 62 
 63 net.apply(init_constant)
 64 print(net[0].weight.data[0], net[0].bias.data[0])
 65 print("------------------------------------------------------------------------")
 66 
 67 
 68 # 也可以单独分别用不同的初始化函数初始化
 69 def xavier(m):
 70     if type(m) == nn.Linear:
 71         nn.init.xavier_uniform_(m.weight)
 72 
 73 
 74 def init_42(m):
 75     if type(m) == nn.Linear:
 76         nn.init.constant_(m.weight, 42)
 77 
 78 
 79 net[0].apply(xavier)
 80 net[2].apply(init_42)
 81 print(net[0].weight.data[0])
 82 print(net[2].weight.data)
 83 
 84 
 85 # 一些更加暴力的处理方法,干脆直接:
 86 def my_init(m):
 87     if type(m) == nn.Linear:
 88         print("Init", *[(name, param.shape)
 89                         for name, param in m.named_parameters()][0])
 90         nn.init.uniform_(m.weight, -10, 10)
 91         m.weight.data *= m.weight.data.abs() >= 5
 92 
 93 
 94 net.apply(my_init)
 95 print(net[0].weight[:2])
 96 
 97 net[0].weight.data[:] += 1
 98 net[0].weight.data[0, 0] = 42
 99 print(net[0].weight.data[0])
100 
101 # 参数绑定
102 shared = nn.Linear(8, 8)
103 net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), shared, nn.ReLU(), shared, nn.ReLU(), nn.Linear(8, 1))
104 net(X)
105 print(net[2].weight.data[0] == net[4].weight.data[0])
106 net[2].weight.data[0] = 12345
107 print(net[2].weight.data[0] == net[4].weight.data[0])
108 
109 
110 # 自定义层 层也是nn.Module的子类
111 # 比如,输入减掉均值,最终让均值变成0,(中心化)
112 class CenterdLayer(nn.Module):
113     def __init__(self):
114         super().__init__()
115 
116     def forward(self, X):
117         return X - X.mean()
118 
119 
120 layer = CenterdLayer()
121 print(layer(torch.FloatTensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])))
122 
123 # 这个层可以随意加入到别的地方
124 net = nn.Sequential(nn.Linear(8, 128), CenterdLayer())
125 Y = net(torch.rand(4, 8))
126 print(Y.mean())
127 
128 
129 # 可以定义带参数的层
130 class MyLinear(nn.Module):
131     def __init__(self, in_units, units):
132         super().__init__()
133         self.weight = nn.Parameter(torch.randn(in_units, units))  # 输入大小*输出大小的矩阵 标准正态分布
134         self.bias = nn.Parameter(torch.randn(units, ))
135 
136     def forward(self, X):
137         linear = torch.matmul(X, self.weight.data) + self.bias.data
138         return F.relu(linear)
139 
140 
141 dense = MyLinear(5, 3)
142 print(dense.weight)
143 
144 # 存取文件
145 x = torch.arange(4)
146 torch.save(x, "x-file")
147 print(torch.load("x-file"))
148 # 存张量
149 y = torch.arange(4)
150 torch.save([x, y], "x-file")
151 print(torch.load("x-file"))
152 
153 # 存字典
154 mydict = {'x': x, 'y': y}
155 torch.save(mydict, 'mydict')
156 print(torch.load('mydict'))
157 
158 
159 # 加载和保存模型
160 class MLP(nn.Module):
161     def __init__(self):  # 定义参数
162         super().__init__()
163         self.hiddenOhYe = nn.Linear(20, 256)
164         self.outOhye = nn.Linear(256, 10)
165 
166     def forward(self, X):
167         return self.outOhye(F.relu(self.hiddenOhYe(X)))
168 
169 from torch.nn import functional as F
170 
171 net = MLP()
172 X = torch.randn((2, 20))
173 Y = net(X)
174 
175 torch.save(net.state_dict(),'mlp-params')  #参数字典
176 
177 # load过程:
178 clone=MLP()  #网络必须生成,所以移植模型之前,一定要移植这段MLP的代码体
179 clone.load_state_dict(torch.load('mlp-params'))
180 print(clone)
181 print(clone.eval())
182 '''
183 神经网络模块存在两种模式,train模式(net.train())和eval模式(net.eval())。一般的神经网络中,这两种模式是一样的,只有当模型中存在dropout和batchnorm的时候才有区别。
184 一旦我们用测试集进行结果测试的时候,一定要使用net.eval()把dropout关掉,因为这里我们的目的是测试训练好的网络,而不是在训练网络,没有必要再dropout和再计算BN的方差和均值(BN使用训练的历史值)。
185 '''
186 
187 Y_clone=clone(X)
188 print(Y_clone==Y)