2.1 pytorch官方demo(Lenet)

2023-11-08

实现一个图像分类器

pytorch官方demo
TRAINING A CLASSIFIER

PytorchDemo—LeNet 介绍

源自教学视频
Convolutions – 卷积 Subsampling – 下采样 Full connection – 全连接
LeNet 结构就是 一个卷积 一个下采样 一个卷积 一个下采样 接三个全连接层

图中显示的INPUT是一个灰度图像,只有一个维度

pytorch中的Tensor通道排列顺序是:[batch, channel, height, width]

demo的流程

  1. model.py ——定义LeNet网络模型
  2. train.py ——加载数据集并训练,训练集计算loss,测试集计算accuracy,保存训练好的网络参数
  3. predict.py——得到训练好的网络参数后,用自己找的图像进行分类测试

1. model.py

# 使用torch.nn包来构建神经网络.
import torch.nn as nn
import torch.nn.functional as F

class LeNet(nn.Module): 					# 定义一个类LeNet,继承于nn.Module这个父类
    def __init__(self):						# 初始化网络结构
        super(LeNet, self).__init__()    	# 多继承需用到super函数
        self.conv1 = nn.Conv2d(3, 16, 5)    # 定义第一个卷积层
        self.pool1 = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(16, 32, 5)
        self.pool2 = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(32*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):			 # 正向传播过程
        x = F.relu(self.conv1(x))    # input(3, 32, 32) output(16, 28, 28) N=(32-5+0)/1+1 = 28
        x = self.pool1(x)            # output(16, 14, 14)                  N=(28-2+0)/2+1 = 14
        x = F.relu(self.conv2(x))    # output(32, 10, 10)                  N=(14-5+0)/1+1 = 10
        x = self.pool2(x)            # output(32, 5, 5)                    N=(10-2+0)/2+1 = 5
        x = x.view(-1, 32*5*5)       # output(32*5*5)
        x = F.relu(self.fc1(x))      # output(120)
        x = F.relu(self.fc2(x))      # output(84)
        x = self.fc3(x)              # output(10)
        return x

1.1 卷积 Conv2d

常用的卷积(Conv2d)在pytorch中对应的函数是:

 torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')

in_channels参数代表输入特征矩阵的深度即channel,比如输入一张RGB彩色图像,那in_channels=3
out_channels参数代表卷积核的个数,使用n个卷积核输出的特征矩阵深度即channel就是n
kernel_size参数代表卷积核的尺寸,输入可以是int类型如3 代表卷积核的height=width=3,也可以是tuple类型如(3, 5)代表卷积核的height=3,width=5
stride参数代表卷积核的步距默认为1,和kernel_size一样输入可以是int类型,也可以是tuple类型
padding参数代表在输入特征矩阵四周补零的情况默认为0,同样输入可以为int型如1 代表上下方向各补一行0元素,左右方向各补一列0像素(即补一圈0),如果输入为tuple型如(2, 1) 代表在上方补两行下方补两行,左边补一列,右边补一列。padding[0]是在H高度方向两侧填充的,padding[1]是在W宽度方向两侧填充的
bias参数表示是否使用偏置(默认使用)
dilation、groups是高阶用法这里不做讲解,如有需要可以参看官方文档

1.2 池化 MaxPool2d

最大池化(MaxPool2d)在 pytorch 中对应的函数是:

MaxPool2d(kernel_size, stride)

1.3 Tensor的展平:view()

在经过第二个池化层后,数据还是一个三维的Tensor (32, 5, 5),需要先经过展平后(3255)再传到全连接层:

 x = self.pool2(x)            # output(32, 5, 5)
  x = x.view(-1, 32*5*5)       # output(32*5*5)
  x = F.relu(self.fc1(x))      # output(120)

1.4 全连接 Linear

全连接( Linear)在 pytorch 中对应的函数是:

Linear(in_features, out_features, bias=True)

在卷积操作过程中,我们知道矩阵经卷积操作后的尺寸由以下几个因数决定:

输入图片大小 W×W
Filter大小 F×F
步长 S
padding的像素数 P
经卷积后的矩阵尺寸大小计算公式为:

  N = (W − F + 2P ) / S + 1

本Demo中分析
input(in_channels,w,w)
Conv2d(in_channels, out_channels,kernel_size,stride=1,padding=0)
output(out_channels, N,N)

