Pytorch深度学习指南 卷I --编程基础(A Beginner‘s Guide) 第1章 一个简单的回归

本章正式开始使用pytorch的接口来实现对应的numpy的学习的过程,来学习模型的实现,我们会介绍numpy是如何学习的,以及我们如何一步步的通过torch的接口来实现简单化的过程,优雅的展示我们的代码,已经我们的代码完成的事情

numpy的线性回归

在此之前,先看看现在的numpy实现的学习的过程是什么样的

#引入计算模块
import numpy as np
from sklearn.linear_model import LinearRegressionimport torch
import torch.optim as optim
import torch.nn as nn
from torchviz import make_dot用真实的数据来生成对应的分布点的数据
true_b = 1
true_w = 2
N = 100# Data Generation
np.random.seed(42)
x = np.random.rand(N, 1)
epsilon = (.1 * np.random.randn(N, 1))
y = true_b + true_w * x + epsilon
np.rand# Shuffles the indices
idx = np.arange(N)
np.random.shuffle(idx)# Uses first 80 random indices for train
train_idx = idx[:int(N*.8)]
# Uses the remaining indices for validation
val_idx = idx[int(N*.8):]# Generates train and validation sets
x_train, y_train = x[train_idx], y[train_idx]
x_val, y_val = x[val_idx], y[val_idx]np.random.seed(42)
b = np.random.randn(1)
w = np.random.randn(1)for _ in range(1000):# Step 1 - Computes our model's predicted output - forward passyhat = b + w * x_train# Step 2 - Computing the loss# We are using ALL data points, so this is BATCH gradient# descent. How wrong is our model? That's the error!error = (yhat - y_train)# It is a regression, so it computes mean squared error (MSE)loss = (error ** 2).mean()# Step 3 - Computes gradients for both "b" and "w" parametersb_grad = 2 * error.mean()w_grad = 2 * (x_train * error).mean()# Sets learning rate - this is "eta" ~ the "n" like Greek letterlr = 0.1# Step 4 - Updates parameters using gradients and # the learning rateb = b - lr * b_gradw = w - lr * w_grad#验证,通过线性的模型直接学习
linr = LinearRegression()
linr.fit(x_train, y_train)

如上一章所说,我们的5个步骤,就是准备数据,前向传递,计算损失,计算梯度,更新参数,循环往复

pytorch的取代

张量(通常指3维)但是这里除了标量全部都是张量,为了简化。

#如下是创建张量的例子
scalar = torch.tensor(3.14159)	#张量
vector = torch.tensor([1, 2, 3]) #一维
matrix = torch.ones((2, 3), dtype=torch.float) #二维
tensor = torch.randn((2, 3, 4), dtype=torch.float)	#三维

获取到张量的shape

shape将会是我们以后将会长期用到的东西

print(tensor.size(), tensor.shape)
torch.Size([2, 3, 4]) torch.Size([2, 3, 4])

view

我们可以使用view的接口来改变一个张量的shape,注意view并不会创建新的张量。

# We get a tensor with a different shape but it still is the SAME tensor
same_matrix = matrix.view(1, 6)
# If we change one of its elements...
same_matrix[0, 1] = 2.

创建新的tensor

使用这个可以使用new_tensor和clone

# We can use "new_tensor" method to REALLY copy it into a new one
different_matrix = matrix.new_tensor(matrix.view(1, 6))
# Now, if we change one of its elements...
different_matrix[0, 1] = 3.

使用clone.detach,为什么要用detach(涉及到后面的数据存放和计算的内容)

another_matrix = matrix.view(1, 6).clone().detach()

加载数据、设备、CUDA

我们需要从numpy的数据转成tensor张量

x_train_tensor = torch.as_tensor(x_train)
x_train.dtype, x_train_tensor.dtype

注意,这里变成了torch的张量,但是这里是还是共享的原始的内存,换句话说,改了还是会一起改

(dtype('float64'), torch.float64)

