建立网络全过程

文章目录

  • 读取数据,构建数据
    • 项目1 创建自己的dataset类
        • transform 对图片进行处理
        • 修改`__getitem__`
        • 将数据集输入`DataLoader`
    • 项目2 使用自带的
        • `ImageFolder`
        • 防止样本不均衡,使用`sample`进行权重分配
  • 创建网络
  • 性能评估
        • 计算函数
        • 准确率函数
  • 训练模型
        • 训练函数
        • 验证函数
        • 保存

读取数据,构建数据

项目1 创建自己的dataset类

transform 对图片进行处理

碎片

  1. 对图片进行数据增强处理
 self.transform = transforms.Compose([transforms.Resize(size = (224,224)),#尺寸规范 #将图片设置为224*224transforms.RandomResizedCrop(200), #随机   随机长宽比裁剪transforms.ToTensor(),   #转化为tensor #那transform.Normalize()是怎么工作的呢?以上面代码为例,ToTensor()能够把灰度范围从0-255变换到0-1之间,transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),#而后面的transform.Normalize()则把0-1变换到(-1,1).具体地说,对每个通道而言,Normalize执行以下操作:image=(image-mean)/std  其中mean和std分别通过(0.5,0.5,0.5)和(0.5,0.5,0.5)进行指定。原来的0-1最小值0则变成(0-0.5)/0.5=-1,而最大值1则变成(1-0.5)/0.5=1.])

对参数进行解释

函数解释
Resize改变大小
RandomResizedCrop随便改变比例,并随机选取中心,设定大小为200v200
ToTensor图像转tensor
Normalize对图像标准化
修改__getitem__
  1. 将测试集(不带标签的数据图像)label设定为文件名(名字必须是数字)

这里对__getitem__进行重写

  def __getitem__(self, idx: int):# img to tensor and label to tensorprint(idx)img_path = self.path_list[idx]#  __getitem__给定  self和一个keyprint(img_path)if self.train_flag is True:if img_path.split('.')[0] == 'dog' : label = 1else:label = 0else:label = int(img_path.split('.')[0]) # split 的是str类型要转换为intlabel = torch.as_tensor(label, dtype=torch.int64) # 必须使用long 类型数据,否则后面训练会报错 expect longimg_path = os.path.join(self.data_path, img_path)img = Image.open(img_path).convert('RGB')img = self.transform(img)return img, label

总览

class MyDataset(Dataset):#创建自己的dataset类  ,继承dataset  def __init__(self, data_path:str, train=True, transform=None):#init初始化方案  指定path的类型是str  train默认是True  transform 默认是无self.data_path = data_path  #设定位置self.train_flag = train     #train的参数if transform is None:   self.transform = transforms.Compose([transforms.Resize(size = (224,224)),#尺寸规范 #将图片设置为224*224transforms.RandomResizedCrop(200), #随机   随机长宽比裁剪transforms.ToTensor(),   #转化为tensor #那transform.Normalize()是怎么工作的呢?以上面代码为例,ToTensor()能够把灰度范围从0-255变换到0-1之间,transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),#而后面的transform.Normalize()则把0-1变换到(-1,1).具体地说,对每个通道而言,Normalize执行以下操作:image=(image-mean)/std  其中mean和std分别通过(0.5,0.5,0.5)和(0.5,0.5,0.5)进行指定。原来的0-1最小值0则变成(0-0.5)/0.5=-1,而最大值1则变成(1-0.5)/0.5=1.])else:self.transform = transformself.path_list = os.listdir(data_path)#给出一个文件夹所有的文件def __getitem__(self, idx: int):# img to tensor and label to tensorprint(idx)img_path = self.path_list[idx]#  __getitem__给定  self和一个keyprint(img_path)if self.train_flag is True:if img_path.split('.')[0] == 'dog' : label = 1else:label = 0else:label = int(img_path.split('.')[0]) # split 的是str类型要转换为intlabel = torch.as_tensor(label, dtype=torch.int64) # 必须使用long 类型数据,否则后面训练会报错 expect longimg_path = os.path.join(self.data_path, img_path)img = Image.open(img_path).convert('RGB')img = self.transform(img)return img, labeldef __len__(self) -> int:  #没有这个指定,就没有len(class)  也就是 没有len(MyDataset)return len(self.path_list)

把测试集与训练集的文件路径输入

train_path =r'E:\machine_learning\mcm\new_net\Math-Modeling-2021-master\data\pic\big_train'
test_path = r'E:\machine_learning\mcm\new_net\Math-Modeling-2021-master\data\pic\test_N'
train_ds =MyDataset(train_path)
test_ds = MyDataset(test_path,train=False)
将数据集输入DataLoader
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=32,shuffle=True, pin_memory=True, num_workers=0)
test_loader = torch.utils.data.DataLoader(test_ds, batch_size=32,shuffle=True, pin_memory=True, num_workers=0)
#pin_memory If True, the data loader will copy tensors into CUDA pinned memory before returning them. 也就是一个数据拷贝的问题
## numworkers设置不为0 会报错 Broken pipe Error 网上说是win10上的pytorch bug

pin_memory 拷贝数据

项目2 使用自带的

ImageFolder

如果使用torch自带的数据集整理功能,那就用ImageFolder

transform = transforms.Compose([transforms.RandomResizedCrop(200),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize(mean=(.5, .5, .5),std=(.5, .5, .5))])trainData = dsets.ImageFolder(train_path, transform=transform)
testData = dsets.ImageFolder(test_path, transform=transform)
防止样本不均衡,使用sample进行权重分配

使用ImageFoldertargets获取一部分数据对应的标签:
class_sample_count表示每种种类的个数
samples_weight表示样本的权重

target = np.array(trainData.targets)
class_sample_count = np.array([len(np.where(target == t)[0]) for t in np.unique(target)])
# print(ctest_sample_count)
samples_weight = np.array([(1. / class_sample_count)[t] for t in target])
samples_weight = torch.from_numpy(samples_weight).double()
sampler = WeightedRandomSampler(samples_weight, len(samples_weight))trainLoader = DataLoader(dataset=trainData, batch_size=BATCH_SIZE, sampler=sampler)
testLoader = DataLoader(dataset=testData, batch_size=BATCH_SIZE, shuffle=False)

创建网络

import torch.nn.functional as F
class MyCNN(nn.Module):def __init__(self):super(MyCNN,self).__init__()# 这是对继承自父类的属性进行初始化,而且是用父类的初始化方法来初始化继承的属性.也就是说,子类继承了父类的所有属性和方法,self.conv1 = nn.Conv2d(3,8,kernel_size=3,stride=1,padding=1) # 按照公式计算后经过卷积层不改变尺寸 #对由多个输入平面组成的输入信号进行二维卷积  3通道 卷积产生8通道 卷积核尺寸为3v3矩阵1步长padding 填充self.pool = nn.MaxPool2d(2,2) # 2*2的池化 池化后size 减半self.conv2 = nn.Conv2d(8,16,kernel_size=3,stride=1,padding=1)self.fc1 = nn.Linear(16*56*56,256)#两个池化,所以是224/2/2=56self.fc2 = nn.Linear(256,64)self.fc3 = nn.Linear(64,2)
#         self.dp = nn.Dropout(p=0.5)def forward(self,x):
#         print("input:", x)x = self.pool(F.relu(self.conv1(x)))
#         print("first conv:", x)x = self.pool(F.relu(self.conv2(x)))
#         print("second conv:", x)x = x.view(-1, 16 * 56* 56)#将数据平整为一维的 x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))  x = self.fc3(x)  
#         x = F.log_softmax(x,dim=1) NLLLoss()才需要,交叉熵不需要return x

性能评估


criterion = nn.CrossEntropyLoss()
# criterion = nn.BCELoss()  #二分类交叉熵损失函数
# criterion = nn.BCEWithLogitsLoss() #二分类交叉熵损失函数 带log loss
# criterion = nn.MSELoss()optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
#也可以选择Adam优化方法
# optimizer = torch.optim.Adam(net.parameters(),lr=1e-2)   
计算函数
class AvgrageMeter(object):def __init__(self):self.reset()def reset(self):self.avg = 0self.sum = 0self.cnt = 0def update(self, val, n=1):self.sum += val * nself.cnt += nself.avg = self.sum / self.cnt
准确率函数

topk=(1,)这个参数设置,是在输入的时候还会收入一个数,然后在maxk=max(topk)中会比对大小,选最大的假设咱做top2准确率,那就输入个2

output.topk(maxk,1,True,True) 输入参数对应output.topk(k=maxk,dim=1,largest=True,sorted=True)
output.topk输出是值value和索引index
value, index= output.topk()
pred.eq()比对label通过索引pred,对两个张量Tensor进行逐元素的比较,若相同位置的两个元素相同,则返回True;若不同,返回False

## topk的准确率计算
def accuracy(output, label, topk=(1,)):#topk还可以再输入一个数maxk = max(topk) batch_size = label.size(0)# 获取前K的索引_, pred = output.topk(maxk, 1, True, True) #使用topk来获得前k个的索引pred = pred.t() # 进行转置# eq按照对应元素进行比较 view(1,-1) 自动转换到行为1,的形状, expand_as(pred) 扩展到pred的shape# expand_as 执行按行复制来扩展,要保证列相等correct = pred.eq(label.view(1, -1).expand_as(pred)) # 与正确标签序列形成的矩阵相比,生成True/False矩阵#     print(correct)rtn = []for k in topk:correct_k = correct[:k].contiguous().view(-1).float().sum(0) # 前k行的数据 然后平整到1维度,来计算true的总个数rtn.append(correct_k.mul_(100.0 / batch_size)) # mul_() ternsor 的乘法  正确的数目/总的数目 乘以100 变成百分比return rtn

训练模型

训练函数
def train( epoch, train_loader, device, model, criterion, optimizer,tensorboard_path):model = model.to(device)for e in range(epoch):model.train()top1 = AvgrageMeter()train_loss = 0.0train_loader = tqdm(train_loader)  #转换成tqdm类型 以方便增加日志的输出train_loader.set_description('[%s%04d/%04d %s%f]' % ('Epoch:', e + 1, epoch, 'lr:', 0.001))for i, data in enumerate(train_loader, 0):  # 0是下标起始位置默认为0inputs, labels = data[0].to(device), data[1].to(device)# 初始为0,清除上个batch的梯度信息optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs,labels)loss.backward()optimizer.step()# topk 准确率计算prec1, prec2 = accuracy(outputs, labels, topk=(1, 2))n = inputs.size(0)top1.update(prec1.item(), n)train_loss += loss.item()postfix = {'train_loss': '%.6f' % (train_loss / (i + 1)), 'train_acc': '%.6f' % top1.avg}train_loader.set_postfix(log=postfix)# ternsorboard 曲线绘制writer = SummaryWriter(tensorboard_path)writer.add_scalar('Train/Loss', loss.item(), epoch)writer.add_scalar('Train/Accuracy', top1.avg, epoch)writer.flush()print('Finished Training')
验证函数
def validate( epoch, validate_loader, device, model, criterion):val_acc = 0.0model = model.to(device)for e in range(epoch):model.eval()with torch.no_grad():  # 进行评测的时候网络不更新梯度val_top1 = AvgrageMeter()validate_loader = tqdm(validate_loader)validate_loss = 0.0for i, data in enumerate(validate_loader, 0):  # 0是下标起始位置默认为0inputs, labels = data[0].to(device), data[1].to(device)#         inputs,labels = data[0],data[1]outputs = model(inputs)loss = criterion(outputs, labels)prec1, prec2 = accuracy(outputs, labels, topk=(1, 2))n = inputs.size(0)val_top1.update(prec1.item(), n)validate_loss += loss.item()postfix = {'validate_loss': '%.6f' % (validate_loss / (i + 1)), 'validate_acc': '%.6f' % val_top1.avg}validate_loader.set_postfix(log=postfix)writer = SummaryWriter(tensorboard_tpath)writer.add_scalar('Validate/Loss', loss.item(), epoch)writer.add_scalar('Validate/Accuracy', val_top1.avg, epoch)writer.flush()val_acc = val_top1.avgreturn val_acc
保存
def submission(csv_path,test_loader, device, model):result_list = []model = model.to(device)test_loader = tqdm(test_loader)with torch.no_grad():  # 进行评测的时候网络不更新梯度for i, data in enumerate(test_loader, 0):images, labels = data[0].to(device), data[1].to(device)
#             print(images)#             print(labels)outputs = model(images)softmax_func = nn.Softmax(dim=1)  # dim=1表示行的和为1soft_output = softmax_func(outputs)predicted = soft_output[:, 1]for i in range(len(predicted)):result_list.append({"id": labels[i].item(),"label": predicted[i].item()})# 从list转成 dataframe 然后保存为csv文件columns = result_list[0].keys()result_dict = {col: [anno[col] for anno in result_list] for col in columns}result_df = pd.DataFrame(result_dict)result_df = result_df.sort_values("id")result_df.to_csv(csv_path, index=None)
# net =  MyCNN()
net =resnet18
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
criterion = nn.CrossEntropyLoss()
# criterion = nn.BCELoss()  #二分类交叉熵损失函数
# criterion = nn.BCEWithLogitsLoss() #二分类交叉熵损失函数 带log loss
# criterion = nn.MSELoss()optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
#也可以选择Adam优化方法
# optimizer = torch.optim.Adam(net.parameters(),lr=1e-2)   

# train( 1, train_loader, device,net, criterion, optimizer,tensorboard_path) # 完整的训练数据集
train( 30, new_train_loader, device,net, criterion, optimizer,tensorboard_path) # 划分80%后的训练数据集


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部