基于深度学习的手写数字识别系统

一、实验目的

​ 1、任选实验环境及深度学习框架,实现手写数字识别系统;

​ 2、掌握所采用的深度血迹框架构建方式。

二、实验理论基础

1、MNIST数据集

​ MNIST 数据集来自美国国家标准与技术研究所, National Institute of Standards and Technology (NIST). 包含四个部分:

​ (1)Training set images:train-images-idx3-ubyte.gz(9.9MB,解压后47MB,包含60000个样本)

​ (2)Training set labels:train-labels-idx1-ubyte.gz(29KB,解压后60KB,包含60000个样本)

​ (3)Test set images:t10k-images-idx3-ubyte.gz(1.6MB,解压后7.8MB,包含10000个样本)

​ (4)Test set labels:t10k-labels-idx1-ubyte.gz(5KB,解压后10KB,包含10000个样本)

​ 训练集 (training set) 由来自 250 个不同人手写的数字构成, 其中 50% 是高中学生, 50% 来自人口普查局 (the Census Bureau) 的工作人员. 测试集(test set) 也是同样比例的手写数字数据。图片是以字节的形式进行存储, 我们需要把它们读取到 NumPy array 中, 以便训练和测试算法.

​ 可以建立一个Mnist文件夹,将下载的数据集放入此文件夹中,方便处理

2、数据集中训练集、验证集和测试集的作用

​ 使用了所有的原始数据去训练模型,得到的结果很可能是该模型最大程度地拟合了原始数据,亦即该模型是为了拟合所有原始数据而存在。当新的样本出现,再使用该模型进行预测,效果可能还不如只使用一部分数据训练的模型。因此,为了防止模型过拟合,对原始数据进行了三个数据集的划分。

​ (1)训练集:作用是用来拟合模型,通过设置分类器的参数,训练分类模型。后续结合验证集作用时,会选出同一参数的不同取值,拟合出多个分类器。手写数字识别系统中是用训练集中的images,进行检测,用labels与之对应,使得网络形成记忆。

​ (2)验证集:作用是当通过训练集训练出多个模型后,为了能找出效果最佳的模型,使用各个模型对验证集数据进行预测,并记录模型准确率。选出效果最佳的模型所对应的参数,即用来调整模型参数。

​ (3)测试集:通过训练集和验证集得出最优模型后,使用测试集进行模型预测。用来衡量该最优模型的性能和分类能力。即可以把测试集当做从来不存在的数据集,当已经确定模型参数后,使用测试集进行模型性能评价。在手写数字识别系统中是将测试集中的images输入网络,并将结果与labels比较,用于计算测试集准确率。

三、实验内容

1、 网络模型搭建;

​ 网络一共有7层,分别是《卷积层–池化层–卷积层–池化层–全连接层–全连接层–全连接层》;

​ (1)输入是一个单通道28*28大小的手写数字图片;

​ (2)定义卷积层1,输入通道为1,卷积核数为6,卷积核大小为5*5,池化层1,池化核大小为2*2;

​ (3)定义卷积层2,输入通道为6,卷积核数为16,卷积核大小为5*5,池化层2,池化核大小为2*2;

​ (4)全连接层1、2、3;

​ (5)定义前向传播顺序。

class LeNet5(nn.Module):def __init__(self):  # 初始化函数super(LeNet5,self).__init__()# 多基层一般使用superself.conv1 = nn.Conv2d(1, 6, 5)# 定义第一个卷积层,1是通道数灰度图片,6是卷积核个数,5卷积核大小self.pool1 = nn.MaxPool2d(2, 2)# 池化核大小2*2,步距也为2,池化层,只改变高和宽,深度不改变self.conv2 = nn.Conv2d(6, 16, 5)# 输入变为6,因为通过第一个卷积层有6个卷积核,输出深度为6self.pool2 = nn.MaxPool2d(2, 2)self.fc1 = nn.Linear(16*4*4, 120) # 展开成一维的,第一层120个节点,输入16*4*4个节点self.fc2 = nn.Linear(120, 84) # 输入120,设置84个节点self.fc3 = nn.Linear(84, 10) # 输出根据训练集修改def forward(self,x):x = self.pool1(F.relu(self.conv1(x))) # input(1,28,28),output1(6,24,24) output2(6,12,12)x = self.pool2(F.relu(self.conv2(x))) # input(6,12,12),output1(16,8,8) output2(16,4,4)x = x.view(-1, 16*4*4) # -1第一个维度x = F.relu(self.fc1(x)) # 全连接层1及其激活函数x = F.relu(self.fc2(x)) # 全连接层3得到输出x = self.fc3(x)return x

