欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > 深度学习·Pytorch

深度学习·Pytorch

2024/10/24 20:22:31 来源:https://blog.csdn.net/2301_80132162/article/details/141195003  浏览:    关键词:深度学习·Pytorch

以下代码源自李沐

自定义模块类

继承module类

  • 继承nn.Module
  • 重写构造函数+前向传播
class MLP(nn.Module):# 用模型参数声明层。这里,我们声明两个全连接的层def __init__(self):# 调用MLP的父类Module的构造函数来执行必要的初始化。# 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍)super().__init__()self.hidden = nn.Linear(20, 256)  # 隐藏层self.out = nn.Linear(256, 10)  # 输出层# 定义模型的前向传播,即如何根据输入X返回所需的模型输出def forward(self, X):# 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。return self.out(F.relu(self.hidden(X)))

顺序块

_module的本质是OrderedDict字典
利用enumerate(args)打包索引和module

class MySequential(nn.Module):def __init__(self, *args):super().__init__()for idx, module in enumerate(args):# 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员# 变量_modules中。_module的类型是OrderedDictself._modules[str(idx)] = moduledef forward(self, X):# OrderedDict保证了按照成员添加的顺序遍历它们for block in self._modules.values():X = block(X)return X

参数访问

字典返回

  • print(net.state_dict()):返回所有nn对应的weight和bias
  • print(net[2].state_dict()):返回第二层的weight和bias

直接访问

bias,weight都是nn.Parameter的子类
例如:

  • 使用nn.bias返回的是nn.parameter
  • 使用nn.bias.data返回的是bias具体的数值

自定义层

含参数的自定义层

层的构造函数:输入和输出单元个数
注意套上nn.Parameter
注意定义好forward函数

class MyLinear(nn.Module):def __init__(self, in_units, units):super().__init__()self.weight = nn.Parameter(torch.randn(in_units, units))self.bias = nn.Parameter(torch.randn(units,))def forward(self, X):linear = torch.matmul(X, self.weight.data) + self.bias.datareturn F.relu(linear)

*数据预处理

这一部分从李沐中学到了很多新函数和操作技巧

选择部分行

排除某些行:使用python的列表递推式

features=[i for i in data.columns if not in 'Sale Price']

选择数值型变量

dtype返回一个Series,对每一个Series进行条件索引,最后返回符合条件的index作为dataframe的索引

numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
all_features[numeric_features] = all_features[numeric_features].apply(lambda x: (x - x.mean()) / (x.std()))

热编码

dummy_na=True:给nan也分个类型

all_features = pd.get_dummies(all_features, dummy_na=True)

数据转换为dataset和dataloader

dataset是torch的数据存储单位
dataloader是torch的数据处理器,本质上是一个迭代器,可以用于随机抽样,返回batch_size大小的数据(打包返回)和与之对应的标签
*args:将多个数据打包为元组

def load_array(data_arrays, batch_size, is_train=True):"""Construct a PyTorch data iterator.sDefined in :numref:`sec_linear_concise`"""dataset = data.TensorDataset(*data_arrays)return data.DataLoader(dataset, batch_size, shuffle=is_train)

训练函数train

  • 神经网络、数据集、测试集、学习率、衰减率、批量大小
  • train_iter:将数据转换为dataloader,X是数据,y是标签
def train(net, train_features, train_labels, test_features, test_labels,num_epochs, learning_rate, weight_decay, batch_size):train_ls, test_ls = [], []train_iter = d2l.load_array((train_features, train_labels), batch_size)# 这里使用的是Adam优化算法optimizer = torch.optim.Adam(net.parameters(),lr = learning_rate,weight_decay = weight_decay)for epoch in range(num_epochs):for X, y in train_iter:optimizer.zero_grad()l = loss(net(X), y)l.backward()optimizer.step()train_ls.append(log_rmse(net, train_features, train_labels))if test_labels is not None:test_ls.append(log_rmse(net, test_features, test_labels))return train_ls, test_ls

K折交叉验证

总共进行K*nums_epoch次的循环

沿着行拼接tensor:torch.cat([y_train, y_part], 0)

  • 如果i等于j:选择作为验证集(CV)
  • 如果训练集为空:生成新的训练集
  • 如果训练集不为空:拼接新的训练集