cuda的数据

cuda就是要使用GPU来存储和运算的数据,我们需要手动的将其放到GPU的内存中,用于加速计算的过程

#判断是否有GPU的数据可以使用的接口,如果存在那么设置device为GPU,否则CPU
device = 'cuda' if torch.cuda.is_available() else 'cpu'
#可以获取GPU的数量
n_cudas = torch.cudsa.device_count()
for i in range(n_cuda):print(torch.cuda.get_device_naem(i))

我的机器上的输出的结果

NVIDIA GeForce RTX 2060

将数据发送到GPU上

gpu_tensor = torch.as_tensor(x_train).to(device)
gpu_tensor[0]

输出

torch.cuda.FloatTensor

如果发送到了GPU上的数据,需要重新变成numpy的数组,需要使用CPU的变量

back_to_numpy = x_train_tensor.cpu().numpy()

创建参数,并且需要梯度计算

为什么要使用torch,很多的时候在于可以自行进行梯度计算,也可以使用到很多pytorch的使用的接口和用法

# 创建一个随机1以内的参数,并且需要梯度,类型是float
b = torch.randn(1, requires_grad=True, dtype=torch.float)
w = torch.randn(1, requires_grad=True, dtype=torch.float)
print(b, w)

创建数据并且发送到GPU,但是需要注意的是,这样会丢失梯度,因为这个是CPU的数据需要梯度,发送到GPU后又是新的数据,

b = torch.randn(1, requires_grad=True, dtype=torch.float).to(device)
w = torch.randn(1, requires_grad=True, dtype=torch.float).to(device)

好的方法是直接在GPU上创建变量

b = torch.randn(1, requires_grad=True, dtype=torch.float,device = device)
w = torch.randn(1, requires_grad=True, dtype=torch.float),device = device)

Autograd

自动求解梯度

backward

我们可以通过backward直接计算和进行backward的实现,注意b,w是我们创建的参数(需要梯度的那种)

# Step 1 - Computes our model's predicted output - forward pass
yhat = b + w * x_train_tensor# Step 2 - Computes the loss
# We are using ALL data points, so this is BATCH gradient descent
# How wrong is our model? That's the error! 
error = (yhat - y_train_tensor)
# It is a regression, so it computes mean squared error (MSE)
loss = (error ** 2).mean()# Step 3 - Computes gradients for both "b" and "w" parameters
# No more manual computation of gradients! 
# b_grad = 2 * error.mean()
# w_grad = 2 * (x_tensor * error).mean()
loss.backward()

需要说明的是,所有的参与到b,w的计算的都是需要梯度的参数,例如这里面的yhat,error,loss,都是通过w,b的计算得来的,我们都认为是传递了梯度的计算特性

需要特别注意的是,这里的梯度是累计的,因为为了后续的小批量的情况,所以每次更新完毕以后需要手动设置gard_zero_()函数

b.grad.zero_(), w.grad.zero_()

还需要特别注意的是,我们更新参数的时候,是不能直接更新的,需要使用

    with torch.no_grad():b -= lr * b.gradw -= lr * w.grad

这在停一下,除了前面的变量的配置不一样的地方,我们这里已经在改造我们的numpy代码了

	# 原来的numpy的梯度的计算需要手动计算# Step 3 - Computes gradients for both "b" and "w" parametersb_grad = 2 * error.mean()w_grad = 2 * (x_train * error).mean()#但是这里已经可以使用自动计算的方法loss.backward()#可以直接读取当前的梯度的值b.gradw.grad

动态计算图

可以使用动态计算图,直接看到当前的所有的梯度的变量的相互之间的关系,这里大家可以自己看,我就不放出来了

优化器

我们之前都要手动的执行backward,然后获取b,w的grad,然后手动的进行更新使用了learning rate,最后还需要zero_grad。我们可以通过优化器的方式将变量一开始就加入到优化器中

	optimizer = optim.SGD([b,w],lr = lr)#	....执行学习的步骤loss.backward()optimizer.step()#一次性更新所有的参数的变量optimizer.zero_grad()#一次性zero所有的变量的值

