当前位置:网站首页>【深度学习】(问题记录)<对一个变量求梯度得到什么>-线性回归-小批量随机梯度下降
【深度学习】(问题记录)<对一个变量求梯度得到什么>-线性回归-小批量随机梯度下降
2022-07-30 09:03:00 【阿阿阿阿锋】
前言
博主主页:阿阿阿阿锋的主页_CSDN
原文链接:原文
看书看得感觉前言搭不上后语的时候,我常常忍不住怀疑是不是这书写得有点问题(有时甚至会在心里骂作者几句,怎么这么不小心)。然而经验和残留的理智仍然会提醒我,这大概率是我自己的问题。
我的编程环境:Win10操作系统,python3.6
初学不久,文章如有问题,欢迎指出。
1. 问题和代码
对于代码里sgd函数中的param[:] = param - lr * param.grad / batch_size这一行我一直十分困惑。
例如代码中设置了一个小批量是10个样本,于是我觉得对参数集params求梯度时,得到每个参数的梯度应该是向量(可以理解为一个数组)类型的数据。因为对于每个参数,通过10个样本求梯度就会得到10个相应的值。
于是我就产生了疑问,/ batch_size的目的是得到梯度的平均值,但它左边的被除数并不是一个标量(普通的单个的值),那这行代码怎么会得到我们想要的一个平均值呢?
注:代码参考自《动手学深度学习》
代码:
# 代码目标:训练一个线性回归模型,用小批量随机梯度下降法
%matplotlib inline
from IPython import display
from matplotlib import pyplot as plt
from mxnet import autograd, nd
import random
# 制作训练集
num_inputs = 2
num_examples = 1000
true_w = [2, -3.4]
true_b = 4.2
features = nd.random.normal(scale=1, shape=(num_examples, num_inputs))
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += nd.random.normal(scale=0.01, shape=labels.shape)
features[0], labels[0]
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].asnumpy(), labels.asnumpy(), 1); # 加分号只显示图(否则还会显示一行字)
# 本函数已保存在d2lzh包中方便以后使用
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 = nd.array(indices[i: min(i + batch_size, num_examples)])
yield features.take(j), labels.take(j) # take函数根据索引返回对应元素
batch_size = 10 # 一个“小批量”的大小
# 建立我们要训练的模型的参数
w = nd.random.normal(scale=0.01, shape=(num_inputs, 1))
b = nd.zeros(shape=(1,))
w.attach_grad()
b.attach_grad()
def linreg(X, w, b): # 我们的模型函数
return nd.dot(X, w) + b
def squared_loss(y_hat, y): # 使用的损失函数
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
def sgd(params, lr, batch_size): # 用于迭代(更新)参数
for param in params:
param[:] = param - lr * param.grad / batch_size
lr = 0.03 # 学习率
num_epochs = 3 # 学习周期个数
net = linreg # 取个小名
loss = squared_loss
for epoch in range(num_epochs): # 训练模型一共需要num_epochs个迭代周期
# 在每一个迭代周期中,会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。X
# X和y分别是小批量样本的特征和标签
for X, y in data_iter(batch_size, features, labels):
with autograd.record():
l = loss(net(X, w, b), y) # l是有关小批量X和y的损失
l.backward() # 小批量的损失对模型参数求梯度
sgd([w, b], lr, batch_size) # 使用小批量随机梯度下降迭代模型参数
train_l = loss(net(features, w, b), labels)
print('epoch %d, loss %f' % (epoch + 1, train_l.mean().asnumpy()))
print('\nweights:')
print(true_w, w)
print('\nbias:')
print(true_b, b)
2. 分析问题
在胡思乱想了一阵后,我突然想到,为何不把参数param的梯度打印出来看看呢?那它是个什么情况不就一目了然!请看代码:
def sgd(params, lr, batch_size): # 用于迭代(更新)参数
for param in params:
param[:] = param - lr * param.grad / batch_size
print('\nparam.grad:')
print(param.grad)
我仅仅在sgd函数尾部加了两行打印,那么我们再看一下效果(每处理一个小批量样本时都会调用一次该函数,看一次就够了,因为我只是想知道参数的梯度的数据类型)
运行效果:
前面的param.grad代表的是两个 权重(weight) 参数的梯度,后面的是 偏差(bias) 参数的梯度。也就是说,每个参数求得的梯度都只有一个值。
为什么一批10个样本,得到的只有一个值呢?
这个值是什么?其实在执行l.backward()时,等价于在执行l.sum().backward(),也就是对一批中每个样本都有一个梯度值,然后把这10个梯度值加起来,得到了参数的梯度值。所以再用/ batch_size求平均值也是一件很自然的事情。
其实我后面不久就看到了这个解释,但因为前面我就已经蒙圈了,看到这里的时候只是蒙圈++
🧭 总结
种瓜得瓜,种豆得豆。
变量是什么形状,对这个变量求得的梯度就是什么形状。
我之所以下意识地以为得到的会是一组值而不是一个值,是因为前面看了个对矩阵求梯度的例子,得到的是一组值(一个矩阵)。然后看到这里就混淆了,这里我们求梯度的每个参数对象是一个单个的值,只是数据样本有多个。
| 对矩阵(向量)求梯度 | 求得梯度是个矩阵(向量) |
|---|---|
| 对一个标量求梯度 | 求得梯度是个标量 |
我还有一个感受就是,作为一个之前惯用C/C++程序员,python变量数据类型的这种灵活性真的让我非常、非常的不适应,我多次因此而蒙圈了,呜。
边栏推荐
- [Yugong Series] July 2022 Go Teaching Course 021-Slicing Operation of Go Containers
- leetcode 剑指 Offer 10- I. 斐波那契数列
- 2022 Hangzhou Electric Multi-School 2nd Game
- Functional Interfaces & Lambda Expressions - Simple Application Notes
- HCIP --- MPLS VPN实验
- 瑞吉外卖项目(五) 菜品管理业务开发
- Explain the problem of change exchange in simple terms - the shell of the backpack problem
- PyQt5快速开发与实战 8.1 窗口风格
- Test automation selenium (a)
- Access to display the data
猜你喜欢