def get_k_fold_data(k, i, X, y):assert k > 1fold_size = X.shape[0] // kX_train, y_train = None, Nonefor j in range(k):idx = slice(j * fold_size, (j + 1) * fold_size)X_part, y_part = X[idx, :], y[idx]if j == i:X_valid, y_valid = X_part, y_partelif X_train is None:X_train, y_train = X_part, y_partelse:X_train = torch.cat([X_train, X_part], 0)y_train = torch.cat([y_train, y_part], 0)return X_train, y_train, X_valid, y_valid
def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay,batch_size):train_l_sum, valid_l_sum = 0, 0for i in range(k):data = get_k_fold_data(k, i, X_train, y_train)net = get_net()train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,weight_decay, batch_size)train_l_sum += train_ls[-1]# 取最小的损失valid_l_sum += valid_ls[-1]if i == 0:d2l.plot(list(range(1, num_epochs + 1)), [train_ls, valid_ls],xlabel='epoch', ylabel='rmse', xlim=[1, num_epochs],legend=['train', 'valid'], yscale='log')print(f'折{i + 1},训练log rmse{float(train_ls[-1]):f}, 'f'验证log rmse{float(valid_ls[-1]):f}')return train_l_sum / k, valid_l_sum / k

训练+预测

preds = net(test_features).detach().numpy():tensor转换为numpy前使用detach
pd.concat:接受两个numpy数组或者dataframe,注意索引不会重复添加

def train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size):net = get_net()train_ls, _ = train(net, train_features, train_labels, None, None, num_epochs, lr, weight_decay, batch_size)d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',ylabel='log rmse', xlim=[1, num_epochs], yscale='log')print(f'lr:{weight_decay:.2f},训练log rmse:{float(train_ls[-1]):f}')# 将网络应用于测试集。preds = net(test_features).detach().numpy()# 将其重新格式化以导出到Kaggletest_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])# 返回一个一维数组用于拼接submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)#submission.to_csv('submission.csv', index=False)# 不存储index

torch的存取

操作函数:torch.save()

tensor的保存

y = torch.zeros(4)
torch.save([x, y],'x-files')
x2, y2 = torch.load('x-files')
(x2, y2)
mydict = {'x': x, 'y': y}
torch.save(mydict, 'mydict')
mydict2 = torch.load('mydict')
mydict2

*模型的保存

torch不是很好支持模型的定义存储,我们只需要存储模型的参数,最后克隆定义就好

torch.save(net.state_dict(), 'mlp.params')
load_state_dict(torch.load('mlp.params'))

clone = MLP()
clone.load_state_dict(torch.load('mlp.params'))
clone.eval()

下一次直接调用clone(X)作为预测就好了

迁移学习

下载训练好的resnet18

finetune_net = torchvision.models.resnet18(pretrained=True)
finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2)# 修改输出层参数
nn.init.xavier_uniform_(finetune_net.fc.weight);# 重新初始化输出层

对于靠近输入的层变化应该小一点,对于输出的层变化应该大一点。
可以从net.named_parameters()中选取不同学习率的优化器。

if param_group:params_1x = [param for name, param in net.named_parameters()if name not in ["fc.weight", "fc.bias"]]trainer = torch.optim.SGD([{'params': params_1x},{'params': net.fc.parameters(),'lr': learning_rate * 10}],lr=learning_rate, weight_decay=0.001)

图像增广

图像增广可以提高数据集的多样性,增强模型的泛化能力

翻转和裁剪

[左右翻转图像]通常不会改变对象的类别。这是最早且最广泛使用的图像增广方法之一。
接下来,我们使用transforms模块来创建RandomFlipLeftRight实例,这样就各有50%的几率使图像向左或向右翻转。
torchvision.transforms.RandomHorizontalFlip()
torchvision.transforms.RandomVerticalFlip()
下面的代码将[随机裁剪]一个面积为原始面积10%到100%的区域,该区域的宽高比从0.5~2之间随机取值。
然后,区域的宽度和高度都被缩放到200像素。
在本节中(除非另有说明), a a a b b b之间的随机数指的是在区间 [ a , b ] [a, b] [a,b]中通过均匀采样获得的连续值。

torchvision.transforms.RandomResizedCrop( (200, 200), scale=(0.1, 1), ratio=(0.5, 2)

改变颜色

另一种增广方法是改变颜色。
我们可以改变图像颜色的四个方面:亮度、对比度、饱和度和色调。
在下面的示例中,我们[随机更改图像的亮度],随机值为原始图像的50%( 1 − 0.5 1-0.5 10.5)到150%( 1 + 0.5 1+0.5 1+0.5)之间。
torchvision.transforms.ColorJitter( brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5


最后使用transform类进行增广

train_augs = torchvision.transforms.Compose([torchvision.transforms.RandomHorizontalFlip(),torchvision.transforms.ToTensor()])

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com