损失函数

实际上,我们的损失函数也有torch的封装,可以直接使用已经配置好的损失函数
loss_fn = nn.MSELoss(reduction = ‘mean’)

损失函数直接得到我们的yhat的结果和y_lable之间的损失的值

	#原文中的损失函数的部分error = (yhat - y_train_tensor)loss = (error**2).mean()#取代后loss_fn = nn.MSELoss(reduction='mean')loss = loss_fn(y_hat,y_train_tensor)此时的loss计算出来的结果和之前的是一模一样的

需要注意的是,如果此时需要回归的numpy,需要执行detach()操作,表示Loss函数不再参与grad的计算

模型

我们已经有了优化器(用于更新参数),损失函数(用于生成损失值),我们还可以定义自己的module模型(显然吗,我们还需要构建很多的我们自己的东西)

我们使用model函数来用现有的模型针对输入得到我们的输出函数,model函数对比forward函数,还会 前向和反向的钩子函数
我们声明一个继承与Module的自己的类

class ManualLinearRegression(nn.Module):def __init__(self):super().__init__()# To make "b" and "w" real parameters of the model,# we need to wrap them with nn.Parameterself.b = nn.Parameter(torch.randn(1,requires_grad=True, dtype=torch.float))self.w = nn.Parameter(torch.randn(1, requires_grad=True,dtype=torch.float))def forward(self, x):# Computes the outputs / predictionsreturn self.b + self.w * x

通过parameters的函数,我们可以得到一个module类的目前包含的参数

dummpy = ManualLinearRegression()
list(dummy.parameters)
[Parameter containing:tensor([0.3367], requires_grad=True), Parameter containing:tensor([0.1288], requires_grad=True)]

也可以state_dict来获取所有的参数的当前值,和parameters的区别在于state_dict通常用于加载和保存模型,而前面的通常用于展示优化器的包含的变量
注意,数据和模型需要在同一个设备

dummy = ManualLinearRegression().to(device)

阶段代码

经过我们的使用自己的类以后的代码可以优化如下

# Greek letter
lr = 0.1# Step 0 - Initializes parameters "b" and "w" randomly
torch.manual_seed(42)
# Now we can create a model and send it at once to the device
model = ManualLinearRegression().to(device)# Defines a SGD optimizer to update the parameters 
# (now retrieved directly from the model)
optimizer = optim.SGD(model.parameters(), lr=lr)# Defines a MSE loss function
loss_fn = nn.MSELoss(reduction='mean')# Defines number of epochs
n_epochs = 1000for epoch in range(n_epochs):model.train() # What is this?!?# Step 1 - Computes model's predicted output - forward pass# No more manual prediction,直接使yhat = model(x_train_tensor)# 一定注意这里使用的是model而不是forward# Step 2 - Computes the lossloss = loss_fn(yhat, y_train_tensor)# Step 3 - Computes gradients for both "b" and "w" parametersloss.backward()# Step 4 - Updates parameters using gradients and# the learning rateoptimizer.step()optimizer.zero_grad()# We can also inspect its parameters using its state_dict
print(model.state_dict())

model.train()

这个是配置了训练模式,训练模式可以有很多内容,例如我们常见的dropout的优化模式来减少过拟合的问题

嵌套模型

我们可以使用了已经有的模型来作为嵌套的模型

首先我们使用nn自带的Linear来取代我们手写的线性的Module,如下是一个具有一个权重w,和一个bias的线性模型,我们完全可以用这个来取代我们之前的手写的类

linear = nn.Linear(1,1)

当然我们可以嵌套这个到我们自己的类,这个和之前的基本上是完全等价的

