Pytorch基础教程:从零实现手写数字分类

news2025/1/15 5:26:06

1.Pytorch简介

‌PyTorch是一个开源的深度学习框架,由Facebook的人工智能研究院(FAIR)开发,并于2017年1月正式推出。‌ PyTorch以其灵活性和易用性著称,特别适合于深度学习模型的构建和训练。它基于Torch张量库开发,提供了动态计算图的功能,允许在运行时改变计算图,这使得模型构建更加灵活

2.理解tensor

Tensor 是PyTorch中最近本的数据结构,可以将其视为n维数组或者矩阵。n维矩阵在我们生活里非常常见。

2.1 一维矩阵

在这里插入图片描述
基本操作
在这里插入图片描述

2.2 二维矩阵

二维矩阵是一个表格,其中包含行和列。例如:
在这里插入图片描述
在这个矩阵中,
a11a 11 、a12a12 、a13a13 、a21a21 、a22a22 、a23a23 、a31a31 、a32a32 、a33a33 是矩阵的元素。第一个方括号内的元素属于第一行,第二个方括号内的元素属于第二行,第三个方括号内的元素属于第三行。

2.3 三维矩阵

三维矩阵可以看作是由多个二维矩阵组成的“矩阵的矩阵”,通常用于表示多维数据。例如,一个3x3x3的三维矩阵可以表示为:
在这里插入图片描述
在这个三维矩阵中,每一个二维矩阵(由方括号包围的部分)可以看作是一个“层”,整个三维矩阵由这些层组成。

3.创建tensor

3.1 你可以直接从一个Python列表或NumPy数组创建一个tensor:

import torch

# 从Python列表创建tensor
data = [[1, 2], [3, 4]]
tensor_from_list = torch.tensor(data)
print(tensor_from_list)

# 从NumPy数组创建tensor
import numpy as np
np_array = np.array(data)
tensor_from_np = torch.from_numpy(np_array)
print(tensor_from_np)

在这里插入图片描述

3.2 创建特定形状的tensor

你可以使用torch的内置函数来创建具有特定形状和值的tensor:

import torch

# 创建一个全为零的tensor,形状为(2, 3)
zeros_tensor = torch.zeros((2, 3))
print(zeros_tensor)

# 创建一个全为一的tensor,形状为(2, 3)
ones_tensor = torch.ones((2, 3))
print(ones_tensor)

# 创建一个未初始化的tensor,形状为(2, 3),其值可能是随机的
uninit_tensor = torch.empty((2, 3))
print(uninit_tensor)

# 创建一个具有指定值的tensor,所有元素都设为5,形状为(2, 3)
full_tensor = torch.full((2, 3), 5)
print(full_tensor)

在这里插入图片描述

3.3 创建三维tensor

要创建一个三维tensor,你只需指定三个维度的大小:

import torch

# 创建一个形状为(2, 3, 4)的三维tensor,所有元素都初始化为0
three_dim_tensor = torch.zeros((2, 3, 4))
print(three_dim_tensor)

3.4 使用随机数填充tensor

你还可以使用随机数来填充tensor:

import torch

# 创建一个形状为(2, 3)的tensor,其元素是从均匀分布[0, 1)中抽取的随机数
rand_tensor = torch.rand((2, 3))
print(rand_tensor)

# 创建一个形状为(2, 3)的tensor,其元素是从标准正态分布中抽取的随机数
randn_tensor = torch.randn((2, 3))
print(randn_tensor)


在这里插入图片描述

3.5 指定tensor的数据类型

在创建tensor时,你还可以指定其数据类型(dtype):

import torch

# 创建一个形状为(2, 3)的tensor,元素类型为浮点数(默认)
float_tensor = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
print(float_tensor)
print(float_tensor.dtype)  # 输出: torch.float32

# 创建一个形状为(2, 3)的tensor,元素类型为整数
int_tensor = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32)
print(int_tensor)
print(int_tensor.dtype)  # 输出: torch.int32



在这里插入图片描述

4.tensor基本运算

4.1 ‌算术运算:

4.1.1 ‌加法‌:

import torch
x = torch.tensor([1.0, 2.0, 3.0])
y = torch.tensor([4.0, 5.0, 6.0])
z = x + y  # 对应元素相加
print(z)  # 输出: tensor([5., 7., 9.])

4.1.2 ‌减法‌:

z = x - y  # 对应元素相减
print(z)  # 输出: tensor([-3., -3., -3.])

4.1.3 ‌乘法‌(逐元素乘法,不是矩阵乘法):

z = x * y  # 对应元素相乘
print(z)  # 输出: tensor([4., 10., 18.])

4.1.4 ‌除法‌:

z = x / y  # 对应元素相除
print(z)  # 输出: tensor([0.2500, 0.4000, 0.5000])

4.1.5 ‌幂运算‌:

z = x ** 2  # 每个元素求平方
print(z)  # 输出: tensor([1., 4., 9.])

4.2 ‌‌矩阵运算:

4.2.1 ‌‌矩阵乘法‌:

A = torch.tensor([[1, 2], [3, 4]])
B = torch.tensor([[5, 6], [7, 8]])
C = torch.mm(A, B)  # 或者使用 A @ B 在PyTorch 1.0及以上版本
print(C)  # 输出: tensor([[19, 22], [43, 50]])

4.2.2 ‌‌‌矩阵转置‌:

A_t = A.t()
print(A_t)  # 输出: tensor([[1, 3], [2, 4]])

4.2.3 ‌‌‌逐元素运算的广播机制:

PyTorch支持广播机制,当两个tensor的形状不完全相同时,较小的tensor会自动扩展以匹配较大的tensor的形状,然后进行逐元素运算。

x = torch.tensor([1.0, 2.0, 3.0])
y = torch.tensor(2.0)  # 这是一个标量,将被广播到与x相同的形状
z = x + y
print(z)  # 输出: tensor([3., 4., 5.])

4.3 ‌‌‌‌统计运算:

4.3.1 ‌‌‌‌求和‌:

sum_x = x.sum()  # 对所有元素求和
print(sum_x)  # 输出: tensor(6.)

4.3.2 ‌‌‌‌平均值‌:

mean_x = x.mean()  # 对所有元素求平均值
print(mean_x)  # 输出: tensor(2.)

4.3.3 ‌‌‌‌最大值和最小值‌:

max_x, _ = x.max()  # 返回最大值及其索引(这里只关心最大值)
min_x, _ = x.min()  # 返回最小值及其索引(这里只关心最小值)
print(max_x)  # 输出: tensor(3.)
print(min_x)  # 输出: tensor(1.)

4.4 形状操作:

4.4.1 ‌‌‌‌改变形状‌:

x_reshaped = x.view(-1, 1)  # 将x改变为列向量
print(x_reshaped)  # 输出: tensor([[1.], [2.], [3.]])

4.4.2 ‌‌‌‌展平‌:

x_flattened = x.flatten()  # 将x展平为一维数组
print(x_flattened)  # 输出: tensor([1., 2., 3.])

5.理解神经网络

在开始之前,我觉得有必要提个醒, 神经网络本质上是数学,但我们仅仅作为开发者,我们要做的事情是通过pytorch或类似的工具实现我们想要的功能,达到我们想要的目的。至于为什么里面的数学公式是这样子,为什么神经网络的架构是这样搭,为什么他这个结构这么好,我们根本不用去管里面的最底层机理。我们只需要知道这样子这样子就能达到效果,就可以了。我们不要被这些数学公式吓跑了。

5.1 什么是分类,什么是回归

‌分类和回归是机器学习中两种基本的预测方法,它们的核心区别在于预测的输出类型‌。

5.1.1 分类

分类,简单来说,就是给数据打上标签,预测它属于哪一个类别。比如,我们有一堆邮件,需要判断哪些是垃圾邮件,哪些是正常邮件。这就是一个典型的二分类问题,因为输出只有两种可能:垃圾邮件或正常邮件。再比如,我们有一张动物图片,需要判断它是猫、狗还是其他动物,这就是一个多分类问题,因为输出有多个可能的类别‌。

举例:想象你手里有一堆水果,你需要把它们分成苹果和橙子两类,这就是分类任务。你要看水果的颜色、形状等特征,然后决定它是苹果还是橙子。

5.1.2 回归

回归,则是预测一个具体的数值,这个数值可以是任何实数。比如,我们想知道一套房子的价格,根据它的面积、位置等特征来预测。这就是一个回归问题,因为输出是一个连续的数值,而不是一个类别标签。再比如,我们想预测明天的温度或者股票的价格,这些都是回归问题‌。

