tnblog
首页
视频
资源
登录

Pytorch 基于经典网络架构训练图像分类模型

2284人阅读 2023/12/27 22:39 总访问:3467429 评论:0 收藏:0 手机
分类: pytorch

Pytorch 基于经典网络架构训练图像分类模型

数据预处理部分:


数据增强:torchvision中transforms模块自带功能,比较实用
数据预处理:torchvision中transforms也帮我们实现好了,直接调用即可
DataLoader模块直接读取batch数据

网络模块设置:


加载预训练模型,torchvision中有很多经典网络架构,调用起来十分方便,并且可以用人家训练好的权重参数来继续训练,也就是所谓的迁移学习。
需要注意的是别人训练好的任务跟咱们的可不是完全一样,需要把最后的head层改一改,一般也就是最后的全连接层,改成咱们自己的任务
训练时可以全部重头训练,也可以只训练最后咱们任务的层,因为前几层都是做特征提取的,本质任务目标是一致的

网络模型保存与测试


模型保存的时候可以带有选择性,例如在验证集中如果当前效果好则保存
读取模型进行实际测试

  1. import os
  2. import matplotlib.pyplot as plt
  3. %matplotlib inline
  4. import numpy as np
  5. import torch
  6. from torch import nn
  7. import torch.optim as optim
  8. import torchvision
  9. #pip install torchvision
  10. from torchvision import transforms, models, datasets
  11. #https://pytorch.org/docs/stable/torchvision/index.html
  12. import imageio
  13. import time
  14. import warnings
  15. import random
  16. import sys
  17. import copy
  18. import json
  19. from PIL import Image

数据读取与预处理操作


相关数据集请点击这里下载,创建相关路径。

  1. data_dir = './flower_data/'
  2. train_dir = data_dir + '/train'
  3. valid_dir = data_dir + '/valid'

制作数据源


data_transforms中指定了所有图像预处理操作
ImageFolder假设所有的文件按文件夹保存好,每个文件夹下面存贮同一类别的图片,文件夹的名字为分类的名字。
压缩的图片大小越小,卷积得越小。

数据增强


通过对原始图片数据随机旋转、裁剪、缩放…等增加图片数据的识别度。
定义训练集和验证集,并对其进行数据增强。

  1. data_transforms = {
  2. 'train': transforms.Compose([
  3. transforms.Resize([96,96]), # 压缩成96*96的图片
  4. transforms.RandomRotation(45),#随机旋转,-4545度之间随机选
  5. transforms.CenterCrop(64),#从中心开始裁剪 64
  6. transforms.RandomHorizontalFlip(p=0.5),#随机水平翻转 选择一个概率概率
  7. transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转
  8. transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
  9. transforms.RandomGrayscale(p=0.025),#概率转换成灰度率,3通道就是R=G=B
  10. transforms.ToTensor(),
  11. transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#均值,标准差
  12. ]),
  13. 'valid': transforms.Compose([
  14. transforms.Resize([96,96]),
  15. transforms.CenterCrop(64),
  16. transforms.ToTensor(),
  17. transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
  18. ]),
  19. }


创建图片数据集,图片加载器和图片数量。

注意我的图片目录结构很特殊,长这样。

  1. batch_size = 8
  2. image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'valid']}
  3. dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True) for x in ['train', 'valid']}
  4. dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'valid']}
  5. class_names = image_datasets['train'].classes
  1. image_datasets

  1. dataloaders

  1. dataset_sizes

{‘train’: 6552, ‘valid’: 818}

读取标签对应的实际名字


这里的有一个cat_to_name.json文件用于标签每个图片文件夹对应的类型名称,我们可以通过如下代码查看一下:

  1. with open('cat_to_name.json', 'r') as f:
  2. cat_to_name = json.load(f)
  1. cat_to_name

展示下数据

注意:tensor的数据需要转换成numpy的格式,而且还需要还原回标准化的结果

  1. dataloaders['valid']

