|

楼主 |
发表于 2023-5-25 17:09:45
|
显示全部楼层
最终代码
- #本代码实现构筑一个dataset和dataloader
- from torch.utils.data import Dataset
- import cv2
- import numpy as np
- import torch
- import torch.nn as nn
- import torch.nn.functional as F
- import torch.optim as optim
- import tensorflow as tf
- import random
- import pathlib
- from torch.utils.data import DataLoader
- BATCH_SIZE=16
- DEVICE=torch.device("cuda"if torch.cuda.is_available()else"cpu")
- EPOCHS=100
- class TensorDataset(Dataset):
- # TensorDataset继承Dataset, 重载了__init__, __getitem__, __len__
- # 实现将一组Tensor数据对封装成Tensor数据集
- # 能够通过index得到数据集的数据,能够通过len,得到数据集大小
- def __init__(self, data_tensor, target_tensor):
- self.data_tensor = data_tensor
- self.target_tensor = target_tensor
- def __getitem__(self, index):
- return self.data_tensor[index], self.target_tensor[index]
- def __len__(self):
- return self.data_tensor.size(0) # size(0) 返回当前张量维数的第一维
- def getImgPathAndName():
- data_path = pathlib.Path('./data/testphotos')
- all_image_paths = list(data_path.glob('*/*'))
- all_image_paths = [str(path) for path in all_image_paths] # 所有图片路径的列表
- random.shuffle(all_image_paths) # 打散,这个操作后顺序重新打乱
- all_images = torch.empty((0, 1, 28, 28), dtype=torch.float32)
- for image_path in all_image_paths:
- img = getDataFromImgPath(image_path)
- all_images = torch.cat([all_images, img], dim=0)
- #img = img.permute(0, 3, 1, 2)
- # 将图像channel提到前面即 [batch size, width, height, channel]-> [batch size, channel, width, height]
- label_names = sorted(item.name for item in data_path.glob('*/') if item.is_dir())
- label_to_index = dict((name, index) for index, name in enumerate(label_names))
- all_image_labels = [label_to_index[pathlib.Path(path).parent.name] for path in all_image_paths]
- all_image_labels = torch.tensor(all_image_labels) #从list转为tensor类型
- return all_images, all_image_labels
- def getDataFromImgPath(image_path):
- img = cv2.imread(image_path, 0).astype(np.uint8)
- # 第二个参数0表示灰度图
- img = cv2.resize(img, (28, 28))
- img = img / 255.
- img = torch.from_numpy(img)
- img = torch.tensor(img, dtype=torch.float32)
- img = img.unsqueeze(0) # 在第一维度上增加一个维度,作为channel大小
- img = img.unsqueeze(0) # 在第一维度上增加一个维度,作为batch size大小
- return img
- all_images, all_image_labels = getImgPathAndName()
- # 将数据封装成 Dataset (用 TensorDataset 类)
- train_dataset = TensorDataset(all_images, all_image_labels)
- train_loader=DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
- # 可使用索引调用数据
- #print('tensor_data[0]: ', tensor_dataset[0])
- # 可返回数据len
- #print('len os tensor_dataset: ', len(tensor_dataset))
- class Digit(nn.Module):
- def __init__(self):
- super().__init__()
- self.convl = nn.Conv2d(1,10,5)
- self.conv2 = nn.Conv2d(10,20,3)
- self.fcl = nn.Linear(20*10*10,500)
- self.fc2 = nn.Linear(500,10)
- def forward(self,x):
- input_size = x.size(0)#batch_size
- x = self.convl(x) #输入:batch*1*28*28,输出:batch*10*24*24(28-5+1)
- x = F.relu(x)#保持shape不变 激活层
- x = F.max_pool2d(x,2,2)#池化层 对图片进行压缩 输入:batch*10*24*24
- #输出 batch*10*12*12
- x = self.conv2(x)#输入:batch*10*12*12 输出:batch*20*(12-3+1)-(12-3+1)
- x = F.relu(x)
- #拉伸
- x = x.view(input_size,-1) #-1 自动计算维度20*10*10=2000
- #进入全连接层
- x = self.fcl(x)#输入:batch*2000 输出batch*500
- x = F.relu(x)
- x = self.fc2(x)#输入batch*500 输出:batch*10
- output=F.log_softmax(x,dim=1)#计算分类,每个数字的概率值
- return output
- #定义优化器
- model=Digit().to(DEVICE)
- optimizer = optim.Adam(model.parameters())
- #定义训练方法
- def train_model(model,device,train_loader,optimizer,epoch):
- model.train()#切换成训练模式
- for batch_index,(data,target) in enumerate(train_loader):
- data,target=data.to(device),target.to(device)#部署到device上去
- #梯度初始化为0
- optimizer.zero_grad()
- #训练后的结果
- output=model(data)
- #计算损失
- loss=F.cross_entropy(output,target)#交叉熵损失函数
- #找到概率值最大的下标
- pred = output.max(1,keepdim=True)
- #反向传播
- loss.backward()
- #参数优化
- optimizer.step()
- if batch_index%3000==0:
- print("Train Epoch : {} \t Loss:{:.6f}".format(epoch,loss.item()))
- #定义测试方法
- def test_model(model,device,imgPath):
- #模拟验证
- data = getDataFromImgPath(imgPath)
- #data = torch.tensor(imgPath)
- model.eval()
- with torch.no_grad():#不会计算梯度,也不会进行反向传播
- data=data.to(device)
- #测试数据
- output=model(data)
- #找到概率值最大的索引
- pred=output.max(1,keepdim=True)[1]#值 索引
- print('该图片判断为:' + str(pred[0][0]))
- return pred
- #调用方法
- for epoch in range(1,EPOCHS+1):
- train_model(model,DEVICE,train_loader,optimizer,epoch)
- print('当前批次'+str(epoch))
- # test_model(model,DEVICE,test_loader)
- #测试图片
- test_model(model,DEVICE,'data\\testphotos\\1\\pic1200.jpg')
复制代码 |
|