举例:想象你要预测一辆汽车的价格,你会考虑它的品牌、型号、年份、里程数等特征,然后给出一个具体的价格预测,比如10万元、15万元等,这就是回归任务。
图片转自‘人工智能教学实践’
上图转自‘人工智能教学实践’博客,我觉得这张图很好地解析什么是分类,什么是回归,预测天气的是分类,预测温度是多少,是回归。

5.2 有什么函数可以实现分类和回归?答案:线性回归

5.2.1 从二元一次方程组到Simple Linear Regression

初中时,我们通过两个点的坐标求解二元一次方程。例如:已知直线y = ax + b 经过点(1,1)和(3,2),求解a, b的值。
在这里插入图片描述

解法是将坐标值带入方程,得到一个二元一次方程组,并对其进行求解:

在这里插入图片描述
坐标图如下:
在这里插入图片描述
以上二元一次方程组的求解可以看作一个简单的线性回归问题,估算出x和y之间的线性关系,得到公式:y = 1/2*x + 1/2

5.2.1 什么是线性关系(Linear Relationship)?

在这里插入图片描述
在这里插入图片描述
需要注明的是,线性关系不仅仅指存在于两个变量之间,它也可以存在于三个或者更多变量之间。比如y = a + bx1 + cx2,这条直线可以在三维空间中表达。
但实际情况是,我们在真实世界的数据不会完美的落在一个直线上,即使两个数据存在线性关系,它们或多或少离完美的直线都还有一些偏差。图像表示如下:
在这里插入图片描述
以上直线表达的是predictor和outcome之间近似的线性关系:y ≈ ax + b

5.3 线性回归到神经网络

可以看出,线性回归非常直观且易于实现,同时也过于简单,只能适用于比较简单的模型,如果模型稍显复杂,则不能很好地反映数据的分布。
在这里插入图片描述
例如在该图中,红色线段为我们想要拟合的图形,蓝色线段为我们的线性回归模型,无论怎样调整斜率w 或截距 b,都无法与红色较好地匹配。说明在此例中,线性函数模型过于简单,我们需要一个稍微复杂一些的模型。这里我们引入一个分段函数作为模型:
在这里插入图片描述
可以看出,当 x<x1 或 x>x2 时,函数值恒等于一个值,而当 x∈[x1,x2] 时,函数值则是呈线性变化的。该函数图像如下:
在这里插入图片描述
所以如果用这个分段函数来模拟上面的红色线段的话,可以采用下面几个步骤:
在这里插入图片描述
step 0:取常数 b 作为红色线段在 y 轴上的截距;
step 1:令分段函数中间部分的斜率和长度与红色线段第一部分相同(w1,b1);
step 2:令分段函数中间部分的斜率和长度与红色线段第二部分相同(w2,b2);
step 3:令分段函数中间部分的斜率和长度与红色线段第三部分相同(w3,b3)。
所以红色线段可用几个不同的蓝色线段表示为:
在这里插入图片描述
问题又来了,这种分段函数看着非常复杂,而且计算不方便,能否再使用一个近似的函数进行替换呢?于是这里又引入了 Sigmoid 函数:
在这里插入图片描述
Sigmoid 函数可以很好的表现上面的蓝色线段,而且是非线性的,没有线性的那么直(或者说hard),所以也把上面蓝色的图形叫做hard sigmoid。
于是,我们的模型又等价于:
在这里插入图片描述
这里 n 的大小,取决于我们要模拟多复杂的函数,n越大,意味着要模拟的函数越复杂。
在这里插入图片描述

5.3.1 理解新模型 - 简易版神经网络

对于我们的新模型
在这里插入图片描述
来说,可以看做是先进行线性计算,然后放入Sigmoid函数计算后,再加上常数b的过程。可用下图表示:
在这里插入图片描述
如此一来,原本稍显繁琐的公式一下子就显得直观了不少。而且整个图看起来与神经网络非常相似,线性函数 wx+b 为输入层,Sigmoid 可看做隐藏层,加总后的y可看做输出层。如果让模型变得更复杂点,就更像了:
在这里插入图片描述
这里,我们增加了输入样本的复杂度(由单一连接变成了全连接),并且增加了多层 Sigmoid 函数,虽然模型整体更加复杂,但本质上还是没有变。所以我们完全可以从一个简单的线性模型过渡到一个复杂的神经网络。
再来看公式,看到这个加总符号 ∑,就说明里面进行的都是一系列相似的计算,所以用向量替换比较合适。
如果先约定好,统一使用列向量来表示数据,并使用 σ(x) 表示 Sigmoid 函数,则以上数据及参数可表示为:
在这里插入图片描述
然后我们就可以用这些向量来表示模型的公式了:
在这里插入图片描述

