class Mydata():
def __init__(self,name,path):
self.name=name
self.path=path #定义实类的时候可以直接将函数值赋予
def hello(self,sex):
print(self.path+sex)
def __len__(self):
print(len(self.name))
一个讲解自定义数据集很好的一个blog(按住crtl+点击这里)
#自定义数据类,必须重载__getitem__()函数和__len__()函数
class MyData(torch.utils.data.Dataset):
#自定义实体类时,回直接调用__init__()函数,可以同时为内部所需要赋值的类变量赋予变量
def __init__(self, root_dir, image_dir, label_dir, transform):
#self.的对象及是类的变量
self.root_dir = root_dir
self.image_dir = image_dir
self.label_dir = label_dir
self.label_path = os.path.join(self.root_dir, self.label_dir)
self.image_path = os.path.join(self.root_dir, self.image_dir)
self.image_list = os.listdir(self.image_path)
self.label_list = os.listdir(self.label_path)
self.transform = transform
# 因为label 和 Image文件名相同,进行一样的排序,可以保证取出的数据和label是一一对应的
self.image_list.sort()
self.label_list.sort()
# __getitem__(self, idx)必须要重载此函数,此函数可以对数据进行索引
def __getitem__(self, idx):
img_name = self.image_list[idx]
label_name = self.label_list[idx]
img_item_path = os.path.join(self.root_dir, self.image_dir, img_name)
label_item_path = os.path.join(self.root_dir, self.label_dir, label_name)
img = Image.open(img_item_path)
with open(label_item_path, 'r') as f:
label = f.readline()
# img = np.array(img)
img = self.transform(img)
sample = {'img': img, 'label': label}
return sample
# 必须重载此函数,此函数可以获得数据集的长度
def __len__(self):
assert len(self.image_list) == len(self.label_list)
return len(self.image_list)
from torch.utils.tensorboard import SummaryWriter #导入tensorboard数据包
write=SummaryWriter('logs') #创建write
write.add_image('title',img,index,dataformat='HWC')
#添加图表,所需数据类型为numpy,需要指定数据高 宽通道 一个顺序
write.add_scalar('标题',x,y) #添加图表的标题
tensorboard --logdir=logs #tensorboard的显示
tensorboard --logdir=logs --port=6007 #改变端口
write.close() #关掉
import torchvision.transforms as transforms
#transform的作用是将原始数据继续裁剪,归一化,totensor等等操作
#totensor
#resize
#alt+enter快速引入库
tensor_trans=transform.toTensor() #获得转换的一个函数,相当于类的实体化,主要利用transform的各种函数
tensor_img=tensor_trans(img) #可以将img转化为tensor数据类型
transform.compose([
transform.centercrop(),
transform.totensor()
]) #将多个进行合成
trans_norms=transoform.normalize([],[]) #归一化transform内部有很多内置函数,可以在transform中进行查看
img_norms=trans_norm(img_tensor) #totensor之后的图像可以转化为归一化,进行tansform之前要把数据类型转化为tensor数据类型
trans_resize=transform.resize(high,length)
img_resize=trans_resize(img)
img_resize=trans_totensor(img_resize) #可以在forward中查看所学的数据类型
trans_reszie_s=transform.reszie(512)
trans_compose=transform.compose([trans_reszie_2,
trans_totensor]) # transpose构建之后和其余的函数一致,只是单纯生成了函数
img_resize_2=trans_compose(img)
#__call__方法可以直接调用,函数需要.调用
#ctrl+p提醒参数数据类型
#关注输入和输出,官方文档print(type(img_resize))查看数据类型
train_set=torchvision.datasets.CIFAR10(root='./dataset',
train=true,
download=true)
#将数据集进行下载并且作为训练集,可以利用这种方法使用官方提供的数据集
#大多数参数都有默认值,需要从中找到没有默认值的参数
#其中dataset为指定数据集,batch_size为每次得到的数据大小,shuffle是是否随机排序,num_workers多进程,在windows下可能有一些问题,drop_last,batch_size中的数据不够整除,是否丢掉
#其中返回的test_loader是img,label的数据,共有batch_size个,从dataset中获取
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=True)
import torch.nn as nn
import torch.nn.functional as F
#继承与父类
class Model(nn.Module):
#自定初始化函数
def __init__(self):
#初始化父类,必须要写的
#所写的函数只是定义,并不是所执行
super().__init__()
self.conv1 = nn.Conv2d(1, 20, 5)
self.conv2 = nn.Conv2d(20, 20, 5)
#前向传播,input->forward->output
#该函数是自动执行的,不需要调用即可。实体类在进行调用之后便会自己执行forward函数
#该函数中是经过依次卷积,经过relu激活函数
#再进行一次卷积,在经过依次非线性激活relu
def forward(self, x):
x = F.relu(self.conv1(x))
return F.relu(self.conv2(x))
#可以从官网文档查看函数中每个参数的意义
torch.reshape(input,(,,,))
F.conv2d(data,kernal)
#conv2d主要应用在图像中
#in_channels输入图片的通道数
#out_channels输出图片的通道数
#kernal_size卷积核的大小
#stride步长
#padding卷积方式
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)
#数据集的导入常用技巧
dataset = torchvision.datasets.CIFAR10("../data", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=64)
卷积进行输入时的维度是[batch_size,channal,high,宽]
在卷积层,池化层中输入都是[batch_size,channal,high,wide]四个参数组成
#这个是torch.nn中的
torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
#这个是torch.nn.functional中的
torch.nn.functional.max_pool2d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
#在functional中的和torch.nn中一般是functional要进行输入,而torch.nn是调用出来
#这个是torch.nn.functional中的
torch.nn.functional.relu(input, inplace=False) → Tensor
#这个是torch.nn中的
#inplace一般设为false,若为true,则原始数据也被替换
torch.nn.ReLU(inplace=False)
#正则化层
#dropout
# in_feature=输入的特征维度
# out_feature=输出的特征维度
# bias偏置
torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)
torch.flatten(img) #将数据展平
# 使用sequential后可以按照顺序继续宁执行
model = nn.Sequential(
nn.Conv2d(1,20,5),
nn.ReLU(),
nn.Conv2d(20,64,5),
nn.ReLU()
)
# 自定义一个网络类,并且继承nn.module
class Net(nn.Module):
def __init__(self):
# 对父类进行初始化
super(Net, self).__init__()
# 利用sequential建立网络
self.model1 = Sequential(
# 输入的维度,输出的维度,卷积核大小,padding方式
Conv2d(3, 32, 5, padding=2),
# 池化方式
MaxPool2d(2),
# 输入的卷积维度,输出的卷积维度,卷积核大小
Conv2d(32, 32, 5, padding=2),
# 池化的方式
MaxPool2d(2),
# 输入的卷积维度,输出的卷积维度,padding的方式
Conv2d(32, 64, 5, padding=2),
# 池化的方式
MaxPool2d(2),
# 平铺
Flatten(),
# 线性输入的维度,线性输出的维度
Linear(1024, 64),
# 线性输入的维度,线性输出的维度
Linear(64, 10)
)
# 在前向调用中直接调用model1,也就是sequential所定义的网络结构
def forward(self, x):
x = self.model1(x)
return x
所使用的网络模型如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pA5dUZJI-1655220591425)(D:\研一\课程\深度学习\DeepLearning\pytorch学习笔记图片\1655100535458.png)]
# 倘若无法计算线形层的结构是多少,可以查看数据的大小,然后继续线性操作
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten()
net=Net()
input = torch.ones((64, 3, 32, 32))
output = net(input)
print(output.shape)
# 可以通过自定义一个torch对象,查看所输出的数据类型
两种定义网络的方式,一种是定义sequential,另一种是初始化里面里面变量,在forward中调用
writer = SummaryWriter("../logs_seq")
writer.add_graph(net, input)
writer.close()
# 可以通过这种方式将所搭建的网络直接通过tensorboard继续输出查看
# 交叉熵损失
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=- 100, reduce=None, reduction='mean', label_smoothing=0.0)
# Example of target with class indices
将损失函数首先定义,然后调用即可
loss = nn.CrossEntropyLoss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.empty(3, dtype=torch.long).random_(5)
output = loss(input, target)
output.backward()
# Example of target with class probabilities
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5).softmax(dim=1)
output = loss(input, target)
output.backward()
# pytorch中标签转为one-hot形式
def one_hot(data, dim):
data = torch.tensor(data)
index = data.unsqueeze(1).to(dtype=int)
train_target = torch.zeros(len(data), dim).scatter_(1, index, 1)
return train_target
# 两种常用的优化器
# lr 学习速率
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr=0.0001)
# 每一次训练要zero_grad(),否则会出现问题
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
# 方法一
# 利用GPU训练可以选择网络模型,损失函数,数据
if torch.cuda.is_available()
net.cuda()
loss.cuda()
data.cuda() #数据中包含数据和标签,data & label
# 方法二
device = torch.device('cpu')
device = torch.device('cuda:0')
cnnNet.to(device)
loss.to(device)
# 在torchvision 中的模型可以导入已经训练好的模型,设置为true则使用官方训练好的额,为false则为未经过训练的原始数据
vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_true = torchvision.models.vgg16(pretrained=True)
# 查看网络架构
print(vgg16,true)
# 利用现成的网络模型预测自己的数据
train_data = torchvision.datasets.CIFAR10('../data', train=True, transform=torchvision.transforms.ToTensor(),
download=True)
# 利用VGG16作为前缀网络,添加一个线性层
vgg16_true.add_module('add_linear', nn.Linear(1000, 10))
vgg16_true.classifier.add_module('add_linear', nn.Linear(1000, 10))
# 若是对VGG16做修改
vgg16_false.classifier[6] = nn.Linear(4096, 10)
# 模型保存方式1
# vgg16是模型的名称
# 第二个参数是保存的名称
# 保存的是模型的机构和参数
torch.save(vgg16, "vgg16_method1.pth")
# 进行模型的读取
model = torch.load('vgg16_method1.pth')
print(modefl)
# 模型的保存方式二
# 只是保存网络的参数,第一个是网络要保存的参数
# 第二个参数是保存的网络参数的路径名称
torch.save(vgg16.state_dict(), "vgg16_method2.pth")
# 模型的读取
model = torch.load('vgg16_method2.pth')
print(model)
# 因为读取的不是网络,需要把读取到的网络参数放到网络中,因此需要先导入网络架构
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dic(model)
# 若是自定义的网络
# 需要Net()网络类可以被访问到
cnnNet = Net()
torch.save(cnnNet,'cnnNet_method1.pth')
model = torch.load('cnnNet_method1.pth')
# 准备数据集,建立数据集类
train_data = torchvision.datasets.CIFAR10(root="../data", train=True, transform=torchvision.transforms.ToTensor(),
download=True)
# 建立测试集
test_data = torchvision.datasets.CIFAR10(root="../data", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
# 利用Dataloader进行导入 ,同时指定batch_size的大小
train_dataloader = DataLoader(train_data, batch_size=64)
# 网络类实体化
# 网络模型可以定义在一个文件中
cnnNet = Net()
# 损失函数定义
loss_fn = nn.CrossEntropyLoss()
# 优化器定义
optim = torch.optim.SGD(tudui.parameters(), lr=learning_rate)
# 指定训练的轮数
epoch = 10
# 添加tensorboard
writer = SummaryWriter("logs")
#开始进行训练步骤
for i in range(epoch):
# 获得损失
data = data
label = label
output = cnnNet(data)
loss = loss_fn(output,label)
# 利用优化器对损失进行处理
optim.zeros_grad()
loss.backward()
optim.step()
# 开始进行测试步骤
with torch.no_grad():
for data in testData:
output = cnnNet(data)
loss = loss_fn(output,label)
total_loss = total_loss+loss.item()