limu|P8-9|线性回归、softmax回归

线性回归模型\(y = Xw + b + \epsilon\)
1、如何衡量模型质量?loss function损失函数——量化实际值和预测值之间的差距
可证:在高斯噪声的假设下,线性模型的最大似然估计 等价于 最小化均方误差(MSE)。证明在另一篇里写过:https://www.cnblogs.com/xjl-ultrasound/p/18305000
平方误差:
\(l^{(i)}(w,b) = \frac{1}{2}(\hat{y}^{(i)} - y^{(i)})^2\)
均方误差(在n个样本上的损失均值):
\(L(w,b) = \frac{1}{n}\sum_{i=1}^{n}l^{(i)}(w,b)\)
2、如何更新参数以提升模型质量?一步步去更新参数以降低loss,最后,找到一组参数,使loss最小化
常用的为“梯度下降”:
(1)即在loss function递减的方向上更新参数,以降低loss。已知梯度是函数值增加最快的方向,那么负梯度方向则是函数值下降最快的方向。所以,可沿着loss function的负梯度方向更新参数,使loss降低
(2)这里面每次更新参数时都涉及求loss function的梯度,如果每次都要遍历数据集,会很慢,常用小批量随机梯度下降(minibatch SGD),每次更新参数,随机抽取一个小批量B,去计算小批量的损失均值关于模型参数的导数,用原参数减去(学习率*导数)
(3)公式:\((w,b) \leftarrow (w,b) - \lambda\frac{\sum_{i\in{B}}\partial_{(w,b)}l^{(i)}(w,b)}{|B|}\)
(4)学习率lr和批量大小batch_size两个超参数:
lr太小——算太多次梯度,贵!
lr太大——容易走过头,不断震荡但loss未有效下降
这里小批量随机梯度下降,相当于每次用小批量的损失均值去近似整体的损失均值,以更新参数。但是,反直觉的是,batch_size小点反而利于收敛
batch_size小:1-noise大,对神经网络是好事,不易走偏,使得模型容忍度↑,更鲁棒,防过拟合;2-但若batch_size过小,每次计算量太小,不适合并行以最大化利用资源
batch_size大:1-太大的话可能模型不那么鲁棒;2-内存消耗大;3-一个batch内可能包含太多相似的样本,浪费计算

线性模型实现
不管是复杂还是简单的神经网络,实现过程都是模板化的:
1、数据集获取&读取
2、定义模型
3、初始化模型参数
4、定义损失函数
5、定义优化算法
6、定义评估指标
7、训练
8、预测、评估

第一步:数据集获取和读取
这一步是模板化的,以下给出的不是线性回归所用的数据集,线性回归用的数据是自己生成的
公共数据集+DataLoader读取,如下:

def load_data_fashion_mnist(batch_size, resize=None):  #@save"""下载Fashion-MNIST数据集,然后将其加载到内存中"""trans = [transforms.ToTensor()]if resize:trans.insert(0, transforms.Resize(resize))trans = transforms.Compose(trans)mnist_train = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)mnist_test = torchvision.datasets.FashionMNIST(root="../data", train=False, transform=trans, download=True)return (data.DataLoader(mnist_train, batch_size, shuffle=True,num_workers=get_dataloader_workers()),data.DataLoader(mnist_test, batch_size, shuffle=False,num_workers=get_dataloader_workers()))

私有数据集(Dataset类)+DataLoader读取,如下:

from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
import os
from PIL import Imagebatch_size = 128
train_trans = transforms.Compose([transforms.ToPILImage(), # 如果用Image.open打开(如下),这行不需要transforms.RandomHorizontalFlip(),transforms.RandomRotation(15),transforms.ToTensor(),])
test_trans = transforms.Compose([transforms.ToPILImage(),  # 如果用Image.open打开(如下),这行不需要transforms.ToTensor(),]) 
# 测试集不需要翻转或旋转图片
# 注意ToTensor会把channel提到第一维
# 还可按需加入Resizeclass Mydata(Dataset):def __init__(self, root_dir, label_dir, trans = None):self.root_dir = root_dirself.label_dir = label_dirself.path = os.path.join(self.root_dir, self.label_dir)self.img_path = os.listdir(self.path) # 获取path路径下所有子文件(图像)的名称self.trans = transdef __getitem__(self, idx):img_name = self.img_path[idx] img_item_path = os.path.join(self.root_dir, self.label_dir, img_name)img = Image.open(img_item_path) # Image.open返回PIL类型,还可以用cv2.imread(),返回ndarray类型if self.transform is not None:img = self.transform(img)label = self.label_dirreturn img, labeldef __len__(self):return len(self.img_path)root_tr = r'D:\ai-learning\pytorch\hymenoptera_data\train' # train文件夹
benign_label_dir = "benign"
malignant_label_dir = "malignant"
benign_tr = Mydata(root_tr, benign_label_dir, trans=train_trans)
malignant_tr = Mydata(root_tr, malignant_label_dir, trans=train_trans)
tr_dataset = benign_tr + malignant_tr
# 同理可得te_datasettr_iter = DataLoader(tr_dataset, batch_size=batch_size, shuffle=True, num_workers=0)
# te_iter = DataLoader(te_dataset, batch_size=batch_size, shuffle=False, num_workers=0)

Image.open和cv2.imread区别:https://www.cnblogs.com/ElaineTiger/p/18138084

第二步:定义线性模型

from torch import nn
net = nn.Sequential(nn.Linear(2, 1))
# nn.Sequential理解为list of layers

第三步:初始化模型参数

net[0].weight.data.normal_(0, 0.01) # 访问net中第一层的参数weight,进行初始化
net[0].bias.data.fill_(0)

第四步:定义损失函数
loss = nn.MSELoss()

第五步:定义优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.03)

训练

num_epochs = 3
for epoch in range(num_epochs):for X, y in data_iter: # 每个batch的数据拿出来l = loss(net(X) ,y) # net(X)算的预测值y'trainer.zero_grad() # 先把trainer(SGD)的梯度清零l.backward() # 算loss(损失均值)关于参数的梯度trainer.step() # 更新模型参数l = loss(net(features), labels) # X=features, y=labelsprint(f'epoch {epoch + 1}, loss {l:f}')

李沐老师的线性回归部分QA总结(QA绝对是精华)
一、求梯度时为什么是求损失均值关于模型参数的导数,即为什么损失要求均值?
使得梯度大小不受batch_size影响,这样调学习率的时候也不受batch_size影响。此外,因为可能出现最后一个batch内数据量不足batch_size的情况,SGD里是会自动帮你除以当前batch的size,而不是预设好的batch_size
二、调学习率的办法:
1、用对学习率没那么敏感的方法,如Adam,比较smooth
2、合理的参数初始化,使得学习率简单调调就行,,,
3、gridsearch
三、二阶导(牛顿法)收敛更快,为什么不用二阶导而用一阶导?
1、未必都能求二阶导
2、二阶导,计算量大,贵;易陷入局部最优
*真正的牛顿法做不了,但有的方法可以近似
3、我们不太关心收敛得快不快,更关心收敛得准不准
还有另一个思想:模型都是错的,但是有用。意思是,我们不可能得到精确的模型,这时候,什么最优解意义不大,快速准确的求解模型可能还不如大方向是正确的随机计算(粗糙拟合)好。。。比如用梯度解析解(只有线性模型有解析解)的泛化性不如SGD。。。
四、load数据时,如果数据很大,全部load进来,内存爆炸?
可以把数据放在硬盘里,每次取一个batch左右的数据
五:随机取batch,其实是把数据下标随机打乱,按顺序抽,能够保证一个epoch下来,取完全部的数据
六、数据总量不是batch_size大小的整数倍,怎么办?1-不咋办,就这样,最后一个batch小一点;2-最后一个小一点的batch直接扔掉;3-从下一个epoch采点数据,补全最后一个小一点的batch
七、怎么判断收敛?关系到epoch的大小
1、两个目标之间变化不大时
2、用一个验证集,其预测精度变化不大时
3、一般更常用的是,先凭直觉设置epoch大小,比如epoch=100,画学习曲线,再定epoch。从而对不同数据集形成经验

iter和for循环:
for循环的本质就是先通过__iter__这个方法获取可迭代对象的迭代器,然后对获取的迭代器进行不断调用__next_方法,来获取下一个值,并将其赋值给临时变量i(in前面的那个临时变量),当遇到StopIteration异常对象则终止循环。参考:https://blog.csdn.net/abraham_ly/article/details/107874466
——————————————————————————————————————
Softmax回归模型:即Softmax输出层
用于:多类别分类问题——只有1个正确答案——互斥输出
真实值(标签):one-hot encoding,一个向量,分量数=类别数,仅正确类别的分量为1,其余为0
预测值(预测概率和预测类别):全连接层(input_dim=上一层输出的feature数,output_dim=类别数)+ softmax(保证1-输出为概率,范围0-1;2-输出之和为1;3-模型保持可导),这样我们取概率最大的分量对应的类别为预测类别
softmax公式\(\hat{y} = softmax(o)\),其中,\(\hat{y_i} = \frac{exp(o_j)}{\sum_{k}\exp(o_k)}\)
损失函数:真实值和预测值均为概率模型,损失函数衡量两个概率模型之间的差异——交叉熵损失\(l(y,\hat{y}) = -\sum_{j=1}^{q}y_{j}log\hat{y_j}\)
——————————————————————————————————————
信息量、熵、KL散度、交叉熵
1、信息量

可以看出信息量公式需要满足:
(1)概率相乘变相加——需要log运算
(2)发生概率越小,获得信息量越大——加负号
(3)以几为底?无所谓,先以2为底(这样单位是比特)。如果以e为底,单位是纳特
即:
\(f(x) = -log_{2}x\)
信息量:一件事从不确定变为确定的难度。原来的概率x越小,难度越大,包含的信息量f(x)就越大
2、熵
熵:一个系统(中的所有事件)从不确定变为确定的难度。即所有事件信息量的加权和(期望),权重即为本事件发生的概率
因此,熵可以衡量一个系统(一个概率模型)的混乱程度=不确定程度
概率模型P的熵:\(H(P) = \sum_{i=1}^{m}p_{i}f(p_{i}) = \sum_{i=1}^{m}p_{i}(-log_{2}p_i)\)
3、KL散度、交叉熵
KL散度衡量两个概率模型之间的差距。比如\(D_{KL}(P\|{Q})\)以概率模型P为基准(谁写在前,以谁为基准),衡量概率模型P和Q之间的差距
\(D_{KL}(P\|{Q}) = \sum_{i=1}^{m}p_{i}(f_{Q}(q_i)-f_{P}(p_i)) = \sum_{i=1}^{m}p_{i}(-logq_i) - \sum_{i=1}^{m}p_{i}(-logp_i)\)
计算内容为 事件在Q中的信息量与在P中的信息量的差值的加权和(期望),权重为对应事件在P中的概率。最后得到,以概率模型P为基准时,概率模型P和Q之间的KL散度=交叉熵-在P系统的熵
4、把交叉熵作为损失函数的合理性
吉布斯不等式证明了KL散度一定≥0。当P和Q一样时,为0;不一样时,大于0
让模型P(真实模型)和模型Q(预测模型)尽可能接近 —— 让\(D_{KL}(P\|{Q})\)尽可能小(KL散度=交叉熵-在P系统的熵,而后一项已知不变)—— 让交叉熵尽可能小
因此,交叉熵可作为损失函数,衡量两个概率模型的接近程度。最小化交叉熵,可使真实模型和预测模型尽可能接近
5、任何指数族分布模型均满足:交叉熵的梯度 = 预测概率 - 真实概率
一方面,我们可以看到,梯度为0,交叉熵取最小值时,确实让预测概率和真实概率尽可能接近(相等)
另一方面,这个性质使得求解梯度变得简单
——————————————————————————————————————
代码实现:

import torch
from torch import nn
from d2l import torch as d2lclass Accumulator:  #@save"""在n个变量上累加"""def __init__(self, n):self.data = [0.0] * ndef add(self, *args):self.data = [a + float(b) for a, b in zip(self.data, args)]def reset(self):self.data = [0.0] * len(self.data)def __getitem__(self, idx):return self.data[idx]class Animator:  #@save"""在动画中绘制数据"""def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,ylim=None, xscale='linear', yscale='linear',fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,figsize=(3.5, 2.5)):# 增量地绘制多条线if legend is None:legend = []d2l.use_svg_display()self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)if nrows * ncols == 1:self.axes = [self.axes, ]# 使用lambda函数捕获参数self.config_axes = lambda: d2l.set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)self.X, self.Y, self.fmts = None, None, fmtsdef add(self, x, y):# 向图表中添加多个数据点if not hasattr(y, "__len__"):y = [y]n = len(y)if not hasattr(x, "__len__"):x = [x] * nif not self.X:self.X = [[] for _ in range(n)]if not self.Y:self.Y = [[] for _ in range(n)]for i, (a, b) in enumerate(zip(x, y)):if a is not None and b is not None:self.X[i].append(a)self.Y[i].append(b)self.axes[0].cla()for x, y, fmt in zip(self.X, self.Y, self.fmts):self.axes[0].plot(x, y, fmt)self.config_axes()display.display(self.fig)display.clear_output(wait=True)def accuracy(y_hat, y):  #@save"""计算预测正确的数量"""if len(y_hat.shape) > 1 and y_hat.shape[1] > 1: # 检查 y_hat 是否是一个二维张量,即有多个类的概率分布y_hat = y_hat.argmax(axis=1) # 找到每个样本预测概率最大的类别索引,y_hat 将变成一个一维张量,表示每个样本的预测类别cmp = y_hat.type(y.dtype) == y # y_hat和y相同位置元素比较,若一样,在cmp对应位置的元素为True,否则为Falsereturn float(cmp.type(y.dtype).sum())def evaluate_accuracy(net, data_iter):  #@save"""计算在指定数据集上模型的精度"""if isinstance(net, torch.nn.Module):net.eval()  # 将模型设置为评估模式,只做前向传递,不做梯度(反向传播)metric = Accumulator(2)  # 正确预测数、预测总数with torch.no_grad():for X, y in data_iter: # 累加器用于累加一个epoch的结果metric.add(accuracy(net(X), y), y.numel()) # 分类正确的样本数、总样本数;在下一句两者相除,得到精度return metric[0] / metric[1]def train_epoch_ch3(net, train_iter, loss, updater):  #@save"""训练模型一个迭代周期"""if isinstance(net, torch.nn.Module):net.train() # 将模型设置为训练模式,要计算梯度# 训练损失总和、训练准确度总和、样本数;因此用长度为3的迭代器累计信息metric = Accumulator(3)for X, y in train_iter:# 计算梯度并更新参数y_hat = net(X)l = loss(y_hat, y)if isinstance(updater, torch.optim.Optimizer):# 如果使用PyTorch内置的优化器和损失函数updater.zero_grad()l.mean().backward()updater.step()else:# 如果使用自定义的优化器和损失函数l.sum().backward()updater(X.shape[0])metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())# 返回训练损失和训练精度return metric[0] / metric[2], metric[1] / metric[2]def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):  #@save"""训练模型(定义见第3章)"""animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9],legend=['train loss', 'train acc', 'test acc'])for epoch in range(num_epochs):train_metrics = train_epoch_ch3(net, train_iter, loss, updater) # 训练test_acc = evaluate_accuracy(net, test_iter) # 测试animator.add(epoch + 1, train_metrics + (test_acc,)) # 可视化train_loss, train_acc = train_metricsassert train_loss < 0.5, train_lossassert train_acc <= 1 and train_acc > 0.7, train_accassert test_acc <= 1 and test_acc > 0.7, test_accdef predict_ch3(net, test_iter, n=6):  #@save"""预测标签(定义见第3章)"""for X, y in test_iter:breaktrues = d2l.get_fashion_mnist_labels(y)preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))titles = [true +'\n' + pred for true, pred in zip(trues, preds)]d2l.show_images(X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])# 读取数据
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) # 定义模型
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10)) 
# nn.Flatten用于将多维张量展平为二维张量(即,保持批量维度不变,将其余维度展平为一个维度)。常用于在卷积层和全连接层之间的转换#初始化权重
def init_weights(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);# 在交叉熵损失函数中传递未规范化的预测,并同时计算softmax及其对数,这样做可以防止溢出
loss = nn.CrossEntropyLoss(reduction='none') 
# nn.CrossEntropyLoss的reduction参数:1-默认为mean,对n样本的loss求均值;2-sum,对n样本的loss求和;3-none,直接返回n样本的loss
# 如果这里不使用默认的mean,则在d2l.train_ch3的设置里求梯度之前,要先求loss的mean,即l.mean().backward()#优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.1)#训练
num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)#预测
predict_ch3(net, test_iter)

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

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