使用这种表示方式,不仅显得更简洁,而且计算速度也非常快,特别是当样本非常多的情况下。

6.定义网络结构

如果觉得上面讲解还是有点复杂,我们可以将神经网络简单粗暴地理解成是多对多的线性方程,比如说,我现在有个784像素的图片,图片里都是0-9的单独数字,想通过一张图片,预测是哪个数字。

输入: 784个参数
输出: 10个预测的概率

哪个概率最大哪个就是预测的数字。这就是我们要搭建的结构。
之前提过了, 一个神经网络中间是有几个隐藏层。而且隐藏层的参数个数我们可以自己定义,那上面的结构就可以这样表示。

输入: 784个参数
隐藏层1: 555个参数
隐藏层2: 888个参数
输出: 10个预测的概率

隐藏层的参数个数我们可以自己定义,这里隐藏层1参数个数我随便设置成555,隐藏层2参数个数设置成888.
但层与层之前的我们通过什么的方式连接呢?我们可以通过in_features, out_features的数值来设置,比如说这一层的输入的参数个数,是上一层的输出参数的个数, 这一层的输出的参数个数,是下一成的输入的参数个数。

输入: in_features = 784,out_features = 555
隐藏层1: in_features = 555,out_features = 888
隐藏层2: in_features = 888,out_features = 888
输出: in_features = 888,out_features = 10

到这里,大体的网络框架大概搭建了,但刚才说到了除了输入和输出外,我们还需要一个激活函数,激活函数我们之前学到了Sigmoid ,让线性的函数变得更加符合现实化,非线性化。也就是:

输入: in_features = 784,out_features = 555
**激活函数: ** Sigmoid()
隐藏层1: in_features = 555,out_features = 888
**激活函数: ** Sigmoid()
隐藏层2: in_features = 888,out_features = 888
**激活函数: ** Sigmoid()
输出: in_features = 888,out_features = 10

到这里的话其实神经网络已经体现出来了,但这个输出的值是一个正无穷到负无穷的值。它还不是一个概率值。

比如: [[-0.0575, -0.0059, 0.0094, 0.0205, -0.0239, 0.0034, -0.0519, -0.0335, 0.0502, 0.0181]]

我们还需要对他进行归一化。我们会用到一个函数叫Softmax(), 这个函数的作用就是对这些正无穷到负无穷的值进行处理,使其变成0-1之间的数,变成0-1之间的数后,我们就可以大胆地称之为概率。
在这里插入图片描述
在这里插入图片描述
ok, 那经过上面的套路,总结起来,神经网络就是

输入: in_features = 784,out_features = 555
**激活函数: ** Sigmoid()
隐藏层1: in_features = 555,out_features = 888
**激活函数: ** Sigmoid()
隐藏层2: in_features = 888,out_features = 888
**激活函数: ** Sigmoid()
输出: in_features = 888,out_features = 10
归一化: Softmax()

到此为止,我们已经手撕了一个简单的神经网络,回到我们的主题,如何通过Pytorch搭建神经网络。Here we go!

import torch
import torch.nn as nn

#784个像素点构成的灰度图->函数->10个概念(0,1,2,3,4,5,6,7,8,9)


#输入层 in_channel=784 out_channel=555
#隐藏层1 in_channel=555 out_channel=888
#隐藏层2 in_channel=888 out_channel=888
#输出层 in_channel=888 out_channel=10

data = torch.rand(1, 784)

model = nn.Sequential(
    nn.Linear(784, 555),
    nn.Sigmoid(),
    nn.Linear(555, 888),
    nn.Sigmoid(),
    nn.Linear(888, 888),
    nn.Sigmoid(),
    nn.Linear(888, 10),
    nn.Softmax()
)

predict = model(data)
print(model)
print(predict)

在这里插入图片描述
Pytorch已经帮我们封装好了函数,我们更重要的是理解然后手撕了一个简单的神经网络,然后通过Pytorch提供的函数进行调用了完事了。