若是输入图片为input(3, 32,32)
经过conv1=nn.Conv2d(3, 16, 5)卷积后 矩阵的大小为N=(32-5+0)/1+1=28
output(16, 28,28)
经过下采样层pool1 = nn.MaxPool2d(2, 2)池化后 矩阵的大小为
N=(28-2+0)/2+1=14
output(16,14,14)
源自Fun'

2. train.py

2.1 导入数据集

import torch
import torchvision
import torch.nn as nn
from model import LeNet
import torch.optim as optim
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import time

数据预处理

ToTensor
对输入的图像数据做预处理,即由shape (H x W x C) in the range [0, 255] → shape (C x H x W) in the range [0.0, 1.0]
Normalize
使用均值和标志差标志化Tensor

transform = transforms.Compose(
        [transforms.ToTensor(),          # convert a PLT image or numpy.ndarray(H*W*C)in range(0,255) to (C*H*W) in range(0.0,1.0)
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  # 使用均值和标志差进行标准化 output[channel]=(input[channel]-mean[chan])/std[chan]

数据集介绍

利用torchvision.datasets函数可以在线导入pytorch中的数据集,包含一些常见的数据集如MNIST等
源自Fun‘

此demo用的是CIFAR10数据集,也是一个很经典的图像分类数据集,由 Hinton 的学生 Alex Krizhevsky 和 Ilya Sutskever 整理的一个用于识别普适物体的小型数据集,一共包含 10 个类别的 RGB 彩色图片。
在这里插入图片描述


导入、加载 训练集

train_set = torchvision.datasets.CIFAR10(root='./data', train=True,
                                             download=False, transform=transform)

root=‘./data’ 将数据集下载到root后的地址,在当前目录的data文件夹下
train=True 将会导入CEFAR10的训练集样本
download=True 将会自动下载数据集 下载完后手动调为False
transform=transform 即对数据集进行预处理

# 加载训练集,实际过程需要分批次(batch)训练                                        
train_loader = torch.utils.data.DataLoader(train_set, 	  # 导入的训练集
										   batch_size=50, # 每批训练的样本数
                                          shuffle=False,  # 是否打乱训练集
                                          num_workers=0)  # 使用线程数,在windows下设置为0

导入、加载 测试集

# 导入10000张测试图片
test_set = torchvision.datasets.CIFAR10(root='./data', 
										train=False,	# 表示是数据集中的测试集
                                        download=False,transform=transform)
# 加载测试集

```python
# 导入10000张测试图片
test_set = torchvision.datasets.CIFAR10(root='./data', 
										train=False,	# 表示是数据集中的测试集
                                        download=False,transform=transform)
# 加载测试集
test_loader = torch.utils.data.DataLoader(test_set, 
										  batch_size=10000, # 每批用于验证的样本数
										  shuffle=False, num_workers=0)
# 获取测试集中的图像和标签,用于accuracy计算
test_data_iter = iter(test_loader)                  #将加载的测试集转换成可迭代的迭代器
test_image, test_label = test_data_iter.next()     #next()可获得一批数据的图像和标签值


数据集的分类(此处在工程中不需要)

# classes = ('plane', 'car', 'bird', 'cat',
    #            'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

展示一些测试集图片 (此处在工程中不需要)

import matplotlib.pyplot as plt
import numpy as np

# functions to show an image
def imshow(img):
    img = img / 2 + 0.5     # unnormalize 反标准化
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))  #Tensor通道排序是[channel,height,width] 此处将标准化后的shape (C x H x W)转换成输入图像形式的(H x W x C)
    plt.show()


# get some random training images
dataiter = iter(test_loader)
test_image, test_label = dataiter.next()

# print labels
print(' '.join(f'{classes[test_label[j]]:5s}' for j in range(batch_size)))
# show images
imshow(torchvision.utils.make_grid(test_image))

2.2 训练过程

名词 定义
epoch 对训练集的全部数据进行一次完整的训练,称为 一次 epoch
batch 由于硬件算力有限,实际训练时将训练集分成多个批次训练,每批数据的大小为 batch_size
iteration 或 step 对一个batch的数据训练的过程称为 一个 iteration 或 step
以本demo为例,训练集一共有50000个样本,batch_size=50,那么完整的训练一次样本:iteration或step=1000,epoch=1

net = LeNet()						  				# 定义训练的网络模型
loss_function = nn.CrossEntropyLoss() 				# 定义损失函数为交叉熵损失函数 
optimizer = optim.Adam(net.parameters(), lr=0.001)  # 定义优化器(训练参数,学习率)

for epoch in range(5):  # 一个epoch即对整个训练集进行一次训练  此处训练5次
    running_loss = 0.0   # 累加的损失值
    # time_start = time.perf_counter() 
    
    for step, data in enumerate(train_loader, start=0):   # 遍历训练集,返回训练集的data和步数,step从0开始计算
        inputs, labels = data 	# 获取训练集的图像和标签
        optimizer.zero_grad()   # 清除历史损失梯度 如果,就会对计算的历史梯度进行累加(通过这个特性,能够实现一个很大batch的训练)
        
        # forward + backward + optimize
        outputs = net(inputs)  				  # 正向传播  输入图像传入网络模型得到输出(预测)图像
        loss = loss_function(outputs, labels) # 计算损失   outputs预测的值  labels标签值 两者之间的损失
        loss.backward() 					  # 反向传播
        optimizer.step() 					  # 优化器更新参数

        # 打印耗时、损失、准确率等数据
        running_loss += loss.item()
        if step % 500 == 499:    # print every 1000 mini-batches,每500步打印一次
            with torch.no_grad(): # 在以下步骤中(验证过程中)不用计算每个节点的损失梯度,防止内存占用
                outputs = net(test_image) 				 # 测试集传入网络(test_batch_size=10000),output维度为[10000,10]  [batch,channel]
                predict_y = torch.max(outputs, dim=1)[1] # 以output中值最大位置对应的索引(标签)作为预测输出     寻找预测值最大可能的标签是10个中的哪个 dim=1对应channel [1]代表索引
                accuracy = (predict_y == test_label).sum().item() / test_label.size(0) # (predict_y == test_label)预测值和标签值相同为1,不同为0  .sum进行求和  前面的为Tensor形式  .item得到数值
                print('[%d, %5d] train_loss: %.3f  test_accuracy: %.3f' %  # 打印epoch,step,loss,accuracy
                      (epoch + 1, step + 1, running_loss / 500, accuracy))
                
                print('%f s' % (time.perf_counter() - time_start))        # 打印耗时
                running_loss = 0.0

print('Finished Training')

# 保存训练得到的参数
save_path = './Lenet.pth'
torch.save(net.state_dict(), save_path)

2.3 使用GPU/CPU训练

使用下面语句可以在有GPU时使用GPU,无GPU时使用CPU进行训练

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

也可以直接指定

device = torch.device("cuda")
# 或者
# device = torch.device("cpu")

对应的,需要用to()函数来将Tensor在CPU和GPU之间相互移动,分配到指定的device中计算

net = LeNet()
net.to(device) # 将网络分配到指定的device中
loss_function = nn.CrossEntropyLoss() 
optimizer = optim.Adam(net.parameters(), lr=0.001) 

for epoch in range(5): 

    running_loss = 0.0
    time_start = time.perf_counter()
    for step, data in enumerate(train_loader, start=0):
        inputs, labels = data
        optimizer.zero_grad()
        outputs = net(inputs.to(device))				  # 将inputs分配到指定的device中
        loss = loss_function(outputs, labels.to(device))  # 将labels分配到指定的device中
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        if step % 500 == 499:    
            with torch.no_grad(): 
                outputs = net(test_image.to(device)) # 将test_image分配到指定的device中
                predict_y = torch.max(outputs, dim=1)[1]
                accuracy = (predict_y == test_label.to(device)).sum().item() / test_label.size(0) # 将test_label分配到指定的device中

                print('[%d, %5d] train_loss: %.3f  test_accuracy: %.3f' %
                      (epoch + 1, step + 1, running_loss / 1000, accuracy))

                print('%f s' % (time.perf_counter() - time_start))
                running_loss = 0.0

print('Finished Training')

save_path = './Lenet.pth'
torch.save(net.state_dict(), save_path)

打印信息如下:(服务器暂时没了,借用的Fun’的结果)

[1,  1000] train_loss: 1.537  test_accuracy: 0.541
35.345407 s
[2,  1000] train_loss: 1.198  test_accuracy: 0.605
40.532376 s
[3,  1000] train_loss: 1.048  test_accuracy: 0.641
44.144097 s
[4,  1000] train_loss: 0.954  test_accuracy: 0.647
41.313228 s
[5,  1000] train_loss: 0.882  test_accuracy: 0.662
41.860646 s
Finished Training

3. predict.py

# 导入包
import torch
import torchvision.transforms as transforms
from PIL import Image
from model import LeNet

# 数据预处理
transform = transforms.Compose(
    [transforms.Resize((32, 32)), # 首先需resize成跟训练集图像一样的大小
     transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

# 导入要测试的图像(自己找的,不在数据集中),放在源文件目录下
im = Image.open('horse.jpg')
im = transform(im)  # [C, H, W]
im = torch.unsqueeze(im, dim=0)  # 对数据增加一个新维度,因为tensor的参数是[batch, channel, height, width] 

# 实例化网络,加载训练好的模型参数
net = LeNet()
net.load_state_dict(torch.load('Lenet.pth'))

# 预测
classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
with torch.no_grad():
    outputs = net(im)
    predict = torch.max(outputs, dim=1)[1].data.numpy()
print(classes[int(predict)])

输出即为预测的标签。
其实预测结果也可以用 softmax 表示,输出10个概率:

with torch.no_grad():
    outputs = net(im)
    predict = torch.softmax(outputs, dim=1)
print(predict)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2.1 pytorch官方demo(Lenet) 的相关文章

  • 如何使用 cython 编译扩展?

    我正在尝试从示例页面编译一个简单的 cython 扩展here http docs cython org src userguide tutorial html在我安装了 Python 2 6 64 位版本的 Windows 7 64 位计
  • 将tensorflow 2.0 BatchDataset转换为numpy数组

    我有这个代码 train images test images tf keras datasets mnist load data train dataset tf data Dataset from tensor slices train
  • 在 Pandas 中按日期获取有效合约

    我在检测 pandas DataFrame 中的活动合约方面遇到了一些困难 假设每一行都是一个协商 对于每一行 我有两列 initial date 和 end date 我想知道的是按日期划分的活跃合约数量 到目前为止我做了一个非常低效的方
  • 在Python3.6中调用C#代码

    由于完全不了解 C 编码 我希望在我的 python 代码中调用 C 函数 我知道有很多关于同一问题的问答 但由于一些奇怪的原因 我无法从示例 python 模块导入简单的 c 类库 以下是我所做的事情 C 类库设置 我使用的是 VS 20
  • 在 Numpy 中切片后确定结果数组的形状

    我很难理解在 numpy 中切片后如何确定结果数组的形状 例如 我使用以下简单代码 import numpy as np array np arange 27 reshape 3 3 3 slice1 array 1 2 1 slice2
  • Tensorflow 可变图像输入大小(自动编码器、放大......)

    Edit WARNING不建议使用不同图像大小的图像 因为张量需要具有相同的大小才能实现并行化 我一直在寻找解决方案 了解如何使用不同大小的图像作为神经网络的输入 Numpy 第一个想法是使用numpy 然而 由于每个图像的大小不同 我无法
  • python 中分割字符串以获得一个值?

    需要帮助 假设我在名为 input 的变量中有一个字符串 Sam Person name kind input split 通过执行上述操作 我得到两个具有不同字符串 Sam 和 Person 的变量 有没有办法只获取第一个值 name S
  • Python BeautifulSoup XML 解析

    我编写了一个简单的脚本来使用 BeautifulSoup 模块解析 XML 聊天日志 标准 soup prettify 工作正常 只是聊天日志中有很多绒毛 您可以在下面看到我正在使用的脚本代码和一些 XML 输入文件 Code import
  • 可以在 TensorFlow 中使用排名相关作为成本函数吗?

    我正在处理偶尔充满异常值的极其嘈杂的数据 因此我主要依靠相关性来衡量我的神经网络的准确性 是否可以明确使用诸如等级相关性 斯皮尔曼相关系数 之类的东西作为我的成本函数 到目前为止 我主要依赖 MSE 作为相关性的代理 我现在面临三个主要障碍
  • sudo pip install python-Levenshtein 失败,错误代码 1

    我正在尝试在 Linux 上安装 python Levenshtein 库 但每当我尝试通过以下方式安装它时 sudo pip install python Levenshtein 我收到此错误 命令 usr bin python c 导入
  • 如何使用 python urllib 在 HTTP/1.1 中保持活力

    现在我正在这样做 Python3 urllib url someurl headers HOST somehost Connection keep alive Accept Encoding gzip deflate opener urll
  • Python Kivy - 在本机网络浏览器中打开 url 的应用程序

    我尝试制作一个简单的应用程序 在单击 Screen One 上的按钮后 在 Kivy 中打开一个网页 我使用了这个主题 Python 在应用程序中直接显示网络浏览器 iframe https stackoverflow com questi
  • 如何在python中检索aws批处理参数值?

    流程 Dynamo DB gt Lambda gt 批处理 如果将角色 arn 插入动态数据库 它是从 lambda 事件中检索的 然后使用submit job角色 arn 的 API 被传递为 parameters role arn ar
  • 如何使用Python的super()来更新父值?

    我对继承很陌生 之前所有关于继承和 Python 的 super 函数的讨论都有点超出我的理解 我当前使用以下代码来更新父对象的值 usr bin env python test py class Master object mydata
  • 如何通过字符串匹配加速 pandas 行过滤?

    我经常需要过滤 pandas 数据框df by df df col name string value 并且我想加快行选择操作 有没有快速的方法可以做到这一点 例如 In 1 df mul df 3000 2000 3 reset inde
  • 张量流:注册 numpy bfloat16 扩展

    正如我所见 tensorflow 中有 bfloat16 的 numpy 扩展 https github com tensorflow tensorflow blob 24ffe9f729160a095a5cab8f592392018280
  • Python 3.2 中 **kwargs 和 dict 有什么区别?

    看起来Python的很多方面都只是功能的重复 除了我在 Python 中的 kwargs 和 dict 中看到的冗余之外 还有什么区别吗 参数解包存在差异 许多人使用kwargs 并通过dict作为论据之一 使用参数解包 Prepare f
  • 如何在sphinx中启用数学?

    我在用sphinx http sphinx pocoo org index html与pngmath http sphinx pocoo org ext math html module sphinx ext pngmath扩展来记录我的代
  • 如何将列表字典写入字符串而不是 CSV 文件?

    This 堆栈溢出问题 https stackoverflow com questions 37997085 how to write a dictionary of lists to a csv file将列表字典写入 CSV 文件的答案
  • 无法在 Windows 10 上构建 Detectron2

    尽管 Windows 上的 Detectron2 没有官方支持 但有很多可用的说明 我尝试按照这些说明进行操作 但最终出现了相同的错误 这是我的设置 OS Windows 10 专业版 19043 1466 微软视觉工作室 2019 CUD

随机推荐

  • Undo框架(三)

    21 5 使用外部对象管理Undo状态 在前面的示例中 我们自定义的UndoableEdit实现要负责维护可撤销对象的之前与之后状态 Swing Undo框架同时支持使用可撤销编辑实现之外的对象来管理状态的能力 当使用一个外部对象用于状态管
  • 2019第十届蓝桥杯B组省赛E题迷宫(bfs)

    试题 E 迷宫 本题总分 15 分 问题描述 下图给出了一个迷宫的平面图 其中标记为 1 的为障碍 标记为 0 的为可 以通行的地方 010000 000100 001001 110000 迷宫的入口为左上角 出口为右下角 在迷宫中 只能从
  • (2023)最新VSCode安装包(.zip版本),解压缩直接用

    1 官网地址 Download Visual Studio Code Mac Linux Windows 2 下载 zip文件 给了网盘链接 自行下载 链接 https pan baidu com s 1wl uaAw3VsbaeCIehT
  • 笔记:Linux中的管道符和重定向

    只是为了一边学习一边做笔记 欢迎交流 一 管道符 管道符就是那个竖杠 它的核心作用就是把前面命令的输出当作后边命令的输入 直接举例说明 ls etc grep v 将ls命令的输出 当作grep命令的输入 注意 管道符可以连续使用多个 二
  • MySQL----MySQL将数据从一个数据导入到另一个数据库

    原文链接 1 从源数据库到处数据 mysqldump u 用户名 p 数据库名 gt 文件名 sql 如 mysqldump u root p test gt test sql 2 将test sql文件复制到另一个数据库所在的服务器上 比
  • 【QT】【ChatGPT】具有一点点深度的问题

    QT ChatGPT 具有一点点深度的问题 程序说明 一 博客日期 二 引言 版权声明 先上简单菜 稍微复杂点 一 有哪些类是隐式的引用计数 二 请你谈一下你对C 智能指针的理解和使用方式 三 请你简述一下C 中的虚函数 四 请你谈一下对C
  • 第18课 微信小程序app.js全局属性与公共方法的使用

    第18课 微信小程序app js全局属性与公共方法的使用 通过小程序的背景api播放器案例演示 由于背景音乐播放器全局只能有一个 所以只能在全局设置这一个并调用一个 1 app js内获取背景音乐api并设置成属性 2 在utils内设置公
  • 关于Jquery的Validate插件--rules添加自定义方法(强密码验证方法)

    简介 请看菜鸟教程 根据给出的方法 自定义识别密码是否为复杂密码的方法 链接 https www runoob com jquery jquery plugin validate html Query Validate 插件为表单提供了强大
  • ERROR: No matching distribution found for Django 报错解决

    ERROR No matching distribution found for Django 报错解决 今天安装一个 python 依赖时 执行 pip install r requirements txt后 界面出现ERROR No m
  • getAction()

    event getAction 获得的返回值 触摸屏幕时刻 case MotionEvent ACTION DOWN 0 break 触摸并移动时刻 case MotionEvent ACTION MOVE 2 break 终止触摸时刻 c
  • 向Intel迁移!(上)

    转自 http www programmer com cn 14703 文 王越 2005年 苹果宣布其芯片向Intel迁移 在这背后夹杂着错综复杂的缘由 从Intel的诞生 精简指令集与复杂指令集之争到AIM与Wintel两大联盟之争 几
  • 计算机系统的组成说课,计算机系统的组成说课稿

    计算机系统的组成说课稿 一 教学内容分析 1 教学内容分析 本节是广东教育出版社出版的 信息技术 初中第一册第一章 信息处理与计算机 第二节的内容 授课为1课时 这是小学升初一新生接触信息技术这门课的第二堂课 这节课能否讲得生动易懂 涉及能
  • 函数式语言Haskell

    函数式语言Haskell 为了方便 建设在windows下安装编译器和解析器 今有2个 Hugs 和 GHC 网址如下 http cvs haskell org Hugs pages downloading htm http www has
  • 密码学之公钥密码体系(2):RSA算法

    密码学之公钥密码体系 2 RSA算法 文章目录 一 RSA算法背景 二 RSA算法描述 三 RSA的硬件实现 四 RSA的安全性 五 对RSA的选择密文攻击 一 RSA算法背景 上一讲介绍了公钥密码体系中的背包算法 在Merkle背包算法出
  • Spring自动事物管理失效情形

    声明式事物管理虽然十分方便 但是也有失效的情形 1 Transactional作用在非public方法上 Spring的事物管理只支持使用public声明的方法 即使是在同一个包或者同一个类中的方法事务管理也会失效 package com
  • Materialize时间组件datepicker汉化

    首先说明我用的是1 0版本 由于版本差异导致js调用的方法不一致 请注意
  • ubuntu20.04修改时间localtime

    根据网络上目前的一些语句设置都无法正常实现 主要原因在于 网上的办法都是基于 System clock synchronized 参数的值是 yes 但是我的该参数一直都是no 且根据网上常规办法无法实现修改时区 因此 我经过查找资料找到了
  • 安装nodejs时提示Leaving directory

    在按照标准的编译命令 configure gt make gt make install 在make的时候发生错误 deps v8 src base platform mutex h 210 error expected before co
  • 在线PDF保护解除器,完全免费,没有文件数量限制 - PDF在线解锁器

    通常一般的PDF文件我们可以使用PDF阅读器程序打开 并可以打印内容 复制文本或转换为其他格式 但是 有时你可能发现某些PDF文件虽然可以像普通PDF一样被我们查看 但却无法打印它或选择复制文本内容 这些文件是被PDF创建者加了权限保护的P
  • 2.1 pytorch官方demo(Lenet)

    实现一个图像分类器 pytorch官方demo TRAINING A CLASSIFIER PytorchDemo LeNet 介绍 Convolutions 卷积 Subsampling 下采样 Full connection 全连接 L