相关文章

学习笔记-图灵完备、图灵机与Brainfuck

前言 本文是近日对图灵完备的学习所做的笔记,如有错误还请指正. 本文包含以下内容: 1.什么是图灵机?什么是图灵完备?什么是Brianfuck? 2.对图灵机的简单模拟. 3.使用Brianfuck模拟一个简单的图灵机. 图灵机? Alan Mathison Turing在1937年提出了一个通用计算设备的猜想.他猜…

帝国cms怎么整站迁移

帝国CMS整站迁移指南第一步:备份数据使用帝国CMS自带的备份功能,对网站数据进行完整备份,包括数据库、目录和文件。第二步:导入新数据库在新的服务器上,创建一个新的数据库,并导入之前备份的数据库。第三步:修改配置文件和数据库连接参数修改 config/config.php 和 data…

织梦dedecms怎么上传本地视频

如何使用 Dedecms 上传本地视频步骤 1:准备视频文件确保视频文件格式符合 Dedecms 支持的格式(例如 MP4、FLV、AVI)。 确定视频文件的存储位置,最好保存在本地电脑上。 步骤 2:打开 Dedecms 管理后台输入管理员账号密码登录 Dedecms 管理后台。 步骤 3:创建新的视频分类在…

帝国cms数据库如何批量替换字段值