7.整理数据集

我们可以从kaggle比赛中下载数据集。
https://www.kaggle.com/competitions/digit-recognizer/data

在这里插入图片描述
在这里插入图片描述
我们主要来看train.csv
在这里插入图片描述
从train.csv可以看到,第一列是标签, 其他列就是像素,0,1,2。。。。783
我们需要python中pandas的工具包来帮我们分解train.csv,并且用来隔开特征和标签。

import pandas as pd

raw_df = pd.read_csv('dataset/train.csv')
# 标签
label = raw_df['label'].values
# 特征
feature = raw_df.drop(['label'], axis=1)

特征这一列中,我们先删除label这一列,然后保留其他列,剩下的就是特征。
分割完标签和特征后,我们还要分测试集和训练集。我采取4:1的分割方式。

import torch
import torch.nn as nn
import pandas as pd

raw_df = pd.read_csv('dataset/train.csv')
# 标签
label = raw_df['label'].values
# 特征
feature = raw_df.drop(['label'], axis=1).values


#整个数据集划分成两个数据集 训练集 测试集, 4:1

train_feature = feature[:int(len(feature)*0.8)]
train_label = label[:int(len(label)*0.8)]
test_feature = feature[int(len(feature)*0.8):]
test_label = label[int(len(label)*0.8):]

print(len(train_feature),len(train_label),len(test_feature),len(test_label))

打印结果

33600 33600 8400 8400

至此,数据准备完成。

8.训练模型

模型架构有了, 数据也准备好了,我们可以训练起来了。
说到训练,我们就要进行梯度下降。找到一组合适的w和b,让损失值越小越好。
优先我们要准备一个损失函数,交叉熵损失函数。用来计算损失值。

lossfunction = nn.CrossEntropyLoss()

计算完损失值,我们下一步就是优化里面的w和b, pytorch给我们提供了很多优化函数,我们用Adam就足够了。

optimizer = torch.optim.Adam(params=model.parameters(), lr=0.0001)

import torch
import torch.nn as nn
import pandas as pd

raw_df = pd.read_csv('dataset/train.csv')
# 标签
label = raw_df['label'].values
# 特征
feature = raw_df.drop(['label'], axis=1).values


#整个数据集划分成两个数据集 训练集 测试集, 4:1

train_feature = feature[:int(len(feature)*0.8)]
train_label = label[:int(len(label)*0.8)]
test_feature = feature[int(len(feature)*0.8):]
test_label = label[int(len(label)*0.8):]

train_feature = torch.tensor(train_feature).to(torch.float)
train_label = torch.tensor(train_label)
test_feature = torch.tensor(test_feature).to(torch.float)
test_label = torch.tensor(test_label)

print(len(train_feature),len(train_label),len(test_feature),len(test_label))


#784个像素点构成的灰度图->函数->10个概念(0,1,2,3,4,5,6,7,8,9)


#输入层 in_channel=784 out_channel=555
#隐藏层1 in_channel=555 out_channel=888
#隐藏层2 in_channel=888 out_channel=888
#输出层 in_channel=888 out_channel=10

data = torch.rand(1, 784)

model = nn.Sequential(
    nn.Linear(784, 555),
    nn.Sigmoid(),
    nn.Linear(555, 888),
    nn.Sigmoid(),
    nn.Linear(888, 888),
    nn.Sigmoid(),
    nn.Linear(888, 10),
    nn.Softmax()
)

# predict = model(data)
# print(model)
# print(predict)

# 梯度下降。找到一组合适的w和b,让损失值越小越好。
lossfunction = nn.CrossEntropyLoss()
# 优化器
optimizer = torch.optim.Adam(params=model.parameters(), lr=0.0001)


# 训练的轮数
for i in range(100):
    # 清空优化器的梯度(偏导)
    optimizer.zero_grad()
    predict = model(train_feature)
    loss = lossfunction(predict, train_label)
    loss.backward()
    optimizer.step()
    print(loss.item())

至此,简单的神经网络训练程序已经搭建出来了, 我们可以开始运行,打印损失值。
在这里插入图片描述
我们可以看到损失值越来越小。意味着我们预测的准确率越来越高。
其实到这里我们已经结束了,但我们还想看看准确率,那我们可以在中间打印一下。首先

