【深度学习基础】使用Pytorch搭建DNN深度神经网络与手写数字识别

目录

写在开头

一、DNN的搭建

问题描述与数据集

神经网络搭建

模型训练

模型评估

模型复用

二、手写数字识别

任务描述

数据集 

神经网络搭建

模型训练    

模型评估

写在最后

写在开头

     本文将介绍如何使用PyTorch框架搭建深度神经网络模型。实现模型的搭建、模型训练、测试、网络的保存等。实现机器学习领域的Hello world——手写数字识别。本文是基于B站爆肝杰哥的讲解基础下进行的总结,特别感谢杰哥的讲解,其视频如下:

Python深度学习:安装Anaconda、PyTorch(GPU版)库与PyCharm_哔哩哔哩_bilibili

   使用的PyTorch为1.12.0版本,Numpy为1.21版本,相近的版本语法差异很小。有关数组的数据结构教程、神经网络的基本原理(前向传播/反向传播)和神经网络作为“函数模拟器”直观感受,详见本专栏的前两篇文章,链接如下:

【深度学习基础】NumPy数组库的使用-CSDN博客

【深度学习基础】用PyTorch从零开始搭建DNN深度神经网络-CSDN博客

     在本专栏的上一篇文章中,我们手动搭建了神经网络,并通过反向传播对参数final_bias进行了优化,上一篇博客中提到的在神经网络的类中,前向传播方法如下:

    def forward(self, input):input_to_top_relu = input * self.w00 + self.b00top_relu_output = F.relu(input_to_top_relu)scaled_top_relu_output = top_relu_output * self.w01input_to_bottom_relu = input * self.w10 + self.b10bottom_relu_output = F.relu(input_to_bottom_relu)scaled_bottom_relu_output = bottom_relu_output * self.w11input_to_final_relu = scaled_top_relu_output + scaled_bottom_relu_output + self.final_biasoutput = F.relu(input_to_final_relu)return output

        然而这种方法在实现前向传播计算输出值的过程过于繁琐,需要人工的写很多公式以搭建神经网络,可扩展性很差。如果是有很多层数的大型神经网络,难道也要这样逐个公式的手工摆出吗?实际上,PyTorch封装了一些可以直接搭建网络的方法,后文中我们会具体实现,非常便捷。下面我们就用PyTorch搭建DNN,实现一个简单的分类预测问题。

一、DNN的搭建

      使用PyTorch搭建的神经网络需要引入一些库,如下所示:

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
# 下面这几行用于展示高清图,在jupter notebook中最好加上,本地运行代码也可以不加
%matplotlib inline
from matplotlib_inline import backend_inline
backend_inline.set_matplotlib_formats('svg')

问题描述与数据集

     本节我们以一个简易的分类预测问题为例,通过使用PyTorch搭建神经网络,实现模型的训练、测试、模型的保存等。一共有三个输入特征X1,X2,X3,预测输出特征Y1,Y2,Y3,其中Y1,Y2,Y3为对应的类别。设X_sum = X1 + X2 + X3,数据集中输入特征满足以下分布:

1.X1,X2,X3相互独立,且服从在范围(0-1)的均匀分布;

2.当X_sum < 1 时,Y1=1,否则Y1=0;

3.当1<X_sum < 2 时,Y2=1,否则Y2=0;

2.当X_sum > 2时,Y3=1,否则Y3=0。

   显然,输出特征组合后是一个One-Hot编码,这是一个分类问题。

   特别注意,如上的X1,X2,X3的分布是我们创建数据集自定义的规则,对于神经网络而言,神经网络起初并不知道这些分布,需要通过对数据集的学习(模型训练),去尽可能拟合出这些分布,以实现分类预测

     通过以下代码可以实现数据集的构建,数据集一共有10000个样本,每个样本有3个输入特征和3个输出特征(标签),我们针对每个输入特征,生成0-1均匀分布的随机数,构成10000行1列的矩阵X1,X2,X3,然后根据数据集特征的分布构建其标签Y1,Y2,Y3,特别注意,.float()方法用于将布尔型张量转换为浮点型,代码如下:

# 生成数据集
X1 = torch.rand(10000,1)
X2 = torch.rand(10000,1)
X3 = torch.rand(10000,1)
Y1 = ((X1+X2+X3)<1).float()
Y2 = (((X1+X2+X3)>1) & ((X1+X2+X3)<2)).float()
Y3 = (X1+X2+X3>2).float()
Data = torch.cat([X1,X2,X3,Y1,Y2,Y3], axis=1) #整合数据集
Data = Data.to('cuda:0')   # 将数据集迁移到GPU上

     最后我们可以看一下这个数据集的形状和内容:

    确实是10000*6的张量形式,前三列为输入特征,后三列为真实情况的分类(One-Hot编码)。下面我们划分数据集为训练集和测试集。7000:3000即可,代码如下:

# 划分训练集和测试集
train_size = int(len(Data)*0.7)   # 训练集大小
test_size = len(Data) - train_size   # 测试集大小
Data = Data[torch.randperm(Data.size(0)), :]  #打乱数据集
train_Data = Data[:train_size, :]
test_Data = Data[train_size:, :]

     这段基本上是固定的代码,打乱数据集也有助于模型训练。

神经网络搭建

    接下来我们进入正题,用PyTorch搭建神经网络。我们搭建的神经网络以nn.Module作为父类,直接继承父类的方法和属性,nn.Module中已经包含了网络各个层的定义。用__init__方法作为构造函数,构造自己的神经网络结构, forward方法用于将输入数据进行前向传播。反向传播无需我们再写代码实现,因为张量可以自动计算梯度。搭建DNN的代码如下:

class DNN(nn.Module):def __init__(self):'''搭建神经网络的各层'''super(DNN, self).__init__()   # 初始化父类self.net = nn.Sequential(nn.Linear(3, 5), nn.ReLU(),nn.Linear(5, 5), nn.ReLU(),nn.Linear(5, 5), nn.ReLU(),nn.Linear(5, 3))def forward(self, inputx):'''前向传播'''outputy = self.net(inputx)  #从输入到输出return outputy    # 返回输出结果

     这段代码非常简洁,我们用nn.Sequential()方法按顺序搭建了神经网络的4个全连接层,除了输出层外,剩下的每层(即隐藏层)后都使用了ReLU作为激活函数,用于引入非线性。特别注意每一层的神经元个数分别为(3,5,5,5,3),其中最开始的3表示输入层的三个神经元,这是因为有3个输入特征,同理,最后的3表示输出层的三个神经元,由输出特征的数量(3个)决定。至于隐藏层的个数和隐藏层中的神经元个数,这些称之为超参数,可由读者自行决定。

    接下来我们创建网络的实例:

model = DNN().to('cuda:0')  #创建子类实例,并搬到GPU上

    可以直接在jupter notebook上查看以下我们实例的模型model:

    如上图所示,显示了每一层的形式,输入特征和输出特征分别有多少个(通常我们不把单个激活函数称之为“一层”,不过这里显示单独把ReLU列为一层,大家懂其含义就行,关键还是看Liner层的层数)。 如果想看一下每一层的参数具体是多少,也可以通过如下代码实现:

# 查看内部参数(非必要)
for name, param in model.named_parameters():print(f"参数:{name}\n形状:{param.shape}\n数值:{param}\n")

   比如这里我们可以看到在训练前,输入层的参数如下:

    最后一层,即输出层的参数如下:

   此时这些参数都还没经过训练(注意到requites_grad=True,变送这些需要进行反向传播的内部参数都打开了张量的自动梯度计算功能),参数都是随机的(实际上我们还可以对初始值进行一些操作,这里不展开讲了),读者可以等模型训练完毕之后,再度查看一下参数的情况,会发现参数大多发生了改变。 

模型训练

     网络已经搭建完毕,接下来我们就要开始训练网络了。首先设置损失函数和优化算法:

# 选择损失函数
loss_fn = nn.MSELoss()
# 选择优化算法
learning_rate = 0.01  # 设置学习率
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)    # 梯度下降法进行优化

      这里有关损失函数的选择和优化算法的具体选择我们不展开说,读者可以自行查阅资料,PyTorch 1.12版本的文档在torch.nn — PyTorch 1.12 documentation 。

     接下来对网络进行训练,并作图画出损失函数的变化曲线:

# 训练网络
epochs = 1000
losses = []  #记录损失函数变化的列表# 对训练集划分输入输出
X = train_Data[:, :3]   #前三列为输入特征
Y = train_Data[:, -3:]  #后散列为输出特征for epoch in range(epochs):Pred = model(X)  #进行一次前向传播loss = loss_fn(Pred, Y)  #计算损失函数losses.append(loss.item())  # 记录损失函数的变化,loss是张量,用.item()降级为普通元素optimizer.zero_grad()  # 清理上一轮滞留的梯度loss.backward()  # 一次反向传播optimizer.step() # 优化内部参数# 作图表示损失函数的变化
Fig = plt.figure()
plt.plot(range(epochs), losses)
plt.ylabel('loss')
plt.xlabel('epochs')
plt.show()

      所有代码的注释已经标注出来,绘图结果如下,设置训练轮次是1000。显然,随着轮次epoch的增加,损失函数逐渐减小:

    训练完成后,读者如果对于网络此时的内部参数感兴趣,也可以用上文的方法查看,相比训练前有所不同了。 

模型评估

    网络已经训练完成了。那么这个网络的性能如何呢?能不能实现由输入特征预测输出分类呢?这就需要用测试集进行模型评估了。测试的代码如下:

# 测试网络# 给测试集划分输入和输出
X_test = test_Data[:, :3]  # 前三列为输入特征
Y_test = test_Data[:, -3:] # 后三列为输出特征with torch.no_grad():   # 只需要前向传播,该局部关闭梯度计算功能,降低内存开销,提高运算速度Pred = model(X_test)  # 一次前向传播Pred[:, torch.argmax(Pred, axis=1)] = 1Pred[Pred!=1] = 0  # 这两行,用argmax函数,将预测值中的最大者置为1,然后再将不为1的地方置为0,相当于转换为one-hot编码的输出形式correct = torch.sum((Pred == Y_test).all(1))  #预测正确的样本数total = Y_test.size(0)  # 所有样本数print(f"预测的正确的样本数{correct}\n测试集的精准度是:{100*correct/total}%")

    测试集共有3000条数据,也就是最终的预测输出会有一个3000行、3列的输出。当然,经过前向传播Pred = model(X_test)得到的结果应该是浮点型的张量,我们如何将其转换为One-hot编码的形式,并与真实情况进行对比呢?

     这个问题也不难解决,我们使用argmax函数,将输出的三个特征中的最大值的位置设置为1,其他位置设置为0,就相当于将输出转换为了One-hot编码的形式,具体如下:

Pred = model(X_test)  # 一次前向传播,此时Pred是3000*3的浮点型张量

接下来我们要将Pred转换为One-hot编码的形式。

torch.argmax(Pred, axis=1)可以求得此时Pred张量中,最大值所在列的位置。

然后通过代码   Pred[:, torch.argmax(Pred, axis=1)] = 1    将最大值所在列的位置的值置为1
再通过  Pred[Pred!=1] = 0    将其他位置的值置为0,就相当于实现了One-hot编码。

     最终我们输出预测结果,如下:

    准确率大概是67%,说明我们这个模型还有不小的提升空间,可以调节网络的结构或使用更好的优化算法、使用小批量梯度下降的方式进行优化。

模型复用

     最后还有个实际的问题,那就是我们训练好的网络如何保存?当在其他环境需要用到模型的时候,该如何迁移?这个只要用如下的代码就可以实现模型保存:

# 保存网络
torch.save(model, 'model.pth')

    torch.save()函数的参数是,model表示要保存的模型(此处就是我们的model),’model.pth‘是保存模型的路径,此处我们就保存在当前文件夹下,运行次代码后,我们可以看到当前文件夹中出现了model.pth,即我们的模型:

    接下来可以通过torch.load(模型路径)的方法将模型赋值给新网络:

# 把模型赋给新网络
new_model = torch.load('model.pth')# 用新网络测试
# 给测试集划分输入和输出
X_test = test_Data[:, :3]  # 前三列为输入特征
Y_test = test_Data[:, -3:] # 后三列为输出特征with torch.no_grad():   # 只需要前向传播,该局部关闭梯度计算功能,降低内存开销,提高运算速度Pred = new_model(X_test)  # 一次前向传播Pred[:, torch.argmax(Pred, axis=1)] = 1Pred[Pred!=1] = 0  # 这两行,用argmax函数,将预测值中的最大者置为1,然后再将不为1的地方置为0,相当于转换为one-hot编码的输出形式correct = torch.sum((Pred == Y_test).all(1))  #预测正确的样本数total = Y_test.size(0)  # 所有样本数print(f"new_model预测的正确的样本数{correct}\n测试集的精准度是:{100*correct/total}%")

      如下图所示,网络是一样的,测试集也一样,当然预测结果也一样啦:

 最后给出完整的模型训练-测试代码:

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
# 展示高清图
# from matplotlib_inline import backend_inline
# backend_inline.set_matplotlib_formats('svg')class DNN(nn.Module):def __init__(self):'''搭建神经网络的各层'''super(DNN, self).__init__()self.net = nn.Sequential(nn.Linear(3, 5), nn.ReLU(),nn.Linear(5, 5), nn.ReLU(),nn.Linear(5, 5), nn.ReLU(),nn.Linear(5, 3))def forward(self, inputx):'''前向传播'''outputy = self.net(inputx)  # 从输入到输出return outputy# 生成数据集
X1 = torch.rand(10000,1)
X2 = torch.rand(10000,1)
X3 = torch.rand(10000,1)Y1 = ((X1+X2+X3)<1).float()
Y2 = (((X1+X2+X3)>1) & ((X1+X2+X3)<2)).float()
Y3 = (X1+X2+X3>2).float()
print(Y1.shape, Y2.shape, Y3.shape)Data = torch.cat([X1,X2,X3,Y1,Y2,Y3], axis=1) #整合数据集
Data = Data.to('cuda:0')# 划分训练集和测试集
train_size = int(len(Data)*0.7)
test_size = len(Data) - train_size
Data = Data[torch.randperm(Data.size(0)), :]  #打乱数据集
train_Data = Data[:train_size, :]
test_Data = Data[train_size:, :]model = DNN().to('cuda:0')  #创建子类实例,并搬到GPU上
# 查看内部参数(非必要)
for name, param in model.named_parameters():print(f"参数:{name}\n形状:{param.shape}\n数值:{param}\n")# 选择损失函数
loss_fn = nn.MSELoss()
# 选择优化算法
learning_rate = 0.01  # 设置学习率
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)# 训练网络
epochs = 1000
losses = []  #记录损失函数变化的列表# 对训练集划分输入输出
X = train_Data[:, :3]   #前三列为输入特征
Y = train_Data[:, -3:]  #后散列为输出特征for epoch in range(epochs):Pred = model(X)  #进行一次前向传播loss = loss_fn(Pred, Y)  #计算损失函数losses.append(loss.item())  # 记录损失函数的变化,loss是张量,用.item()降级optimizer.zero_grad()  # 清理上一轮滞留的梯度loss.backward()  # 一次反向传播optimizer.step() # 优化内部参数# 作图表示损失函数的变化
Fig = plt.figure()
plt.plot(range(epochs), losses)
plt.ylabel('loss')
plt.xlabel('epochs')
plt.show()# 测试网络# 给测试集划分输入和输出
X_test = test_Data[:, :3]  # 前三列为输入特征
Y_test = test_Data[:, -3:] # 后三列为输出特征with torch.no_grad():   # 只需要前向传播,该局部关闭梯度计算功能,降低内存开销,提高运算速度Pred = model(X_test)  # 一次前向传播Pred[:, torch.argmax(Pred, axis=1)] = 1Pred[Pred!=1] = 0  # 这两行,用argmax函数,将预测值中的最大者置为1,然后再将不为1的地方置为0,相当于转换为one-hot编码的输出形式correct = torch.sum((Pred == Y_test).all(1))  #预测正确的样本数total = Y_test.size(0)  # 所有样本数print(f"预测的正确的样本数{correct}\n测试集的精准度是:{100*correct/total}%")