UPDATE phome_ecms_news_data_1 SET newstext=REPLACE(newstext,原来,现在) 说明:phome_ecms_news_data_1为数据表名,可以改为任意数据表名,newstext为批量替换的字段。扫码添加技术【解决问题】专注中小企业网站建设、网站安全12年。熟悉各种CMS,精通PHP+MYSQL、HTML5、CS…

大小核溯源:parallelism 和 heterogeneity

ETH Computer Architecture Fall 2023 [1]课程笔记从 parallelism 到 heterogeneity Parallelism 加速的本质来自 Admals Law 和 Polloacks Rule。理想 N 核体系相比单核加速比遵守 \(s = \frac{1}{p+\frac{1-p}{N}}\), 但一味增加并行计算能力不仅边缘递减反而还会 degradati…

地铁站点客流量预测:随机森林极限梯度提升回归器XGBoost

全文链接: https://tecdat.cn/?p=37308 原文出处:拓端数据部落公众号 分析师:Xinyi He 随着城市化进程的加快,地铁作为城市公共交通的重要组成部分,其客流量管理与预测对于城市交通规划和资源配置具有重要意义。准确的客流量预测不仅有助于提高地铁运营效率,确保乘客安全…

项目文档管理利器:2024年你必须了解的工具

国内外主流的10款项目文档管理软件对比:PingCode、Worktile、Teambition、Tapd、Tower、Confluence、Notion、Dropbox Paper、Quip、Basecamp。在面对项目管理的复杂性时,选择合适的文档管理工具可以显著提高效率和团队协作。许多团队在文档管理上遭遇混乱和效率低下,尤其是…

