深度学习笔记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)