<torch.utils.data.dataloader.DataLoader at 0x7c6979aef310>

  1. def im_convert(tensor):
  2. """
  3. 张量转换为可视化图像。
  4. 参数:
  5. tensor (torch.Tensor): 一个PyTorch张量,通常是一个图像的表示。
  6. 返回:
  7. numpy.ndarray: 转换后的图像,适用于显示。
  8. """
  9. # 使用CPU,克隆一个图片副本,确保原始张量不受影响
  10. image = tensor.to("cpu").clone().detach()
  11. # 将张量转换为NumPy数组。此步骤去除了任何额外的维度(如批处理大小)
  12. image = image.numpy().squeeze()
  13. # 转换颜色通道的顺序。PyTorch中的张量通常是[通道, 高度, 宽度],
  14. # 而标准图像格式是[高度, 宽度, 通道]。
  15. image = image.transpose(1, 2, 0)
  16. # 对图像进行去标准化。这里假定图像最初是标准化的,即按通道减去均值并除以标准差。
  17. # 这里的操作是标准化的逆过程:先乘以标准差,再加上均值。
  18. image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))
  19. # 将图像的像素值剪切到[0, 1]范围内,以确保适合显示。
  20. image = image.clip(0, 1)
  21. return image
  1. # 创建一个图形窗口,设定大小为20x12英寸
  2. fig = plt.figure(figsize=(20, 12))
  3. # 定义列数和行数
  4. columns = 4
  5. rows = 2
  6. # 从数据加载器中获取一批数据。这里假设'dataloaders'是一个字典,包含了不同数据集(如训练集、验证集等)的DataLoader。
  7. dataiter = iter(dataloaders['valid'])
  8. inputs, classes = next(dataiter)
  9. # 循环遍历要显示的图像数量(由列数和行数决定)
  10. for idx in range(columns * rows):
  11. # 为每张图像创建一个子图。'rows, columns, idx+1'指定了子图的位置。
  12. ax = fig.add_subplot(rows, columns, idx + 1, xticks=[], yticks=[])
  13. # 设置子图的标题。这里假设'cat_to_name'是一个将类别索引映射到其名称的字典,'class_names'是一个包含类别名的列表。
  14. ax.set_title(cat_to_name[str(int(class_names[classes[idx]]))])
  15. # 使用之前定义的'im_convert'函数将PyTorch张量转换为图像,并显示图像。
  16. plt.imshow(im_convert(inputs[idx]))
  17. # 显示整个图表
  18. plt.show()

选择与加载模型


加载models中提供的模型,并且直接用训练的好权重当做初始化参数。
第一次执行需要下载,可能会比较慢,我会提供给大家一份下载好的,可以直接放到相应路径。

  1. model_name = 'resnet' #可选的比较多 ['resnet', 'alexnet', 'vgg', 'squeezenet', 'densenet', 'inception']
  2. #是否用人家训练好的特征来做
  3. feature_extract = True


判断是否使用GPU进行训练模型,如果没有还是使用cpu进行跑模型。

  1. # 是否用GPU训练
  2. train_on_gpu = torch.cuda.is_available()
  3. if not train_on_gpu:
  4. print('CUDA is not available. Training on CPU ...')
  5. else:
  6. print('CUDA is available! Training on GPU ...')
  7. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

CUDA is available! Training on GPU …


定义模型中设置参数并取消梯度的方法。

  1. # 设置一些参数的梯度不再更新
  2. def set_parameter_requires_grad(model, feature_extracting):
  3. if feature_extracting:
  4. for param in model.parameters():
  5. # 让所有参数的梯度都不再更新
  6. param.requires_grad = False
  1. model_ft = models.resnet18()
  2. model_ft

参考pytorch官网例子