leetcode 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

How to use Jmeter to carry out high concurrency in scenarios such as panic buying and seckill?

瑞吉外卖项目(五) 菜品管理业务开发

20220728 Use the bluetooth on the computer and the bluetooth module HC-05 of Huicheng Technology to pair the bluetooth serial port transmission

2022 Hangzhou Electric Multi-School 2nd Game

Kotlin 值类 - value class

It is said that FPGA is high-end, what can it do?

leetcode 剑指 Offer 46. 把数字翻译成字符串

九九乘法表

Kotlin value class - value class
随机推荐
Integral Special Notes - Definition of Integral
Circuit analysis: constant current source circuit composed of op amp and triode
leetcode 剑指 Offer 10- I. 斐波那契数列
Unity性能分析 Unity Profile性能分析工具
快解析结合泛微OA
瑞吉外卖项目(五) 菜品管理业务开发
leetcode 剑指 Offer 22. 链表中倒数第k个节点
积分简明笔记-第一类曲线积分的类型
Jetpack Compose 从入门到入门(八)
20220728 Use the bluetooth on the computer and the bluetooth module HC-05 of Huicheng Technology to pair the bluetooth serial port transmission
快解析结合象过河erp
leetcode 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
LeetCode二叉树系列——94.二叉树的中序遍历
激活数据潜力 亚马逊云科技重塑云上存储“全家桶”
编程界的“躲猫猫”比赛 | 每日趣闻
初识Apifox——如何使用Apifox做一个简单的接口测试
HashSet and LinkedHashSet
342 · 山谷序列
HCIP - MPLS VPN experiment
用示波器揭示以太网传输机制