predict = model(train_feature)

这个predict 是一个数组,是包含所有概率的数组,我们简单理解成这样的数据。

0.3,0.1,0.2,0.1,0.0,0.0,0.0,0.0,0.0,0.0
0.1,0.1,0.2,0.1,0.0,0.0,0.0,0.0,0.5,0.0
0.2,0.1,0.2,0.1,0.0,0.0,0.0,3.0,0.3,0.0
0.1,0.1,0.2,0.1,0.0,0.0,0.0,0.1,0.0,0.0
0.1,0.1,0.2,0.1,0.0,0.0,0.0,0.3,0.0,0.0

我们首先要是每一行里面找到最大值,然后拿出它对应的数字,这里的数字其实就是对应的索引

result = torch.argmax(predict, axis=1)

然后准确率我们可以用这个result和train_label进行对比

train_acc = torch.mean((result==train_label).to(torch.float))

打印结果再看看

# 训练的轮数
for i in range(100):
    # 清空优化器的梯度(偏导)
    optimizer.zero_grad()
    predict = model(train_feature)
    result = torch.argmax(predict, axis=1)
    train_acc = torch.mean((result == train_label).to(torch.float))
    loss = lossfunction(predict, train_label)
    loss.backward()
    optimizer.step()
    print('train loss:{} train acc:{}'.format(loss.item(), train_acc.item()))

在这里插入图片描述

损失值越来越小,准确率越来越高,这就是我们想要的结果。

9.保存模型

torch.save(model.state_dict(), '/mymodel.pt')

就这么简单。model.state_dict()就是训练完的w和b, '/mymodel.pt’就是要保存的路径和名称。

10.加载模型

这里我新建了一个python文件check_model.py

parameters = torch.load('/mymodel.pt')

先拿到之前模型的参数。
但我们要先把之前定义的网络结构搬回来。

model = nn.Sequential(
    nn.Linear(784, 555),
    nn.Sigmoid(),
    nn.Linear(555, 888),
    nn.Sigmoid(),
    nn.Linear(888, 888),
    nn.Sigmoid(),
    nn.Linear(888, 10),
    nn.Softmax()
)

然后再将参数塞进model

model.load_state_dict(parameters)

然后我们再用pandas加载数据, 拿出对应的标签和我们预测的值进行对比。

import torch
import torch.nn as nn
import pandas as pd

model = nn.Sequential(
    nn.Linear(784, 555),
    nn.Sigmoid(),
    nn.Linear(555, 888),
    nn.Sigmoid(),
    nn.Linear(888, 888),
    nn.Sigmoid(),
    nn.Linear(888, 10),
    nn.Softmax()
)

parameters = torch.load('/mymodel.pt')

model.load_state_dict(parameters)


raw_df = pd.read_csv('dataset/train.csv')
# 标签
label = raw_df['label'].values
# 特征
feature = raw_df.drop(['label'], axis=1).values
test_feature = feature[int(len(feature)*0.8):]
test_label = label[int(len(label)*0.8):]
test_feature = torch.tensor(test_feature).to(torch.float)
test_label = torch.tensor(test_label)

new_test_feature = test_feature[100:111]
new_test_label = test_label[100:111]

predict = model(new_test_feature)
result = torch.argmax(predict, axis=1)
print(new_test_label)
print(result)

在这里插入图片描述
预测结果正常,有六个预测正确,因为之前的trainning里面只有0.5左右的正确率,有可能训练的次数有关,训练次数太少。所以这个结果符合我们预期。

11.使用GPU加速

有人会问,我们已经装好了GPU版本的pytorch,为什么还要GPU加速。因为我们默认是用CPU运行,我们需要对代码再进行GPU调用。
使用GPU加速主要可以用两个方向,model方向和数据方向

首先,要将model(model里面的参数w和b)从内存放到显存。

model = model.cuda() 

第二,把加载的数据从内存加载到显存

train_feature = torch.tensor(train_feature).to(torch.float).cuda() 
train_label = torch.tensor(train_label).cuda() 
test_feature = torch.tensor(test_feature).to(torch.float).cuda() 
test_label = torch.tensor(test_label).cuda() 

只要将模型的数据,测试数据和训练数据加载到显存,自然会使用GPU进行处理。

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

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

相关文章

高性能现代PHP全栈框架 Spiral