class MyLinearRegression(nn.Module):def __init__(self):super().__init__()# Instead of our custom parameters, we use a Linear model# with single input and single outputself.linear = nn.Linear(1, 1)def forward(self, x):# Now it only takes a callself.linear(x)

序列模型

一个好的深度学习的模型,显然不只有一层,通常都会有很多隐藏层,将所有的封装子在一起,我们可以认为是一个序列模型

# Building the model from the figure above
model = nn.Sequential(nn.Linear(3, 5), nn.Linear(5, 1)).to(device)model.state_dict()

注意这里创建了一个序列类,序列类里面有两层,第一层是一个35的输出,第二层是一个51的模型,或者我们可以通过添加层的方式来增加带名字的层

# Building the model from the figure above
model = nn.Sequential()
model.add_module('layer1', nn.Linear(3, 5))
model.add_module('layer2', nn.Linear(5, 1))
model.to(device)

这里其实已经涉及到了深度学习的部分,pytorch的层只是很多例如
卷积层、池化层、填充层、非线性激活层、归一化层、循环层、transformer层、线性层、丢弃层、稀疏层、视觉层、数据平移(多GPU),展平层

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

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

相关文章

String.join()

String.join() 方法是 Java 8 及其以上版本中的一个方法,用于将多个字符串用指定的分隔符连接成一个字符串。 其语法为: java复制 String joinedString String.join(CharSequence delimiter, CharSequence... elements); 在这个方法中:…

FastAPI 数据库配置最佳实践

FastAPI 数据库配置最佳实践 1. 基础配置 1.1 数据库连接配置 from sqlalchemy import create_engine, event from sqlalchemy.orm import sessionmaker, declarative_base from sqlalchemy.pool import QueuePool from sqlalchemy.exc import SQLAlchemyError import loggi…

深度解析 Java 的幻读现象与应对策略

目录 一、幻读现象的本质 二、幻读在 Java 数据库编程中的体现 三、幻读带来的问题 四、应对幻读的策略 1. 数据库隔离级别 2. 应用层解决方案 五、总结 在 Java 的数据库编程领域,幻读是一个不容忽视的概念。它涉及到数据库事务处理过程中数据一致性的关键问…

Glary Utilities Pro 多语便携版系统优化工具 v6.21.0.25

Glary Utilities是一款功能强大的系统优化工具软件,旨在帮助用户清理计算机垃圾文件、修复系统错误、优化系统性能等。 软件功能 清理和修复:可以清理系统垃圾文件、无效注册表项、无效快捷方式等,修复系统错误和蓝屏问题。 优化和加速&…

【贪心算法】洛谷P1106 - 删数问题

2025 - 12 - 26 - 第 46 篇 【洛谷】贪心算法题单 - 【贪心算法】 - 【学习笔记】 作者(Author): 郑龙浩 / 仟濹(CSND账号名) 目录 文章目录 目录P1106 删数问题题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示思路代码 P1106 删数问题 题目描述 键盘输入一个高…

Oracle 创建并使用外部表

目录 一. 什么是外部表二. 创建外部表所在的文件夹对象三. 授予访问外部表文件夹的权限3.1 DBA用户授予普通用户访问外部表文件夹的权限3.2 授予Win10上的Oracle用户访问桌面文件夹的权限 四. 普通用户创建外部表五. 查询六. 删除 一. 什么是外部表 在 Oracle 数据库中&#x…

基于FPGA的BPSK+costas环实现,包含testbench,分析不同信噪比对costas环性能影响

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.Verilog核心程序 4.完整算法代码文件获得 1.算法仿真效果 本作品是之前作品的改进和扩展: 1.m基于FPGA的BPSK调制解调通信系统verilog实现,包含testbench,包含载波同步_csdn基于fpga的bpsk-CSDN博客 2.m基于FP…

Linux 目录操作详解

