conda create -n pytorch python=3.7.0
本人是使用conda安装 cpu环境的
conda install -c https://conda.anaconda.org/menpo opencv
练习DataSet的使用,创建自己的数据集类别
学习代码为:
from torch.utils.data import Dataset
import os
from PIL import Image
# 数据集类 必须继承Dataset 实现__getitem__(获取每一个数据及其label)和__len__方法(一共有多少数据)
class MyData(Dataset):
# root_dir是训练集 label_dir是本来应该是label文件夹 但是由于这个文件夹的label就是文件夹名称 就更方便了
def __init__(self,root_dir,label_dir):
# self相当于创建类的成员变量
self.root_dir=root_dir
self.label_dir=label_dir
# 图片集合的路径
self.path=os.path.join(self.root_dir,self.label_dir)
# 存放所有图片名称的集合
self.img_path_list=os.listdir(self.path)
def __getitem__(self, idx):
img_name=self.img_path_list[idx]
img_item_path=os.path.join(self.path,img_name)
img=Image.open(img_item_path)
# 因为label就是文件夹的名字
label=self.label_dir
return img,label
def __len__(self):
return len(self.img_path_list)
root_dir="dataset/train"
ants_label_dir="ants"
bees_label_dir="bees"
ants_dataset=MyData(root_dir,ants_label_dir)
bees_dataset=MyData(root_dir,bees_label_dir)
train_dataset=ants_dataset+bees_dataset
from torch.utils.data import Dataset
from PIL import Image
import os
class MyData(Dataset):
def __init__(self,root_dir,data_dir,label_dir):
self.root_dir=root_dir
self.data_dir=data_dir
self.label_dir=label_dir
self.img_path=os.path.join(self.root_dir,self.data_dir)
self.img_path_list=os.listdir(self.img_path)
def __getitem__(self, idx):
img_name=self.img_path_list[idx]
img_item_path=os.path.join(self.img_path,img_name)
img=Image.open(img_item_path)
label_item_path = os.path.join(self.img_path, img_name)
with open(label_item_path, "r") as f:
label = f.read()
return img,label
def __len__(self):
return len(self.img_path_list)
root_dir="dataset2\\train"
ants_data_dir="ants_image"
ants_label_dir="ants_label"
bees_data_dir="bees_image"
bees_label_dir="bees_label"
ants_dataset=MyData(root_dir,ants_data_dir,ants_label_dir)
bees_dataset=MyData(root_dir,bees_data_dir,bees_label_dir)
train_dataset=ants_dataset+bees_dataset
安装 tensorboard:
pip install tensorboard
使用:
from torch.utils.tensorboard import SummaryWriter
write =SummaryWriter("logs")
for i in range(100):
# 常用参数 前三个 标题 y轴 x轴
write.add_scalar("y=x",i,i)
write.close()
打开生成的文件,当前目录下:tensorboard --logdir=logs --port=6007
这个logs就是创建SummaryWriter实例时候传入的文件名
使用:
from torch.utils.tensorboard import SummaryWriter
import cv2
import numpy as np
write =SummaryWriter("logs")
# 我们之前使用PIL.image读图片 读出来是PLT巴拉巴拉类型的 但是这里的图片要numpy型的 只能用opencv读了
img_path="dataset/train/bees/16838648_415acd9e3f.jpg"
img=cv2.imread(img_path)
# img.shape ->(512, 768, 3)分别是高度 宽度 通道 按照函数的要求 添加参数dataformats='HWC'
write.add_image("test",img,1,dataformats='HWC')
write.close()
核心作用:将一些图片进行特定的图片变换
常用类:
ToTensor 作用:Convert a
PIL Image
ornumpy.ndarray
to tensor
ToPILImage作用:Convert a tensor or an ndarray to PIL Image
Resize:Resize the input image to the given size
小案例:
import cv2
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
img_path="dataset/train/ants/0013035.jpg"
img=cv2.imread(img_path)
# 1、使用ToTensor类
to_tensor=transforms.ToTensor()
# tensor_img=to_tensor(img) 也行 因为是call
tensor_img=to_tensor.__call__(img)
# 2、tensor作用:包装了神经网络理论基础的一些参数
write = SummaryWriter("logs")
write.add_image("tensor_img",tensor_img)
write.close()
import torchvision
from torch.utils.tensorboard import SummaryWriter
dataset_transform=torchvision.transforms.Compose([
torchvision.transforms.ToTensor()
])
train_set =torchvision.datasets.CIFAR10("./dataset",train=True,transform=dataset_transform,download=True)
test_set =torchvision.datasets.CIFAR10("./dataset",train=False,transform=dataset_transform,download=True)
write=SummaryWriter("logs")
for i in range(10):
img,target = test_set[i];
write.add_image("test_set",img,i)
write.close()
常见参数:dataset是我们准备的数据集,batch_size是一次取几个数据,shuffle:每次数据顺序是否相同,num_workers:几个进程(默认值为0 多个进行在windows下可能会有问题),drop_last是否舍去最后的余数
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
test_set =torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
test_loader=DataLoader(dataset=test_set,batch_size=4,shuffle=True,num_workers=0,drop_last=False)
write=SummaryWriter("logs")
step=0
for data in test_loader:
imgs,targets = data
write.add_images("test_loader",imgs,step)
step+=1
write.close()
超级无敌简单的神经网络:
import torch
import torch.nn as nn
class MyModule(nn.Module):
def __init__(self) -> None:
super().__init__()
def forward(self, x):
return x+1
myModule=MyModule()
x=torch.tensor(1.0)
output = myModule(x)
print(output)
卷积就是卷积核在输入图像中移动,每一次卷积核覆盖的位置值和卷积核的值相乘 作为输出,如图像是55的矩阵,卷积核是33的矩阵,他们不断相乘再相加作为输出,输出完之后卷积核移动到下一个位置,继续相乘再相加作为输出
这个移动的步数就是CONV2D
中的参数stride
,一个值就是横向和纵向的步数,一个元组就是两个值分别对应横向移动和纵向移动
import torch
import torch.nn.functional as F
input=torch.tensor([
[1,2,0,3,1],
[0,1,2,3,1],
[1,2,1,0,0],
[5,2,3,1,1],
[2,1,0,1,1]
])
kernel=torch.tensor([
[1,2,1],
[0,1,0],
[2,1,0]
])
# 因为CONV2D要求输入的tensor 是4维的 而我们创建的是二维的所以需要用变换一下
# (1,1,5,5)表示一个通道、batch_size=1、数据是5*5
input=torch.reshape(input,(1,1,5,5))
kernel=torch.reshape(kernel,(1,1,3,3))
output=F.conv2d(input,kernel,stride=1)
print(output)
import torch
from torch import nn
class CNN(nn.Module):
def __init__(self) -> None:
super().__init__()
self.model = nn.Sequential(
# 目标从3通道32*32经过卷积得到32通道32*32 带入公式N=(W-F+2P)/S+1 即(32-5+2padding)/1+1=32 得padding=2
nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),
# 最大池化 得到32通道16*16
nn.MaxPool2d(2),
# 目标从32通道16*16经过卷积得到32通道16*16 带入公式N=(W-F+2P)/S+1 即(16-5+2padding)/1+1=16 得padding=2
nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),
# 最大池化 得到32通道8*8
nn.MaxPool2d(2),
# 目标从32通道8*8经过卷积得到64通道8*8 带入公式N=(W-F+2P)/S+1 即(8-5+2padding)/1+1=8 得padding=2
nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2),
# 最大池化 得到64通道4*4
nn.MaxPool2d(2),
# 展平为64*4*4的一维向量
nn.Flatten(),
# 全连接
nn.Linear(64 * 4 * 4, 64),
nn.Linear(64, 10)
)
def forward(self, x):
x=self.model(x)
return x
if __name__ == '__main__':
cnn = CNN()
# 输出是一组64张图片 三通道 尺寸是32*32
input=torch.ones((64,3,32,32))
# 返回为torch.Size([64, 10]) 即64张图片 每张图片在10个类别中的概率
output=cnn(input)
训练:
import torch.optim
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from model import CNN
# 准备数据集
train_data=torchvision.datasets.CIFAR10(root="./dataset",train=True,transform=torchvision.transforms.ToTensor(),download=True)
test_data=torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
train_loader=DataLoader(dataset=train_data,batch_size=64,shuffle=True)
test_loader=DataLoader(dataset=test_data,batch_size=64,shuffle=True)
# 搭建网络模型
cnn=CNN()
# 损失函数 选择交叉熵
loss_fun=nn.CrossEntropyLoss()
#优化器选择 随机梯度下降
learning_rate=0.01
optimizer=torch.optim.SGD(cnn.parameters(),lr=learning_rate)
# 训练网络的一些参数
total_train_step=0 # 训练的次数
total_test_step=0 # 测试的次数
epoch=10 # 训练的轮数
# 添加tensboard
writer=SummaryWriter("./logs")
for i in range(epoch):
print("第{}轮训练开始".format(i+1))
# 标志开始训练只对某些层管用
torch.train()
for data in train_loader:
imgs,targets=data
outputs=cnn(imgs)
loss=loss_fun(outputs,targets)
# 梯度清零 损失反向传播 然后优化参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step+=1
# loss是一个tensor 使用item方法得到真实的值 如 loss是tensor(5),loss.item()就是5
if total_train_step%100==0:
print("训练次数为{}时,损失为{}".format(total_train_step, loss.item()))
writer.add_scalar("train_loss",loss.item(),total_train_step)
# 测试每一轮训练之后 在测试集上的损失 因为只是测试 不需要对梯度进行调整
torch.eval() # 标志开始测试 只对某些层管用
total_test_loss=0
with torch.no_grad():
for data in test_loader:
imgs, targets = data
outputs = cnn(imgs)
loss = loss_fun(outputs, targets)
total_test_loss+=loss.item()
print("第{}轮训练结束之后 测试集上的整体损失为{}".format(i+1,total_test_loss))
total_test_step+=1
writer.add_scalar("test_loss", total_test_loss, total_test_step)
# 保存每一轮训练的模型
torch.save(cnn,"./path/cnn_{}_path".format(i))
print("模型已经保存")
writer.close()
import torch
import torchvision
from PIL import Image
from model import CNN
image = Image.open("./imgs/002.png")
image=image.convert("RGB")
transform =torchvision.transforms.Compose([
torchvision.transforms.Resize((32,32)),
torchvision.transforms.ToTensor()
])
image=transform(image)
# 这个image是3通道的32*32没有batch_size 给他加上
image=torch.reshape(image,(1,3,32,32))
cnn=torch.load("path/cnn_9_path")
cnn.eval()
with torch.no_grad():
output=cnn(image)
print(output.argmax(1))
# 输出是tensor([3]) 而第三个类别是猫 没有预测准确 害