概述 Spiral Framework 诞生于现实世界的软件开发项目是一个现代 PHP 框架&#xff0c;旨在为更快、更清洁、更卓越的软件开发提供动力。 特性 高性能 由于其设计以及复杂精密的应用服务器&#xff0c;Spiral Framework框架在不影响代码质量以及与常用库的兼容性的情况下&a…

运维高级课作业三

源码编译安装httpd 2.4 首先下载好httpd-2.4.62.tar.bz2的安装包 将这个文件传入Linux中 将他解归档解入/usr/src/ rpm -e httpd --nodeps # 如果系统自带httpd这个软件要删除掉&#xff0c;两个软件不能同时运行 yum -y install apr apr-devel cyrus-sasl-devel expat-dev…

.Net8 Avalonia跨平台UI框架——<vlc:VideoView>控件播放海康监控、摄像机视频(Windows / Linux)

一、UI效果 二、新建用户控件&#xff1a;VideoViewControl.axaml 需引用&#xff1a;VideoLAN.LibVLC.Windows包 Linux平台需安装&#xff1a;VLC 和 LibVLC &#xff08;sudo apt-get update、sudo apt-get install vlc libvlccore-dev libvlc-dev&#xff09; .axaml 代码 注…

【HM-React】08. Layout模块

基本结构和样式reset 结构创建 实现步骤 打开 antd/Layout 布局组件文档&#xff0c;找到示例&#xff1a;顶部-侧边布局-通栏拷贝示例代码到我们的 Layout 页面中分析并调整页面布局 代码实现 pages/Layout/index.js import { Layout, Menu, Popconfirm } from antd impor…

Canvas简历编辑器-选中绘制与拖拽多选交互方案

Canvas简历编辑器-选中绘制与拖拽多选交互方案 在之前我们聊了聊如何基于Canvas与基本事件组合实现了轻量级DOM&#xff0c;并且在此基础上实现了如何进行管理事件以及多层级渲染的能力设计。那么此时我们就依然在轻量级DOM的基础上&#xff0c;关注于实现选中绘制与拖拽多选交…

C# OpenCV机器视觉:转速测量

在一个看似平常却又暗藏神秘能量的日子里&#xff0c;阿杰正在他那充满科技感的实验室里&#xff0c;对着一堆奇奇怪怪的仪器发呆。突然&#xff0c;手机铃声如一道凌厉的剑气划破寂静&#xff0c;原来是工厂的赵厂长打来的紧急电话&#xff1a;“阿杰啊&#xff0c;咱们工厂新…

vue2制作长方形容器,正方形网格散点图,并且等比缩放拖动

需求&#xff1a;有个长方形的容器&#xff0c;但是需要正方形的网格线&#xff0c;网格线是等比缩放的并且可以无线拖动的&#xff0c;并且添加自适应缩放和动态切换&#xff0c;工具是plotly.js,已完成功能如下 1.正方形网格 2.散点分组 3.自定义悬浮框的数据 4.根据窗口大小…

0基础跟德姆(dom)一起学AI 自然语言处理13-注意力机制介绍2

1 注意力机制规则 它需要三个指定的输入Q(query), K(key), V(value), 然后通过计算公式得到注意力的结果, 这个结果代表query在key和value作用下的注意力表示. 当输入的QKV时, 称作自注意力计算规则&#xff1b;当Q、K、V不相等时称为一般注意力计算规则 例子&#xff1a;seq2…

慧集通(DataLinkX)iPaaS集成平台-系统管理之UI库管理、流程模板

UI库管理 UI库管理分为平台级和自建两种&#xff0c;其中平台级就是慧集通平台自己内置的一些ui库所有客户均可调用&#xff0c;自建则是平台支持使用者自己根据规则自己新增对应的UI库。具体界面如下&#xff1a; 自建UI库新增界面&#xff1a; 注&#xff1a;平台级UI库不支…

通过一个算法的设计来了解栈的一些应用

目录 1.前言 2.步骤 3.代码实现 4.测试 5.运行结果 6.一些思考 7.一些应用示例 1.前言 掌握堆栈的基本原理 掌握堆栈的存储结构 掌握堆栈的进栈、出栈&#xff1b; 判断栈空的实现方法 掌握应用堆栈实现括号匹配的原理和实现方法&#xff1b; 熟悉python语言编程 熟练…