2、 数据集模型搭建 ;

​ 构建数据集模型是为了在之后的训练和测试中方便对数据集的调用。

​ (1)定义Dataset类型的数据集Mnist,设置三个参数root、train、transform,其中root是需要调用的数据的储存路径,利用train是否为true,判断调用的数据为训练集还是测试集。

class Mnist(Dataset):def __init__(self, root, train=True, transform=None):# 根据是否为训练集,得到文件名前缀self.file_pre = 'train' if train == True else 't10k'self.transform = transform#定义变换函数# 生成对应数据集的图片和标签文件路径self.label_path = os.path.join(root,'%s-labels-idx1-ubyte.gz' % self.file_pre)self.image_path = os.path.join(root,'%s-images-idx3-ubyte.gz' % self.file_pre)# 读取文件数据,返回图片和标签self.images, self.labels = self.__read_data__(self.image_path,self.label_path)

​ (2)定义__read_data__函数,将data以流的形式读入转化成ndarray对象,ndarray对象是用于存放同类型元素的多维数组,利用reshape函数将图片以标签文件的元素个数读取,设置大小为28*28。

    def __read_data__(self, image_path, label_path):# 数据集读取with gzip.open(label_path, 'rb') as lbpath:labels = np.frombuffer(lbpath.read(), np.uint8,offset=8)#将data以流的形式读入转化成ndarray对象,ndarray对象是用于存放同类型元素的多维数组with gzip.open(image_path, 'rb') as imgpath:images = np.frombuffer(imgpath.read(), np.uint8,offset=16).reshape(len(labels), 28, 28)#将图片以标签文件的元素个数读取,设置大小为28*28return images, labels

​ (3)利用transform函数,将numpy.ndarray类型数据转化为张量。

        # 如果需要转成 tensor,(RGB,HWC)张量, 则使用 tansformif self.transform is not None:image = self.transform(np.array(image))  # 此处需要用 np.array(image),转化为数组return image, label

3、 训练模型搭建;

​ (1)利用定义的Mnist数据集生成训练集,同时利用DataLoader函数,将训练集中的元素随机排序后,以batch_size=32大小返回。

# 生成训练集
train_set = Mnist(root=r'E:\CUDA\Dataset\Mnist',train=True,#训练集transform=transforms.Compose([#Compose方法是将多种变换组合在一起。transforms.ToTensor(),#函数接受PIL Image或numpy.ndarray,将其先由HWC转置为CHW格式transforms.Normalize((0.1037,), (0.3081,))#灰度图像,一个通道,均值和方差,标准化])
)
train_loader = DataLoader(#主要用来将自定义的数据读取接口的输出或者PyTorch已有的数据读取接口的输入按照batch size封装成Tensordataset=train_set,#输出的数据batch_size=32,shuffle=True)#将元素随机排序

​ (2)实化一个定义好的网络,并将网络放进GPU中,定义损失函数和优化器,用来训练网络模型。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")#判断能否调用GPU
print(device)
# 实例化一个网络
net = LeNet5().to(device) #将网络放进GPU
# 定义损失函数和优化器
loss_function = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),#网络参数lr=0.001,#学习率momentum=0.9#Momentum 用于加速 SGD(随机梯度下降)在某一方向上的搜索以及抑制震荡的发生。
)

​ (3)定义训练模型,设置训练10个epoch,在每个epoch中每300个batch打印一次平均损失值,,将训练好的模型保存,打印每次训练后的损失值变化曲线。

# 3 训练模型
loss_list = []#保存损失函数的值
for epoch in range(10):#训练10次running_loss = 0.0#误差清零?for batch_idx, data in enumerate(train_loader, start=0):#enumerate索引函数,start下标开始位置images, labels = data                       # 读取一个batch的数据images=images.to(device)  #将images放进GPUlabels=labels.to(device)  #将labels放进GPUoptimizer.zero_grad()                       # 梯度清零,初始化,如果不初始化,则梯度会叠加outputs = net(images)                      # 前向传播loss = loss_function(outputs, labels)       # 计算误差,label标准?loss.backward()                             # 反向传播optimizer.step()                            # 权重更新running_loss += loss.item()                 # 误差累计# 每300个batch 打印一次损失值if batch_idx % 300 == 299:#(0-299)(300-599)print('epoch:{} batch_idx:{} loss:{}'.format(epoch+1, batch_idx+1, running_loss/300))loss_list.append(running_loss/300)#将新的每个平均误差加到损失函数列表后面running_loss = 0.0                  #误差清零
print('Finished Training.')
torch.save(net.state_dict(),"Linear.pth")#保存训练模型
# 打印损失值变化曲线
import matplotlib.pyplot as plt
plt.plot(loss_list)
plt.title('traning loss')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()

