深度学习本科课程 实验1 Pytorch基本操作

2024-02-05 19:28

本文主要是介绍深度学习本科课程 实验1 Pytorch基本操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、Pytorch基本操作考察

1.1 任务内容

  1. 使用 𝐓𝐞𝐧𝐬𝐨𝐫 初始化一个 𝟏×𝟑 的矩阵 𝑴 和一个 𝟐×𝟏 的矩阵 𝑵,对两矩阵进行减法操作(要求实现三种不同的形式),给出结果并分析三种方式的不同(如果出现报错,分析报错的原因),同时需要指出在计算过程中发生了什么
  2. ① 利用 𝐓𝐞𝐧𝐬𝐨𝐫 创建两个大小分别 𝟑×𝟐 和 𝟒×𝟐 的随机数矩阵 𝑷 和 𝑸 ,要求服从均值为0,标准差0.01为的正态分布;② 对第二步得到的矩阵 𝑸 进行形状变换得到 𝑸 的转置 𝑸^𝑻 ;③ 对上述得到的矩阵 𝑷 和矩阵$ 𝑸^𝑻 $求矩阵相乘
  3. 给定公式 y 3 = y 1 + y 2 = x 2 + x 3 y_3=y_1+y_2=x^2 + x^3 y3=y1+y2=x2+x3,且 x = 1 x=1 x=1。利用学习所得到的Tensor的相关知识,求 y 3 y_3 y3 x x x的梯度,即 d y 3 d x \dfrac{dy_3}{dx} dxdy3。要求在计算过程中,在计算 x 3 x^3 x3时中断梯度的追踪,观察结果并进行原因分析(可略)

1.2 任务思路及代码

步骤1: 矩阵生成与三种矩阵减法 ……

import torchX = torch.tensor([111,222,333])
Y = torch.tensor([[9999], [999]])
print(X)
print(Y)# 进行减法运算
temp1 = torch.tensor([10,10,10])
temp2 = torch.tensor([[10],[10]])
# 第一种方法
C1 = X - temp1
C2 = Y - temp2
print("-----1-----")
print(C1)
print(C2)
# 第二种方法
C1 = torch.sub(X, temp1)
C2 = torch.sub(Y, temp2)
print("-----2-----")
print(C1)
print(C2)
# 第三种方法
X.sub_(temp1)
Y.sub_(temp2)
print("-----3-----")
print(X)
print(Y)

实验结果分析
三种方法中, C = A - BC = torch.sub(A, B)原理基本一致, 即对两个尺寸相同的矩阵(如果尺寸不同, torch将尝试广播机制), 进行每个元素对应的减法

第三种方法A.sub_(B)被称作原地操作, 前两种方法创建了新的Tensor对象来保存结果, 而原地操作将计算结果保留在了原对象上

比较而言, 非原地操作产生了额外的内存开销, 而原地操作直接修改了原对象, 后者的缺点在于丢失了原始数据

步骤2: 矩阵转置与乘法

# step1: 服从正态分布的随机数矩阵生成
P = 0.01 * torch.randn(3,2)
Q = 0.01 * torch.randn(4,2)
print("Matrix P :")
print(P)
print("Matrix Q :")
print(Q)
print("-------")
print()# step2: 矩阵的转置
Q_T = Q.t()
print("Q矩阵转置前:")
print(Q)
print("Q矩阵转置后:")
print(Q_T)
print("-------")
print()# step3: 矩阵的乘法
result = torch.mm(P, Q_T)
print("乘法结果:")
print(result)

实验结果分析
注: 矩阵的乘法除了调用.mm()方式外, 还可以使用torch.matmul()以及C = A @ B

步骤3: 梯度计算

# 正常的梯度计算
x = torch.tensor(1.0, requires_grad = True)y1 = x**2
y2 = x**3
y3 = y1 + y2
y3.backward()
gradient = x.grad
print("梯度为", gradient)
# 在计算x**3时中断梯度跟踪
x = torch.tensor(1.0, requires_grad = True)y1 = x**2
with torch.no_grad():y2 = x**3
y3 = y1 + y2
y3.backward()
gradient = x.grad
print("梯度为", gradient)

实验结果分析
由本实验提供的公式来看, 显然x为自变量, 计算梯度时应该对x进行跟踪

在定义时需要在x=1.0的基础上提交requires_grad = True

按顺序输入公式, 最后调用backward()函数即可计算梯度值

若要实现终端梯度跟踪, 则使用with torch.no_grad()语句

在本实验中, 计算$ x^3 时中断跟踪 , 意味着放弃考虑 时中断跟踪, 意味着放弃考虑 时中断跟踪,意味着放弃考虑 x^3 $项对函数梯度的贡献

因此, 原本梯度值为2+3=5, 现在计算为2 = 2

二、实现 logistic 回归