这是初始化模型的创建的方法,有不同模型可以进行初始化。
这里定义时除了对模型的创建,还做了取消已经训练好的模型梯度下降,并对最后一层进行了更改。

  1. def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True):
  2. # 选择合适的模型,不同模型的初始化方法稍微有点区别
  3. model_ft = None
  4. input_size = 0
  5. if model_name == "resnet":
  6. """ Resnet18
  7. """
  8. model_ft = models.resnet18(pretrained=use_pretrained)
  9. # 设置模型的梯度下降不进行更新
  10. set_parameter_requires_grad(model_ft, feature_extract)
  11. # 找到fc层进行更改
  12. num_ftrs = model_ft.fc.in_features
  13. model_ft.fc = nn.Sequential(nn.Linear(num_ftrs, 102),
  14. nn.LogSoftmax(dim=1))
  15. input_size = 64
  16. elif model_name == "alexnet":
  17. """ Alexnet
  18. """
  19. model_ft = models.alexnet(pretrained=use_pretrained)
  20. set_parameter_requires_grad(model_ft, feature_extract)
  21. num_ftrs = model_ft.classifier[6].in_features
  22. model_ft.classifier[6] = nn.Linear(num_ftrs,num_classes)
  23. input_size = 224
  24. elif model_name == "vgg":
  25. """ VGG11_bn
  26. """
  27. model_ft = models.vgg16(pretrained=use_pretrained)
  28. set_parameter_requires_grad(model_ft, feature_extract)
  29. num_ftrs = model_ft.classifier[6].in_features
  30. model_ft.classifier[6] = nn.Linear(num_ftrs,num_classes)
  31. input_size = 224
  32. elif model_name == "squeezenet":
  33. """ Squeezenet
  34. """
  35. model_ft = models.squeezenet1_0(pretrained=use_pretrained)
  36. set_parameter_requires_grad(model_ft, feature_extract)
  37. model_ft.classifier[1] = nn.Conv2d(512, num_classes, kernel_size=(1,1), stride=(1,1))
  38. model_ft.num_classes = num_classes
  39. input_size = 224
  40. elif model_name == "densenet":
  41. """ Densenet
  42. """
  43. model_ft = models.densenet121(pretrained=use_pretrained)
  44. set_parameter_requires_grad(model_ft, feature_extract)
  45. num_ftrs = model_ft.classifier.in_features
  46. model_ft.classifier = nn.Linear(num_ftrs, num_classes)
  47. input_size = 224
  48. elif model_name == "inception":
  49. """ Inception v3
  50. Be careful, expects (299,299) sized images and has auxiliary output
  51. """
  52. model_ft = models.inception_v3(pretrained=use_pretrained)
  53. set_parameter_requires_grad(model_ft, feature_extract)
  54. # Handle the auxilary net
  55. num_ftrs = model_ft.AuxLogits.fc.in_features
  56. model_ft.AuxLogits.fc = nn.Linear(num_ftrs, num_classes)
  57. # Handle the primary net
  58. num_ftrs = model_ft.fc.in_features
  59. model_ft.fc = nn.Linear(num_ftrs,num_classes)
  60. input_size = 299
  61. else:
  62. print("Invalid model name, exiting...")
  63. exit()
  64. return model_ft, input_size

?设置哪些层需要训练


初始化模型,并使用GPU进行模型的训练,定义训练时保存的文件路径以防数据丢失,最后打印一下需要梯度下降的层。
也就是我们修改的最后一层。

  1. model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
  2. #GPU计算
  3. model_ft = model_ft.to(device)
  4. #?模型保存
  5. filename='checkpoint.pth'
  6. # 是否训练所有层
  7. params_to_update = model_ft.parameters()
  8. print("Params to learn:")
  9. if feature_extract:
  10. params_to_update = []
  11. for name,param in model_ft.named_parameters():
  12. if param.requires_grad == True:
  13. params_to_update.append(param)
  14. print("\t",name)
  15. else:
  16. for name,param in model_ft.named_parameters():
  17. if param.requires_grad == True:
  18. print("\t",name)

  1. model_ft

?优化器设置


创建Adam优化器,1e-2学习率0.01,学习率每7个epoch会减少到原来的1/10,最后定义一个NLLLoss()损失函数。

  1. # 优化器设置
  2. optimizer_ft = optim.Adam(params_to_update, lr=1e-2)
  3. scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)#学习率每7epoch衰减成原来的1/10
  4. #最后一层已经LogSoftmax()了,所以不能nn.CrossEntropyLoss()来计算了,nn.CrossEntropyLoss()相当于logSoftmax()和nn.NLLLoss()整合
  5. # 添加损失函数
  6. criterion = nn.NLLLoss()