​ (4)对训练好的网络进行测试,生成测试集的方法如同生成训练集的方法,记录通过网络预测正确的图片数和总图片数,将测试集中images、labels数据送入GPU中,images输入网络,将输出outputs与labels比较,得到预测正确的数目correct,输出测试集准确率。在测试集images中选取前10个数据,进行预测,并于对应labels比较。

# 测试
test_set = Mnist(#生成测试集root='E:\CUDA\Dataset\Mnist',train=False,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1037,), (0.3081,))])
)
test_loader = DataLoader(dataset=test_set,batch_size=32,shuffle=True
)
correct = 0  # 预测正确数
total = 0    # 总图片数
for data in test_loader:images, labels = dataimages=images.to(device)labels=labels.to(device)outputs = net(images)_, predict = torch.max(outputs.data, 1)#1是指按行,0是按列,-1是指最后一个维度,一般也是按行total += labels.size(0)correct += (predict == labels).sum()
print('测试集准确率 {}%'.format(100*correct // total))
#检测网络
test_output=net(images[:10])#在测试集中选择10张图片输入网络,得到结果
pred_y = torch.max(test_output, 1)[1].data#对得到的结果进行预测
print(pred_y, 'prediction numbe')#输出预测结果
print(labels[:10], 'real number')#输出真实结果

4、 验证模型搭建;

​ (1)调用训练好的网络,生成测试集,从测试集images数据中选取前10个图片输入网络,将预测结果和真实结果输出,并将这10个images数据绘制出来进行比较。

net=LeNet5()
net.load_state_dict(torch.load("Linear.pth"))#调用训练好的网络
test_set = Mnist(#生成测试集root='E:\CUDA\Dataset\Mnist',train=False,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1037,), (0.3081,))])
)
test_loader = DataLoader(dataset=test_set,batch_size=32,shuffle=True)
for data in test_loader:images, labels = data
#检测网络
test_output=net(images[:10])#在测试集中选择10张图片输入网络,得到结果
pred_y = torch.max(test_output, 1)[1].data#对得到的结果进行预测
print(pred_y, 'prediction numbe')#输出预测结果
print(labels[:10], 'real number')#输出真实结果
def plt_image(image):#定义一个函数,将需要预测的手写数字图画出来n = 10plt.figure(figsize=(10,4))for i in range(n):ax = plt.subplot(2,5,i+1)plt.imshow(images[i].reshape(28,28))plt.gray()ax.get_xaxis().set_visible(False)ax.get_yaxis().set_visible(False)plt.show()
plt_image(images)

​ (2)测试自己手动设计的手写数字

I = Image.open('7.jpg')
L = I.convert('L')#转化为二值图像
plt.imshow(L, cmap='gray')
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1037,), (0.3081,))
])
im = transform(L)  # [C, H, W]
im = torch.unsqueeze(im, dim=0)  # [N, C, H, W],扩展维度
with torch.no_grad():outputs = net(im)_, predict = torch.max(outputs.data, 1)print(predict)

四、附件

1、实验环境

​ (1)编程语言:python 3.6.12

​ (2)编程环境:spyder

​ (3)深度学习框架:pytorch 1.7.0

​ (4)系统环境:64位Windows系统

2、实验源码