2.1 任务内容

  1. 要求动手从0实现 logistic 回归(只借助Tensor和Numpy相关的库)在人工构造的数据集上进行训练和测试,并从loss以及训练集上的准确率等多个角度对结果进行分析
    (可借助nn.BCELoss或nn.BCEWithLogitsLoss作为损失函数,从零实现二元交叉熵为选作)
  2. 利用 torch.nn 实现 logistic 回归在人工构造的数据集上进行训练和测试,并对结果进行分析,并从loss以及训练集上的准确率等多个角度对结果进行分析
    ……

2.2 任务思路及代码

import numpy as np
from IPython import display
from matplotlib import pyplot as plt
import random
np.random.seed(0)
num_inputs = 2
num_examples = 1000
true_w = [2, -3.4]
true_b = 4.2
features = torch.tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype=torch.float)
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)
def use_svg_display():# 用矢量图显示    display.set_matplotlib_formats('svg')
def set_figsize(figsize=(3.5, 2.5)):use_svg_display()# 设置图的尺寸plt.rcParams['figure.figsize'] = figsize
set_figsize()
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1)
def data_iter(batch_size, features, labels):num_examples = len(features)indices = list(range(num_examples))random.shuffle(indices)  # 样本的读取顺序是随机的for i in range(0, num_examples, batch_size):j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)]) # 最后一次可能不足一个batchyield  features.index_select(0, j), labels.index_select(0, j)
def linreg(X, w, b):return torch.mm(X, w) + b
def squared_loss(y_hat, y):  return (y_hat - y.view(y_hat.size())) ** 2 / 2
def sgd(params, lr, batch_size):for param in params:param.data -= lr * param.grad / batch_size 
# 权重初始化
w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32)
b = torch.zeros(1, dtype=torch.float32)
# 迭代求参数
w.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True) # 模型训练
lr = 0.03
num_epochs = 3
batch_size = 10
net = linreg
loss = squared_loss
for epoch in range(num_epochs):       # 训练模型一共需要num_epochs个迭代周期# 在每一个迭代周期中,会使用训练数据集中所有样本一次for X, y in data_iter(batch_size, features, labels):# x和y分别是小批量样本的特征和标签l = loss(net(X, w, b), y).sum()     # l是有关小批量X和y的损失l.backward()     # 小批量的损失对模型参数求梯度sgd([w, b], lr, batch_size)     # 使用小批量随机梯度下降迭代模型参数w.grad.data.zero_()    # 梯度清零b.grad.data.zero_()train_l = loss(net(features, w, b), labels)print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item()))print(true_w, '\n', w)
print(true_b, '\n', b)

实验结果分析
经过3轮的迭代后, 模型损失度<0.01%, 说明模型预测值与实际值相差非常小

从模型训练得到的参数来看, w值和b值的差距<0.03%, 说明模型训练结果良好

步骤2

lr = 0.03
import torch.utils.data as Data
batch_size = 10
# 将训练数据的特征和标签组合
dataset = Data.TensorDataset(features, labels)
# 把 dataset 放入 DataLoader
data_iter2 = Data.DataLoader(dataset=dataset,      # torch TensorDataset formatbatch_size=batch_size,      # mini batch sizeshuffle=True,               # 是否打乱数据 (训练集一般需要进行打乱)num_workers=0,              # 多线程来读数据,注意在Windows下需要设置为0
)
from torch import nn
class LinearNet(nn.Module):def __init__(self, n_feature):super(LinearNet, self).__init__()self.linear = nn.Linear(n_feature, 1)# forward 定义前向传播def forward(self, x):y = self.linear(x)return ynet = LinearNet(num_inputs)
# 模型参数初始化
from torch.nn import initinit.normal_(net.linear.weight, mean=0, std=0.01)
init.constant_(net.linear.bias, val=0)   #也可以直接修改bias的data:net[0].bias.data.fill_(0)
# 选择损失函数
loss = nn.MSELoss()
# 选择优化算法(小批量随机梯度下降算法)
import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=0.03)  #梯度下降的学习率指定为0.03# 可以为不同的子网络设置不同学习率
# optimizer =optim.SGD([
#     # 如果不指定学习率,则用默认的最外层学习率
#     {'params': net.subnet1.parameters()}, # lr=0.03
#     {'params': net.subnet2.parameters(), 'lr': 0.01}
# ], lr=0.03)
num_epochs = 3
for epoch in range(1, num_epochs + 1):for X, y in data_iter2:output = net(X)l = loss(output, y.view(-1, 1))optimizer.zero_grad() # 梯度清零,等价于net.zero_grad()l.backward()optimizer.step()print('epoch %d, loss: %f' % (epoch, l.item()))
# 定义准确率计算函数
def accuracy(y_hat, y): return (y_hat.argmax(dim=1) == y).float().mean().item()
def evaluate_accuracy(data_iter, net):acc_sum, n = 0.0, 0for X, y in data_iter:acc_sum = acc_sum + (net(X).argmax(dim=1) == y).float().sum().item()n += y.shape[0]return acc_sum / n# 定义均方误差计算函数
def calMSE(y_hat, y):return ((y_hat - y)**2).float().mean().item()
def evaluate_MSE(data_iter, net):MSE_sum, n = 0.0, 0for X, y in data_iter:MSE_sum = calMSE(net(X).argmax(dim=1), y)n += y.shape[0]return MSE_sum / n# 定义平均绝对误差函数
def calMAE(y_hat, y):return torch.abs(y_hat - y).float().mean().item()
def evaluate_MAE(data_iter, net):MAE_sum, n = 0.0, 0for X, y in data_iter:MAE_sum = calMAE(net(X).argmax(dim=1), y)n += y.shape[0]return MAE_sum / n
print("本模型的准确率:")
print(evaluate_accuracy(data_iter2, net))
print("本模型的MSE:")
print(evaluate_MSE(data_iter2, net))
print("本模型的MAE:")
print(evaluate_MAE(data_iter2, net))