训练模块

  1. def train_model(model, dataloaders, criterion, optimizer, num_epochs=25, is_inception=False,filename=filename):
  2. since = time.time()
  3. best_acc = 0
  4. """
  5. checkpoint = torch.load(filename)
  6. best_acc = checkpoint['best_acc']
  7. model.load_state_dict(checkpoint['state_dict'])
  8. optimizer.load_state_dict(checkpoint['optimizer'])
  9. model.class_to_idx = checkpoint['mapping']
  10. """
  11. model.to(device)
  12. # 初始化用于记录训练过程中的准确度历史、损失历史和学习率的列表。
  13. val_acc_history = [] # 用于记录每个epoch后在验证集上的准确率
  14. train_acc_history = [] # 用于记录每个epoch后在训练集上的准确率
  15. train_losses = [] # 用于记录每个epoch的训练损失
  16. valid_losses = [] # 用于记录每个epoch的验证损失
  17. LRs = [optimizer.param_groups[0]['lr']] # 记录初始学习率
  18. # 复制模型的初始权重。在训练过程中,如果发现更好的模型,将用这个变量来保存那个模型的状态。
  19. best_model_wts = copy.deepcopy(model.state_dict())
  20. for epoch in range(num_epochs):
  21. print('Epoch {}/{}'.format(epoch, num_epochs - 1))
  22. print('-' * 10)
  23. # 训练和验证
  24. for phase in ['train', 'valid']:
  25. if phase == 'train':
  26. model.train() # 训练
  27. else:
  28. model.eval() # 验证
  29. # 初始化累计损失和正确预测数
  30. running_loss = 0.0
  31. running_corrects = 0
  32. # 把数据都取个遍
  33. for inputs, labels in dataloaders[phase]:
  34. inputs = inputs.to(device)
  35. labels = labels.to(device)
  36. # 清零
  37. optimizer.zero_grad()
  38. # 只有训练的时候计算和更新梯度
  39. with torch.set_grad_enabled(phase == 'train'):
  40. if is_inception and phase == 'train':
  41. # 对Inception模型的特殊处理
  42. outputs, aux_outputs = model(inputs)
  43. loss1 = criterion(outputs, labels)
  44. loss2 = criterion(aux_outputs, labels)
  45. loss = loss1 + 0.4*loss2
  46. else:#resnet执行的是这里
  47. # 计算输出和损失
  48. outputs = model(inputs)
  49. loss = criterion(outputs, labels)
  50. _, preds = torch.max(outputs, 1)
  51. # 在训练阶段进行反向传播和优化
  52. if phase == 'train':
  53. loss.backward()
  54. optimizer.step()
  55. # 计算损失累计当前批次的损失和正确预测数
  56. running_loss += loss.item() * inputs.size(0)
  57. running_corrects += torch.sum(preds == labels.data)
  58. # 计算该阶段的平均损失和准确率
  59. epoch_loss = running_loss / len(dataloaders[phase].dataset)
  60. epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
  61. time_elapsed = time.time() - since
  62. print('Time elapsed {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
  63. print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
  64. # 如果是验证阶段,保存最佳模型和更新历史数据
  65. if phase == 'valid' and epoch_acc > best_acc:
  66. best_acc = epoch_acc
  67. best_model_wts = copy.deepcopy(model.state_dict())
  68. state = {
  69. 'state_dict': model.state_dict(),
  70. 'best_acc': best_acc,
  71. 'optimizer' : optimizer.state_dict(),
  72. }
  73. torch.save(state, filename)
  74. if phase == 'valid':
  75. val_acc_history.append(epoch_acc)
  76. valid_losses.append(epoch_loss)
  77. scheduler.step(epoch_loss)
  78. if phase == 'train':
  79. train_acc_history.append(epoch_acc)
  80. train_losses.append(epoch_loss)
  81. # 更新学习率历史
  82. print('Optimizer learning rate : {:.7f}'.format(optimizer.param_groups[0]['lr']))
  83. LRs.append(optimizer.param_groups[0]['lr'])
  84. print()
  85. # 输出总的训练时间和最佳验证准确率
  86. time_elapsed = time.time() - since
  87. print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
  88. print('Best val Acc: {:4f}'.format(best_acc))
  89. # 训练完后用最好的一次当做模型最终的结果
  90. # 加载最佳模型权重
  91. model.load_state_dict(best_model_wts)
  92. # 返回训练后的模型和历史数据
  93. return model, val_acc_history, train_acc_history, valid_losses, train_losses, LRs

开始训练!

  1. model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs = train_model(model_ft, dataloaders, criterion, optimizer_ft, num_epochs=20, is_inception=(model_name=="inception"))


在到13次expose时,验证集的损失达到了0.3191,已经很低了。

再继续训练所有层

  1. # 开启所有层的梯度下降
  2. for param in model_ft.parameters():
  3. param.requires_grad = True
  4. # 再继续训练所有的参数,学习率调小一点
  5. optimizer = optim.Adam(params_to_update, lr=1e-4)
  6. scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
  7. # 损失函数
  8. criterion = nn.NLLLoss()
  1. # Load the checkpoint
  2. checkpoint = torch.load(filename)
  3. best_acc = checkpoint['best_acc']
  4. model_ft.load_state_dict(checkpoint['state_dict'])
  5. optimizer.load_state_dict(checkpoint['optimizer'])
  6. #model_ft.class_to_idx = checkpoint['mapping']
  1. model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs = train_model(model_ft, dataloaders, criterion, optimizer, num_epochs=10, is_inception=(model_name=="inception"))

测试网络效果


输入一张测试图像,看看网络的返回结果:

  1. probs, classes = predict(image_path, model)
  2. print(probs)
  3. print(classes)
  4. > [ 0.01558163 0.01541934 0.01452626 0.01443549 0.01407339]
  5. > ['70', '3', '45', '62', '55']


注意预处理方法需相同

加载训练好的模型

  1. model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
  2. # GPU模式
  3. model_ft = model_ft.to(device)
  4. #?保存文件的名字
  5. filename='seriouscheckpoint.pth'
  6. # 加载模型
  7. checkpoint = torch.load(filename)
  8. best_acc = checkpoint['best_acc']
  9. model_ft.load_state_dict(checkpoint['state_dict'])

测试数据预处理


测试数据处理方法需要跟训练时一直才可以
crop操作的目的是保证输入的大小是一致的
标准化操作也是必须的,用跟训练数据相同的mean和std,但是需要注意一点训练数据是在0-1上进行标准化,所以测试数据也需要先归一化
最后一点,PyTorch中颜色通道是第一个维度,跟很多工具包都不一样,需要转换

  1. def process_image(image_path):
  2. # 读取测试数据
  3. img = Image.open(image_path)
  4. # Resize,thumbnail方法只能进行缩小,所以进行了判断
  5. if img.size[0] > img.size[1]:
  6. img.thumbnail((10000, 256))
  7. else:
  8. img.thumbnail((256, 10000))
  9. # Crop操作
  10. left_margin = (img.width-224)/2
  11. bottom_margin = (img.height-224)/2
  12. right_margin = left_margin + 224
  13. top_margin = bottom_margin + 224
  14. img = img.crop((left_margin, bottom_margin, right_margin,
  15. top_margin))
  16. # 相同的预处理方法
  17. img = np.array(img)/255
  18. mean = np.array([0.485, 0.456, 0.406]) #provided mean
  19. std = np.array([0.229, 0.224, 0.225]) #provided std
  20. img = (img - mean)/std
  21. # 注意颜色通道应该放在第一个位置
  22. img = img.transpose((2, 0, 1))
  23. return img
  1. def imshow(image, ax=None, title=None):
  2. """展示数据"""
  3. if ax is None:
  4. fig, ax = plt.subplots()
  5. # 颜色通道还原
  6. image = np.array(image).transpose((1, 2, 0))
  7. # 预处理还原
  8. mean = np.array([0.485, 0.456, 0.406])
  9. std = np.array([0.229, 0.224, 0.225])
  10. image = std * image + mean
  11. image = np.clip(image, 0, 1)
  12. ax.imshow(image)
  13. ax.set_title(title)
  14. return ax
  1. image_path = 'image_06621.jpg'
  2. img = process_image(image_path)
  3. imshow(img)

  1. img.shape

(3, 224, 224)

  1. # 得到一个batch的测试数据
  2. dataiter = iter(dataloaders['valid'])
  3. images, labels = next(dataiter)
  4. model_ft.eval()
  5. if train_on_gpu:
  6. output = model_ft(images.cuda())
  7. else:
  8. output = model_ft(images)


output表示对一个batch中每一个数据得到其属于各个类别的可能性

  1. output.shape

torch.Size([8, 102])

得到概率最大的那个

  1. _, preds_tensor = torch.max(output, 1)
  2. preds = np.squeeze(preds_tensor.numpy()) if not train_on_gpu else np.squeeze(preds_tensor.cpu().numpy())
  3. preds

array([87, 87, 26, 87, 87, 87, 33, 84])

展示预测结果

  1. fig=plt.figure(figsize=(20, 20))
  2. columns =4
  3. rows = 2
  4. for idx in range (columns*rows):
  5. ax = fig.add_subplot(rows, columns, idx+1, xticks=[], yticks=[])
  6. plt.imshow(im_convert(images[idx]))
  7. ax.set_title("{} ({})".format(cat_to_name[str(preds[idx])], cat_to_name[str(labels[idx].item())]),
  8. color=("green" if cat_to_name[str(preds[idx])]==cat_to_name[str(labels[idx].item())] else "red"))
  9. plt.show()


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

Pytorch 初探

Pytorch 初探[TOC] Pytorch简介PyTorch由 Facebook 的 AI 研究团队开发的一个开源的机器学习库,它提供了张量(tensor)计...

Pytorch 自动求导与简单的线性回归

Pytorch 自动求导与简单的线性回归[TOC] 环境安装安装pytorch%pip install torch torchvision torchaudio 自动计算反向...

Pytorch Tensor 常见的形式

Pytorch Tensor 常见的形式[TOC] 值 描述 scalar 0维张量 vector 1维张量 matrix 2维张量 ...

Pytorch 气温预测

Pytorch 气温预测[TOC] 准备数据集下载temps.csv数据集。# 下载包 !wget https://raw.githubusercontent.com/AiDaShi/lea...

Pytorch Mnist分类任务

Pytorch Mnist分类任务[TOC] Mnist分类任务了解目标——网络基本构建与训练方法,常用函数解析——torch.nn.functional...

Pytorch 卷积神经网络效果

Pytorch 卷积神经网络效果[TOC] 数据与在线实践数据链接: https://pan.baidu.com/s/1VkrHDZGukkF900zLncMn5g 密码: 3lom...

Pytorch 卷积神经网络效果

Pytorch 卷积神经网络效果[TOC] 数据集Dataloader制作如何自定义数据集:1.数据和标签的目录结构先搞定(得知道到哪读数据)...

Pytorch 新闻分类任务(学习笔记)

Pytorch 新闻分类任务(学习笔记)[TOC] 目录结构 models文件夹该文件夹显示搭建的网络结构。里面有TextCNN.py和TextRNN....

Pytorch Flask服务部署图片识别(学习笔记)

Pytorch Flask服务部署图片识别(学习笔记)[TOC] Flask 简介Flask是一个用Python编写的轻量级Web应用框架。它简单易用,...

Pytorch 预测产量(易化学习笔记一)

Pytorch 预测产量(易化学习笔记一)[TOC] 实验目的(二维)通过温度进行产量预测。 实验代码导入数据集import torch im...

Pytorch 曲线拟合(易化学习笔记二)

Pytorch 曲线拟合(易化学习笔记二)[TOC] 感染与天数预测import matplotlib.pyplot as plt import torch import torch....

Pytorch 识别手写数字(易化学习笔记三)

Pytorch 识别手写数字(易化学习笔记三)[TOC] 识别手写数字LeNet-5手写数字识别的非常高效的卷积神经网络。高效原因:1....

Pytorch cifar10识别普适物体(易化学习笔记四)

Pytorch cifar10识别普适物体(易化学习笔记四)[TOC] CIFAR-10简介CIFAR-10(Canadian Institute For Advanced Research...

Pytorch loguru日志收集(易化学习笔记五)

Pytorch loguru日志收集(易化学习笔记五)[TOC] loguru日志简介Loguru 是一个 Python 日志库,旨在简化日志记录的设置和...

Pytorch TensorBoard运用(易化学习笔记六)

Pytorch TensorBoard运用(易化学习笔记六)[TOC] TensorBoard简介TensorBoard是TensorFlow的可视化工具包,旨在帮助研究...
这一世以无限游戏为使命!
排名
2
文章
634
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术