(1)数据集模块data.py
import os
import numpy as np
from torch.utils.data import Dataset
import gzip
import matplotlib.pyplot as plt#绘图库class Mnist(Dataset):def __init__(self, root, train=True, transform=None):# 根据是否为训练集,得到文件名前缀self.file_pre = 'train' if train == True else 't10k'self.transform = transform#定义变换函数# 生成对应数据集的图片和标签文件路径self.label_path = os.path.join(root,'%s-labels-idx1-ubyte.gz' % self.file_pre)self.image_path = os.path.join(root,'%s-images-idx3-ubyte.gz' % self.file_pre)# 读取文件数据,返回图片和标签self.images, self.labels = self.__read_data__(self.image_path,self.label_path)def __read_data__(self, image_path, label_path):# 数据集读取with gzip.open(label_path, 'rb') as lbpath:labels = np.frombuffer(lbpath.read(), np.uint8,offset=8)#将data以流的形式读入转化成ndarray对象,ndarray对象是用于存放同类型元素的多维数组with gzip.open(image_path, 'rb') as imgpath:images = np.frombuffer(imgpath.read(), np.uint8,offset=16).reshape(len(labels), 28, 28)#将图片以标签文件的元素个数读取,设置大小为28*28return images, labelsdef __getitem__(self, index):#迭代使用?使用Minist()会调用_getitem_image, label = self.images[index], int(self.labels[index])# 如果需要转成 tensor,(RGB,HWC)张量, 则使用 tansformif self.transform is not None:image = self.transform(np.array(image))  # 此处需要用 np.array(image),转化为数组return image, labeldef __len__(self):#获取元素个数return len(self.labels)if __name__ == '__main__':# 生成实例train_set = Mnist(root=r'E:\CUDA\Dataset\Mnist',#MNIST数据集路径train=False,)# 取一组数据并展示(data, label) = train_set[0]#第一组数据plt.imshow(data.reshape(28, 28), cmap='gray')#灰色图像plt.title('label is :{}'.format(label))plt.show()
(2)网络模型模块model.py
import torch.nn as nn
import torch.nn.functional as Fclass LeNet5(nn.Module):def __init__(self):  # 初始化函数super(LeNet5,self).__init__()# 多基层一般使用superself.conv1 = nn.Conv2d(1, 6, 5)# 定义第一个卷积层,1是通道数灰度图片,6是卷积核个数,5卷积核大小self.pool1 = nn.MaxPool2d(2, 2)# 池化核大小2*2,步距也为2,池化层,只改变高和宽,深度不改变self.conv2 = nn.Conv2d(6, 16, 5)# 输入变为6,因为通过第一个卷积层有6个卷积核,输出深度为6self.pool2 = nn.MaxPool2d(2, 2)self.fc1 = nn.Linear(16*4*4, 120) # 展开成一维的,第一层120个节点,输入16*4*4个节点self.fc2 = nn.Linear(120, 84) # 输入120,设置84个节点self.fc3 = nn.Linear(84, 10) # 输出根据训练集修改def forward(self,x):x = self.pool1(F.relu(self.conv1(x))) # input(1,28,28),output1(6,24,24) output2(6,12,12)x = self.pool2(F.relu(self.conv2(x))) # input(6,12,12),output1(16,8,8) output2(16,4,4)x = x.view(-1, 16*4*4) # -1第一个维度x = F.relu(self.fc1(x)) # 全连接层1及其激活函数x = F.relu(self.fc2(x)) # 全连接层3得到输出x = self.fc3(x)return xif __name__ == '__main__':net = LeNet5()print(net)
(3)训练模块train.py
import torch
import torchvision.transforms as transforms
import torch.optim as optim#优化器
from torch.utils.data import DataLoader
from data import Mnist
from model import LeNet5# 生成训练集
train_set = Mnist(root=r'E:\CUDA\Dataset\Mnist',train=True,#训练集transform=transforms.Compose([#Compose方法是将多种变换组合在一起。transforms.ToTensor(),#函数接受PIL Image或numpy.ndarray,将其先由HWC转置为CHW格式transforms.Normalize((0.1037,), (0.3081,))#灰度图像,一个通道,均值和方差,标准化])
)
train_loader = DataLoader(#主要用来将自定义的数据读取接口的输出或者PyTorch已有的数据读取接口的输入按照batch size封装成Tensordataset=train_set,#输出的数据batch_size=32,shuffle=True#将元素随机排序
)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")#判断能否调用GPU
print(device)
# 实例化一个网络
net = LeNet5().to(device) #将网络放进GPU# 定义损失函数和优化器
loss_function = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),#网络参数lr=0.001,#学习率momentum=0.9#Momentum 用于加速 SGD(随机梯度下降)在某一方向上的搜索以及抑制震荡的发生。
)# 3 训练模型
loss_list = []#保存损失函数的值
for epoch in range(10):#训练10次running_loss = 0.0#误差清零?for batch_idx, data in enumerate(train_loader, start=0):#enumerate索引函数,start下标开始位置images, labels = data                       # 读取一个batch的数据images=images.to(device)  #将images放进GPUlabels=labels.to(device)  #将labels放进GPUoptimizer.zero_grad()                       # 梯度清零,初始化,如果不初始化,则梯度会叠加outputs = net(images)                      # 前向传播loss = loss_function(outputs, labels)       # 计算误差,label标准?loss.backward()                             # 反向传播optimizer.step()                            # 权重更新running_loss += loss.item()                 # 误差累计# 每300个batch 打印一次损失值if batch_idx % 300 == 299:#(0-299)(300-599)print('epoch:{} batch_idx:{} loss:{}'.format(epoch+1, batch_idx+1, running_loss/300))loss_list.append(running_loss/300)#将新的每个平均误差加到损失函数列表后面running_loss = 0.0                  #误差清零
print('Finished Training.')torch.save(net.state_dict(),"Linear.pth")#保存训练模型# 打印损失值变化曲线
import matplotlib.pyplot as plt
plt.plot(loss_list)
plt.title('traning loss')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()# 测试
test_set = Mnist(#生成测试集root='E:\CUDA\Dataset\Mnist',train=False,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1037,), (0.3081,))])
)
test_loader = DataLoader(dataset=test_set,batch_size=32,shuffle=True
)
correct = 0  # 预测正确数
total = 0    # 总图片数
for data in test_loader:images, labels = dataimages=images.to(device)labels=labels.to(device)outputs = net(images)_, predict = torch.max(outputs.data, 1)#1是指按行,0是按列,-1是指最后一个维度,一般也是按行total += labels.size(0)correct += (predict == labels).sum()print('测试集准确率 {}%'.format(100*correct // total))#检测网络
test_output=net(images[:10])#在测试集中选择10张图片输入网络,得到结果
pred_y = torch.max(test_output, 1)[1].data#对得到的结果进行预测
print(pred_y, 'prediction numbe')#输出预测结果
print(labels[:10], 'real number')#输出真实结果
(4)测试模块test.py
import torch
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from data import Mnist
from model import LeNet5
import matplotlib.pyplot as pltnet=LeNet5()
net.load_state_dict(torch.load("Linear.pth"))#调用训练好的网络#检测网络
test_set = Mnist(#生成测试集root='E:\CUDA\Dataset\Mnist',train=False,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1037,), (0.3081,))])
)
test_loader = DataLoader(dataset=test_set,batch_size=32,shuffle=True
)for data in test_loader:images, labels = datatest_output=net(images[:10])#在测试集中选择10张图片输入网络,得到结果
pred_y = torch.max(test_output, 1)[1].data#对得到的结果进行预测
print(pred_y, 'prediction numbe')#输出预测结果
print(labels[:10], 'real number')#输出真实结果def plt_image(image):#定义一个函数,将需要预测的手写数字图画出来n = 10plt.figure(figsize=(10,4))for i in range(n):ax = plt.subplot(2,5,i+1)plt.imshow(images[i].reshape(28,28))plt.gray()ax.get_xaxis().set_visible(False)ax.get_yaxis().set_visible(False)plt.show()
plt_image(images)# 测试自己手动设计的手写数字
from PIL import Image
I = Image.open('2.jpg')
L = I.convert('L')#转化为二值图像
plt.imshow(L, cmap='gray')transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1037,), (0.3081,))
])
im = transform(L)  # [C, H, W]
im = torch.unsqueeze(im, dim=0)  # [N, C, H, W],扩展维度
with torch.no_grad():outputs = net(im)_, predict = torch.max(outputs.data, 1)print(predict)