2.3 实验结果分析
经过3轮迭代, 模型损失度loss<0.01%, 说明模型预测值与样本实际值相差非常小

然而, 准确度计算结果为0, 说明预测值与实际值完全不相等, 这主要是因为本任务是回归问题而不是分类问题

$ y$ 与 $ \hat{y} $ 的值域是一个连续的区间, 而不是离散的类型, 准确率计算函数可能不适用

如下例所示, 一次抽样中每个对应的元素相差基本处于$ [-0.001, 0.001] $, 却被判定为预测错误, 显然不合理

for X, y in data_iter2:print(X, y)print(net(X))print(net(X).argmax(dim=1) == y)print((net(X).argmax(dim=1) == y).float().mean().item())break

因此, 需要用其他特征来评价线性回归模型, 如均方误差和均方误差

M S E ≈ 0.039 MSE \approx 0.039 MSE0.039
M A E ≈ 0.006 MAE \approx 0.006 MAE0.006

从两个误差值来看, 预测误差非常小, 模型预测效果良好, 正确率高

三、实现 softmax 回归

3.1 任务内容

  1. 要求动手从0实现 softmax 回归(只借助Tensor和Numpy相关的库)在Fashion-MNIST数据集上进行训练和测试,并从loss、训练集以及测试集上的准确率等多个角度对结果进行分析(要求从零实现交叉熵损失函数)

利用torch.nn实现 softmax 回归在Fashion-MNIST数据集上进行训练和测试,并从loss,训练集以及测试集上的准确率等多个角度对结果进行分析

3.2 任务思路及代码

步骤1

引入库

import torchvision
import torchvision.transforms as transforms
mnist_train = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST', train=True, download=True, transform=transforms.ToTensor())
mnist_test = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST', train=False, download=True, transform=transforms.ToTensor())batch_size = 256
num_workers = 0
train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)

创建Softmax回归模型

class SoftmaxRegression(nn.Module):def __init__(self, input_size, num_classes):super(SoftmaxRegression, self).__init__()self.linear = nn.Linear(input_size, num_classes)def forward(self, x):return self.linear(x)
[num_features, num_classes] = [784, 10]
model = SoftmaxRegression(num_features, num_classes)
model = model.to('cuda')

定义损失函数和优化器

def cross_entropy_loss(y_hat, y):# 计算Softmaxexp_y_hat = torch.exp(y_hat)softmax = exp_y_hat / exp_y_hat.sum(dim=1, keepdim=True)# 选择目标类别的概率batch_size = y.size(0)predicted_probs = softmax[torch.arange(batch_size), y]# 计算交叉熵损失loss = -torch.log(predicted_probs)return loss.mean()criterion = cross_entropy_loss
optimizer = optim.SGD(model.parameters(), lr=0.1)

训练模型

num_epochs = 500
for epoch in range(num_epochs):for X, y in train_iter:# 前向传播X = X.view(X.size(0), -1)X = X.to('cuda')y = y.to('cuda')outputs = model(X)loss = criterion(outputs, y)# 反向传播和优化optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 10 == 0:print("当前轮数: ", epoch+1, "Loss: ", loss.item())
print("训练完毕!")

步骤2

测试模型

def eval_Accuracy(data_iter, model):acc_sum, n = 0.0, 0for X, y in data_iter:X = X.view(X.size(0), -1)# X.to('cuda')# y.to('cuda')acc_sum = acc_sum + (model(X).argmax(dim=1) == y).float().sum().item()n += y.shape[0]return acc_sum / n
model.to('cpu')
print(eval_Accuracy(test_iter, model))

3.3 实验结果分析

经过500轮迭代, 损失度为0.37, 其值较小, 说明预测值和样本值基本符合而略有偏差, 训练过程中损失度没有明显的下降, 可能是训练轮次不足导致的

训练集大小为60000, 测试集大小为10000, 本次训练耗时2个小时

如果对模型进行更高轮次的训练, 时间开销可能会过大

检验准确度为0.8439, 说明模型对输入数据分类正确度较高, 预测效果良好

这篇关于深度学习本科课程 实验1 Pytorch基本操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/681915

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件