USB 驱动开发 --- Gadget 驱动框架梳理(一)

本文由 Linux 内核文档翻译与总结而来&#xff0c;个人学习笔记仅供参考。 Gadget 框架 在 USB 协议交互过程中&#xff0c;角色定义&#xff1a; the device driver is the master (or “client driver”) Linux 内核中称为 HCD(Host Controller Driver)&#xff0c;负责与 …

字符串算法篇——字里乾坤,算法织梦,解构字符串的艺术(下)

文章目录 前言第一章&#xff1a;最长公共前缀1.1 题目链接&#xff1a;https://leetcode.cn/problems/longest-common-prefix/description/1.2 题目分析&#xff1a;1.3 思路讲解&#xff1a;1.4 代码实现&#xff1a; 第二章&#xff1a;最长回文子串2.1 题目链接&#xff1a…

计算机网络 笔记 数据链路层3(局域网,广域网,网桥,交换机)

局域网: LAN:在某一区域内由多台计算机互联成的计算机组&#xff0c;使用广播信道 特点&#xff1a; 覆盖范围有限&#xff1a;通常局限在几千米范围内&#xff0c;比如一栋办公楼、一个校园或一个工厂等相对较小的地理区域。 数据传输速率高&#xff1a;一般能达到 10Mbps…

istio-proxy oom问题排查步骤

1. 查看cluster数量 cluster数量太多会导致istio-proxy占用比较大的内存&#xff0c;此时需检查是否dr资源的host设置有配置为* 2. 查看链路数据采样率 若采样率设置过高&#xff0c;在压测时需要很大的内存来维护链路数据。可以调低采样率或增大istio-proxy内存。 检查iop中…

fast-crud select下拉框 实现多选功能及下拉框数据动态获取(通过接口获取)

教程 fast-crud select示例配置需求:需求比较复杂 1. 下拉框选项需要通过后端接口获取 2. 实现多选功能 由于这个前端框架使用逻辑比较复杂我也是第一次使用,所以只记录核心问题 环境:vue3,typescript,fast-crud ,elementPlus 效果 代码 // crud.tsx文件(/.ts也行 js应…

Apache JMeter 压力测试使用说明

文章目录 一、 安装步骤步骤一 下载相关的包步骤二 安装 Jmeter步骤三 设置 Jmeter 工具语言类型为中文 二、使用工具2.1 创建测试任务步骤一 创建线程组步骤二 创建 HTTP 请求 2.2 配置 HTTP 默认参数添加 HTTP消息头管理器HTTP请求默认值 2.3 添加 查看结果监听器2.4 查看结果…

计算机网络 (40)域名系统DNS

前言 计算机网络域名系统DNS&#xff08;Domain Name System&#xff09;是互联网的基础技术之一&#xff0c;它负责将人类可读的域名转换为计算机用来通信的数字IP地址。 一、基本概念 DNS的主要目的是将域名解析或翻译为IP地址&#xff0c;使得用户可以通过简单易记的域名来访…

本地服务器Docker搭建个人云音乐平台Splayer并实现远程访问告别烦人广告

前言 大家好&#xff01;今天我要给大家分享的是如何在Ubuntu上用Docker快速搭建高颜值无广告的某抑云音乐播放器Splayer的详细流程&#xff0c;并且结合cpolar内网穿透工具实现远程访问。如果你是音乐爱好者&#xff0c;经常需要在外办公或旅行&#xff0c;这个教程绝对能让你…

黑马linux入门笔记(01)初始Linux Linux基础命令 用户和权限 实用操作

B站 黑马程序员 的视频 BV1n84y1i7td 黑马程序员新版Linux零基础快速入门到精通&#xff0c;全涵盖linux系统知识、常用软件环境部署、Shell脚本、云平台实践、大数据集群项目实战等 增强自控力 冥想慢呼吸绿色锻炼充分休息减少决策次数优先做重要的事情(早晨)融入强自控群控…

小程序组件 —— 31 事件系统 - 事件绑定和事件对象

小程序中绑定事件和网页开发中绑定事件几乎一致&#xff0c;只不过在小程序不能通过 on 的方式绑定事件&#xff0c;也没有 click 等事件&#xff0c;小程序中绑定事件使用 bind 方法&#xff0c;click 事件也需要使用 tap 事件来进行代替&#xff0c;绑定事件的方式有两种&…