完整代码及解析!!手写数字识别系统(手写数字测试识别 + pytoch实现 + 完整代码及解析)相关推荐

  1. VLSI数字信号处理系统——第一章数字信号处理系统导论

    VLSI数字信号处理系统--第一章数字信号处理系统导论 作者:夏风喃喃 参考:VLSI数字信号处理系统:设计与实现 (美)Keshab K.Parhi/著 文章目录 VLSI数字信号处理系统--第一章 ...

  2. 中安OCR文字识别系统V5.0 ——OCR文字识别开发包SDK

    一.中安OCR文字识别系统V5.0简介 中安OCR文字识别系统V5.0是一种光学字符识别(OCR)软件开发包(OCR SDK):中安OCR文字识别系统V5.0为软件开发人员.系统集成商.数据加工商(B ...

  3. python人脸识别系统早已开源,离线识别率高达99%以上!

    以往的人脸识别主要是包括人脸图像采集.人脸识别预处理.身份确认.身份查找等技术和系统.现在人脸识别已经慢慢延伸到了ADAS中的驾驶员检测.行人跟踪.甚至到了动态物体的跟踪. 由此可以看出,人脸识别系统 ...

  4. 汽车Vin码识别系统,就用OCR识别技术

    汽车VIN码识别系统是一款VIN码识别.采集.解析SDK,可集成在安卓.IOS平台. 汽车VIN码识别系统• 高效--视频流识别.一秒钟采集VIN码,识别率高达99%: 汽车VIN码识别系统• 便捷- ...

  5. 中国正建全球最强人脸识别系统,3 秒内识别身份

    (点击上方公众号,可快速关注) 综合转自:Solidot + 参考消息网 (网络图:人脸识别) 中国将建全国面部识别系统,能在数秒内识别任何公民 阿里巴巴旗下的<南华早报>报道,中国正在建 ...

  6. python车牌识别系统抬杆_车牌识别系统识别到道闸不抬杆是什么问题?

    原标题:车牌识别系统识别到道闸不抬杆是什么问题? 在日常日生活中,我们在进入商场或许居住区的时候,总是因为一些原因,车牌不能自动识别成功进入.有些时分为什么他人能进入,自己就进不了,有时分是挺疑问的. ...

  7. 车牌识别系统不能连接服务器,车牌识别系统常见问题及其解决方法

    一.常见问题 1.车牌定位与字符分割 这是指在已拍摄的图像中确定车牌的位置,提取出车牌的图像,然后分割出车牌中的字符.车牌区域定位的困难主要是来自于采集的图像,由于采集的车牌图像的多样性,并且采集图像 ...

  8. 车牌识别系统不能连接服务器,车牌识别系统图像无法正常输出的原因与解决方法...

    原标题:车牌识别系统图像无法正常输出的原因与解决方法 19日,笔者从广州车牌识别系统安装厂家惠顺科技获悉,经常有物业向会惠顺科技抱怨:他们在使用一些杂牌车牌识别系统过程中会出现图像正常输出的问题,进而 ...

  9. 车牌识别系统服务器设计,道闸车牌识别系统停车场管理设计方案

    1.道闸车牌识别系统将机械.电子计算机和自动控制等技术有机地结合起来.可是现在脱机状态(即非联网状态)下实现:自动是被卡内身份.自动开启与关闭闸机.自动储存记录.自动核算费用.自动LED屏信息提示.语 ...

最新文章

  1. R语言ggplot2可视化:置信区间与分组具有相同色彩、自定义置信区间带的色彩、Make confidence intervals the same color as line by group
  2. 【Java Web开发指南】解析Spring中Ioc和DI(入门Demo)
  3. 数据操纵语言(DML)
  4. android 帐户管理,Android开发之帐户管理
  5. CompletableFuture多任务组合
  6. 微信小程序tabBar导航栏页和其他页执行onLoad与onShow时机;tabBar页获取不到参数问题;navigateTo跳转无效问题;onShow执行两次问题;
  7. 为什么使用交叉熵代替二次代价函数_Softmax回归与交叉熵损失的理解
  8. 卷积神经网络CNN(Convolutional Neural Network)原理与代码实现 Le-Net5
  9. java 输入框_Java文本框和文本区的输入输出
  10. 漫谈Google的Native Client(NaCl)技术(二)–技术篇(兼谈LLVM)
  11. PCL之点特征直方图(PFH)
  12. mysql 分组之后统计记录条数
  13. CKPlayer网页视频播放器
  14. 小米组织变革:新设三大部门,推进“手机X AIOT”战略落地
  15. Windows电脑添加打印机
  16. u盘的大小在计算机无法显示,将U盘插入Win10计算机后不显示可用容量,无法打开无法读取,如何解决...
  17. 导出pdf文件时加图片水印
  18. Spring Cloud Gateway(十):网关过滤器工厂 GatewayFilterFactory
  19. centos部署hadoop完全分布式
  20. .globl伪操作符

热门文章

  1. Groovy脚本基础全攻略
  2. BUUCTF [BJDCTF2020]EzPHP1详解
  3. CS224N Assignment3 #3: Dependency Parsing(2022 winter)
  4. 戴尔灵越15-5567装黑苹果
  5. No enclosing instance of type E is accessible. Must qualify the allocation with an enclosing instanc
  6. logback 配置总结
  7. recycleview获取第一个和最后一个可见item的位置
  8. 高斯旋转热源与双椭球热源_【干货】论焊接,3D打印模拟的热源模型——焊缝、3D打印高度变换模拟...
  9. 通过API接口快速根据关键词获取拼多多商品列表
  10. 什么是光开光?它有什么作用?