做题小结 dp训练4

第一个 我按dp找 结果是个二分 我还想半天 这怎么dp 不过 这题目 也很有意义 首先我一直以为vector的low或者upp下标只能用distance求 现在看来是错的 不要再写auto 迭代器写法 用int就行 减初始指针就行 然后二分的话 思路也很好 先存进去 然后在跑t的时候 先开一个指针 然后对…

Modbus_RTU

本文主要记录串口通信,主要记录 modbus 的默认通信协议 modbus_RTU,当然modbus还包含 modbus_TCP(网口)和 modbus_ASCII(串口)。 一、基础知识 串口和网口串口:串口是一种物理接口,通常用于连接计算机和外部设备,如打印机、鼠标等。它使用一根线缆进行数据传输,常见的…

异步FIFO设计

Asynchronous FIFO Design总结来自Clifford E. Cummings论文 《Simulation and Synthesis Techniques for Asynchronous FIFO Design》一、设计难点使用格雷码计数时空和满的判断。 同步FIFO读写时钟相同,而异步FIFO读写来自不同两个读写时钟,需要考虑跨时钟域设计。二、设计…

常量的基础认知和相互转化

常量:在java程序运行过程中,其值不能够发送改变的量 分类:字面值常量:字符串常量:被双引号括起来的字符序列 "java"字符常量:被单引号括起来的单个字符 a整数常量:所有的整数 100 200 -100小数常量:所有的小数 1.23 3.14 -1.23布尔常量:true false空常…

.NET 窗口/屏幕录制

窗口/屏幕截图适用于截图、批注等工具场景,时时获取窗口/屏幕图像数据流呢,下面讲下视频会议共享桌面、远程桌面这些场景是如何实现画面录制的。 常见的屏幕画面时时采集方案,主要有GDI、WGC、DXGI。 GDI GDI(Graphics Device Interface)就是使用user32下WindowsAPI来实现…