Linux目录操作详解 1. 获取当前工作目录1.1 getcwd()1.2 get_current_dir_name() 2. 切换工作目录2.1 chdir() 3. 创建和删除目录3.1 mkdir()3.2 rmdir() 4. 获取目录中的文件列表4.1 opendir() 打开目录4.2 readdir() 读取目录内容4.3 closedir() 关闭目录 5. dirent 结构体6.…

Spring 依赖注入详解:创建 Bean 和注入依赖是一回事吗?

1. 什么是依赖注入(Dependency Injection,DI)? 依赖注入 是 Spring IoC(控制反转)容器的核心功能。它的目标是将对象的依赖(如其他对象或配置)从对象本身中剥离,由容器负…

AI时代的网络安全:传统技术的落寞与新机遇

AI时代的网络安全:传统技术的落寞与新机遇 在AI技术飞速发展的浪潮中,网络安全领域正经历着前所未有的变革。一方面,传统网络安全技术在面对新型攻击手段时逐渐显露出局限性;另一方面,AI为网络安全带来了新的机遇&…

后端开发Web

Maven Maven是apache旗下的一个开源项目,是一款用于管理和构建java项目的工具 Maven的作用 依赖管理 方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题 统一项目结构 提供标准、统一的项目结构 项目构建 标准跨平台(…

前沿技术趋势洞察:2024年技术的崭新篇章与未来走向!

引言 时光飞逝,2024年已经来临,回顾过去一年,科技的迅猛进步简直让人目不暇接。 在人工智能(AI)越来越强大的今天,我们不再停留在幻想阶段,量子计算的雏形开始展示它的无穷潜力,Web …

【10.2】队列-设计循环队列

一、题目 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普…

博客之星2024年度总评选——我的年度创作回顾与总结

2024年,是我在CSDN博客上持续耕耘、不断成长的一年。在此,与大家分享一下我的年度创作回顾与总结。 一、创作成长与突破 在人工智能领域,技术迭代迅速,知识更新频繁。为了保持自己的竞争力,在今年,我始终…

IDEA运行Java项目总会报程序包xxx不存在

我的在另外一台电脑上跑是没有问题的,在新的电脑上跑的时候,又出现了这个恶心的问题...... 思来想去,唯一的问题就是我的mavn环境没的配置好 如何在本地部署mavn环境,这里推荐一篇很好的文章: Maven安装与配置&…

java 根据前端传回的png图片数组,后端加水印加密码生成pdf,返回给前端

前端传回的png图片数组,后端加水印加密码生成pdf,返回给前端 场景:重点:maven依赖controllerservice 场景: 当前需求,前端通过html2canvas将页面报表生成图片下载,可以仍然不满意。 需要java后…

数据分库分表和迁移方案

在我们业务快速发展的过程中,数据量必然也会迎来突飞猛涨。那么当我们的数据量百倍、千倍、万倍、亿倍增长后,原有的单表性能就不能满足我们日常的查询和写入了,此时数据架构就不得不进行拆分,比如单表拆分成10张表、100张表、单个…

线上突发:MySQL 自增 ID 用完,怎么办?

线上突发:MySQL 自增 ID 用完,怎么办? 1. 问题背景2. 场景复现3. 自增id用完怎么办?4. 总结 1. 问题背景 最近,我们在数据库巡检的时候发现了一个问题:线上的地址表自增主键用的是int类型。随着业务越做越…

[Java] Solon 框架的三大核心组件之一插件扩展体系

1、Solon 的三大核心组件 核心组件说明Plugin 插件扩展机制提供“编码风格”的扩展体系Ioc/Aop 应用容器提供基于注入依赖的自动装配体系ContextHandler 通用上下文处理接口提供“开放式处理”适配体系(俗称,三元合一) 2、Solon Plugin 插件…

TRELLIS微软的图生3D

TRELLIS 教程目录: Youtube:https://www.youtube.com/watch?vJqFHZ-dRMhI 官网地址:https://trellis3d.github.io/ GitHub:https://github.com/Microsoft/TRELLIS 部署目录: 克隆项目 git clone --recurse-submodul…