二、手写数字识别

      接下来我们实现机器学习领域的Hello World——手写数字识别。使用的数据集MNIST是机器学习领域的标准数据集,其中的每一个样本都是一副二维的灰度图像:

任务描述

     因此对于整个手写数字识别的任务,模型的输入是一副图像,输出则是一个对应的识别出的数字(0-9之间的整数)。这里注意,在进行模型训练时,PyTorch会在整个过程中自动将输出转换为One-Hot编码,因此我们在训练时不需要手动将输出转换为One-Hot编码,但进行模型评估测试时,由于需要比对预测输出(One-hot)和真实输出(0-9的数字),要进行一次转化。

    对于单个样本,每个图像都是一个二维灰度图像,像素为28*28.二维灰度图像的通道数为1,因此可以将每个样本图像转换为28*28的张量,作为输入。相当于是下图这样的形式:

    具体怎么转换,需要用到torchvision库中的trabsforms进行图像转换,将数据集转换为张量的形式,并调整数据集的统计分布(转换为标准正态分布更利于训练)。

数据集 

    我们需要从torchvision库中分别下载训练集和测试集,同时还需要用到torchvision库中的trabsforms进行图像转换。同时我们还要用到批次加载器,位于torch.utils.data中的DataLoader,因此需要导入的库如下所示:

import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
import matplotlib.pyplot as plt

    从torchvision库的datasets中下载数据集之前,需要先设定数据集的转换参数,将图像转换为二维张量,并转化为标准正态分布的形式,有助于提高模型性能。根据统计,MNIST中训练集所有像素的均值是0.1307、标准差是0.3081,数据集转换参数的设置代码如下:

# 设定下载参数 (数据集转换参数)
transform = transforms.Compose([transforms.ToTensor(),   # 用于将图像转换为张量transforms.Normalize(0.1307, 0.3081)   # 标准化,MNIST 训练集所有像素的均值是 0.1307、标准差是 0.3081
])

    然后我们就可以进行下载了,分别下载训练集和测试集,代码如下:

# 下载训练集和测试集
train_Data = datasets.MNIST(root = 'D:/Jupyter/dataset/minst/', #下载路径train = True,  # 是否下载训练集download = True,  # 如果该路径没有数据集,则下载transform = transform   # 数据集转换参数
)test_Data = datasets.MNIST(root = 'D:/jupyter/dataset/minst/',train = False,download = True,transform = transform
)

    然后使用批次加载器DataLoader加载数据,可以在接下来的训练中进行小批次的载入数据,有助于提高准确度,对训练集的样本进行打乱,设置shuffle=True。代码如下:

# 批次下载器
train_loader = DataLoader(train_Data, shuffle=True, batch_size=64)
test_loader = DataLoader(test_Data, shuffle=False, batch_size=64)

神经网络搭建

    此处和之前的区别不大,我们直接给出代码:

class DNN(nn.Module):def __init__(self):'''搭建神经网络各层'''super(DNN, self).__init__()self.net = nn.Sequential(nn.Flatten(),   # 先把图像铺平成一维nn.Linear(784, 512), nn.ReLU(),nn.Linear(512, 256), nn.ReLU(),nn.Linear(256, 128), nn.ReLU(),nn.Linear(128, 64), nn.ReLU(),nn.Linear(64, 10))def forward(self, inputx):'''前向传播'''outputy = self.net(inputx)return outputy

    这里需要注意的是,由于图像转换后的张量是二维的,需要用nn.Flatten先将图像展平为一维的。28*28的图像铺平后,相当于有28*28=784个值,因此相当于有784个输入特征。所以输入层的神经元个数也为784,对应第第一个nn.Linear(784,xxx),最终是一个预测任务,输出可能有10个值(即0-9)的分类问题,输出特征个数为10(One-Hot编码),因此我们输出的神经元个数为10。

    与之前类似,将模型实例化,并转移到GPU上:

model = DNN().to('cuda:0')

模型训练    

      这里还要注意,手写数字识别是分类预测问题,输出值相当于是One-Hot编码。对于这种多分类问题,如果想用概率表示分为每一类的可能性,输出层需要添加一个softmax激活函数,用于将输出层的数据归一化到0-1范围内,且总和为1,实现对概率的模拟。在我们选择损失函数的时候,可以选择自带softmax激活函数的交叉熵损失函数CrossEntropyLoss。 最终我们设定的损失函数和优化算法选择如下:

# 损失函数的选择
loss_fn = nn.CrossEntropyLoss()    # 交叉熵损失函数自带softmax# 优化算法的选择
learning_rate = 0.01
optimizer = torch.optim.SGD(model.parameters(),lr = learning_rate,momentum = 0.5
)

    然后开始训练网络,采用小批次的方式加载数据:

# 训练网络
epochs = 5
losses = []   # 记录损失函数变化的列表for epoch in range(epochs):for (x, y) in train_loader:# 由于数据集内部进不去,只能在循环的过程中取出一部分样本,就立即将之搬到 GPU 上x, y = x.to('cuda:0'), y.to('cuda:0') Pred = model(x)loss = loss_fn(Pred, y)losses.append(loss.item())optimizer.zero_grad()loss.backward()optimizer.step()Fig = plt.figure()
plt.plot(range(len(losses)), losses)
plt.show()

   绘制出的损失函数变化如下:

模型评估

    也是相似的方法进行模型评估,代码如下:

# 测试网络
correct = 0
total = 0
with torch.no_grad():   #局部关闭梯度计算,节省开销for (x, y) in test_loader:x, y = x.to('cuda:0'), y.to('cuda:0')Pred = model(x)_, predicted = torch.max(Pred.data, dim=1)correct += torch.sum((predicted==y))total += y.size(0)
print(f"测试集的精确度是{100*correct/total}%")
print(f"correct = {correct}, total = {total}")

     其中代码_,predicted = torch.max(Pred.data, dim=1)表示找出Pred每一行(dim=1)的最大值,将最大值的数值赋值给_(我们不关心这个数值的绝对大小,因此用_接受即可),将最大值所在的位置赋值给predicted,就相当于将One-hot编码转换回了阿拉伯数字(0-9),方便直接判断与标签y是否相等。注意到此处predicted和y都是一维的(一阶张量),因此求取正确预测个数时无需添加.all(1)

    最终的评估结果如下:

    准确率高达96.65,很不错了!

写在最后 

   本文介绍了如何使用PyTorch框架搭建深度神经网络模型。实现模型的搭建、模型训练、测试、网络的复用等,并实现机器学习领域的Hello world——手写数字识别。重点关注PyTorch的实现方式,有关模型结构的设置、损失函数和优化算法的选择并没有进行详细的讲解,读者可以自行研究。可以看出PyTorch框架还是大幅度提高了我们搭建神经网络的效率,可以通过直接调用接口的方式搭建不同的网络模型。

     本文实现的手写数字识别是基于DNN实现的,将灰度图像转换后的二维数组展平到一维,将一维的784个特征作为模型输入。在“展平”的过程中必然会失去一些图像的形状结构特征,因此基于DNN的实现方式并不能很好的利用图像的二维结构特征,而卷积神经网络CNN对于处理图像的位置信息具有一定的优势,相比于DNN,CNN在图像处理领域往往有更好的性能。后续我也可能会更新一些相关的内容。

    后续还会继续更新神经网络的相关知识,另外近期我个人的研究方向涉及到图神经网络,回头也会更新一些相关博客。如果读者有相关建议或疑问也欢迎评论区与我共同探讨,我一定知无不言。总结不易,还请读者多多点赞关注支持!

     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/19667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

USART串口外设

USART介绍 USART&#xff1a;另外我们经常还会遇到串口&#xff0c;叫UART&#xff0c;少了个S&#xff0c;就是通用异步收发器&#xff0c;一般我们串口很少使用这个同步功能&#xff0c;所以USART和UART使用起来&#xff0c;也没有什么区别。 其实这个STM32的USART同步模式&a…

创新产品认定进行第三方软件鉴定测试的原因

鉴定测试报告 随着科技的飞速发展&#xff0c;软件产品在各个领域的应用越来越广泛&#xff0c;对于软件产品的质量和安全性要求也越来越高。为了确保软件产品的质量和安全性&#xff0c;创新产品认定进行第三方软件鉴定测试成为了一种必要手段。 一、保障产品质量 第三方软…

从了解到掌握 Spark 计算框架(二)RDD

文章目录 RDD 概述RDD 组成RDD 的作用RDD 算子分类RDD 的创建1.从外部数据源读取2.从已有的集合或数组创建3.从已有的 RDD 进行转换 RDD 常用算子大全转换算子行动算子 RDD 算子综合练习RDD 依赖关系窄依赖宽依赖宽窄依赖算子区分 RDD 血统信息血统信息的作用血统信息的组成代码…

LM2733升压芯片

具有 40V 内部 FET 开关且采用 SOT-23 封装的 LM2733 0.6MHz 和 1.6MHz 升压转换器 外观 参考价格 1 特性 电路原理图 基于LM2733升压电路设计-CSDN博客https://blog.csdn.net/qq_31251431/article/details/107479885 特此记录 anlog 2024年5月31日 高压方案 此方案经过更多…

MySQL -- SQL笔试题相关

1.银行代缴花费bank_bill 字段名描述serno流水号date交易日期accno账号name姓名amount金额brno缴费网点 serno: 一个 BIGINT UNSIGNED 类型的列&#xff0c;作为主键&#xff0c;且不为空。该列是自动增量的&#xff0c;每次插入新行时&#xff0c;都会自动递增生成一个唯一的…

游戏安全 | 一款「安全」的SLG游戏应该是什么样的?

谈到SLG游戏&#xff0c;也许会想到《万国觉醒》&#xff0c;海外上线5个月后&#xff0c;以5400万美元的月流水创造了新的SLG手游海外收入纪录。 谈到SLG游戏&#xff0c;也许会想到《王国纪元》&#xff0c;通过两军对战的方式&#xff0c;以大面积消灭敌人的攻势&#xff0c…

数据库开发-MySQL01

目录 前言 1. MySQL概述 1.1 安装 1.1.1 版本 1.1.2 安装 1.1.3 连接 1.1.4 企业使用方式(了解) 1.2 数据模型 1.3 SQL简介 1.3.1 SQL通用语法 1.3.2 分类 2. 数据库设计-DDL 2.1 项目开发流程 2.2 数据库操作 2.2.1 查询数据库 2.2.2 创建数据库 2.2.3 使用数…

echarts学习:将echats实例代理为响应式对象可能带来的风险

1.起源 最近我在学习如何封装echarts组件&#xff0c;我所参考的其中一篇博客中提到了一个“图表无法显示的问题”。 根据其中的介绍&#xff0c;造成此种问题的原因是因为&#xff0c;使用ref接受了echarts实例&#xff0c;使得echarts实例被代理为了响应式对象&#xff0c;进…

ChatGPT-4o在临床医学日常工作、论文高效撰写与项目申报、数据分析与可视化、机器学习建模中的应用

ChatGPT-4o在临床医学日常工作、论文高效撰写与项目申报、数据分析与可视化、机器学习建模中的应用 2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT-3.5&#xff0c;将人工智能的发展推向了一个新的高度。…

AI预测福彩3D采取888=3策略+和值012路一缩定乾坤测试5月29日预测第5弹

今天继续基于8883的大底&#xff0c;使用尽可能少的条件进行缩号&#xff0c;同时&#xff0c;同样准备两套方案&#xff0c;一套是我自己的条件进行缩号&#xff0c;另外一套是8883的大底结合2码不定位奖号预测二次缩水来杀号。好了&#xff0c;直接上结果吧~ 首先&…

BUUCTF Crypto RSA详解《1~32》刷题记录

文章目录 一、Crypto1、 一眼就解密2、MD53、Url编码4、看我回旋踢5、摩丝6、password7、变异凯撒8、Quoted-printable9、篱笆墙的影子10、Rabbit11、RSA12、丢失的MD513、Alice与Bob14、大帝的密码武器15、rsarsa16、Windows系统密码17、信息化时代的步伐18、凯撒&#xff1f;…

如何使用视频号下载助手机器人,下载视频号视频

目录 微信视频号版权问题 视频号下载助手机器人如何获取 手机市场基本一年每个品牌商发布的手机就高达10多种&#xff0c;而这些设备中并不支持手机缓存操作&#xff0c;却把市场搞的越来越浑&#xff0c;还不断宣传手机缓存可保存视频&#xff0c;今天教教大家如何使用视频号…

私域加持业务 快消门店运营新玩法

两个月前&#xff0c;某快消品企业的李总急切地联系了纷享销客&#xff0c;希望能找到解决终端门店运营难题的有效方法。 Step1、连接终端门店&#xff0c;导入私域进行深度维系与运营 一、与终端门店建立联系 为了与众多门店老板建立紧密的联系&#xff0c;并将他们转化为企…

sqliteSQL基础

SQL基础 SQLite 数据库简介 SQLite 是一个开源的、 内嵌式的关系型数据库&#xff0c; 第一个版本诞生于 2000 年 5 月&#xff0c; 目前最高版本为 SQLite3。 下载地址&#xff1a; https://www.sqlite.org/download.html 菜鸟教程 : https://www.runoob.com/sqlite/sqlit…

Redis相关详解

什么是 Redis&#xff1f;它主要用来什么✁&#xff1f; Redis&#xff0c;英文全称是 Remote Dictionary Server&#xff08;远程字典服务&#xff09;&#xff0c;是一个开源✁使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化✁日志型、Key-Value 数据库&#xff…

Elasticsearch 认证模拟题 -2

一、题目 有一个索引 task3&#xff0c;其中有 fielda&#xff0c;fieldb&#xff0c;fieldc&#xff0c;fielde 现要求对 task3 重建索引&#xff0c;重建后的索引新增一个字段 fieldg 其值是fielda&#xff0c;fieldb&#xff0c;fieldc&#xff0c;fielde 的值拼接而成。 …

css :hover的使用

参考未整理 即鼠标移入类名为btn的元素时&#xff0c;她的子元素i样式发生改变 自身的样式也发生改变 &#xff0c;如果他有更多的子元素也可以这样写

机器学习笔记(1):sklearn是个啥?

sklearn 简介 Sklearn是一个基于Python语言的开源机器学习库。全称Scikit-Learn&#xff0c;是建立在诸如NumPy、SciPy和matplotlib等其他Python库之上&#xff0c;为用户提供了一系列高质量的机器学习算法&#xff0c;其典型特点有&#xff1a; 简单有效的工具进行预测数据分…

自动化安装Nginx

1. 指定版本号和用户&#xff1b; 2. 确定安装目录&#xff1b; 3. 确定安装编译模块&#xff1b; 4. 安装相关依赖&#xff1b; 5. 下载源码包并解压&#xff1b; 6. 编译安装&#xff1b; 7. 文件授权及临时文件清理。 #!/bin/bash# 用户输入的Nginx版本号NGIN…

VMware虚拟机安装Ubuntu-Server版教程(超详细)

目录 1. 下载2. 安装 VMware3. 安装 Ubuntu3.1 新建虚拟机3.2 安装操作系统 4. SSH方式连接操作系统4.1 好用的SSH工具下载&#xff1a;4.2 测试SSH连接 5. 开启root用户登录5.1 设置root用户密码5.2 传统方式切换root用户5.3 直接用root用户登录5.4 SSH启用root用户登录 6. 安…