之——最基础的神经网络
目录
杂谈
线性回归就是最简单的神经网络,多输入单输出,之所以叫回归正是因为如此,它更像是对于多个输入的一个结果预测,而不是像分类一样预测哪一个。
详细的原理可以看看佬的:
总结性的:
-
线性回归:
- 用途:线性回归用于建立输入特征(自变量)和输出目标(因变量)之间的线性关系。通常用于解决回归问题,即预测一个连续数值的输出。
- 模型:线性回归模型假设自变量与因变量之间存在线性关系。模型通常表示为 Y = aX + b,其中 Y 是因变量,X 是自变量,a 是斜率,b 是截距。
- 损失函数:线性回归通常使用均方误差(Mean Squared Error,MSE)作为损失函数,目标是最小化实际值与预测值之间的平方误差。
- 输出:线性回归输出连续数值,可以是任何实数。
-
Logistic回归:
- 用途:Logistic回归用于解决分类问题,其中目标是将输入特征映射到两个或多个类别中的一个。它通常用于二元分类,但也可以扩展到多类别分类。
- 模型:Logistic回归使用 logistic 函数(也称为 sigmoid 函数)来建模概率。模型输出是介于0和1之间的概率值。
- 损失函数:Logistic回归使用对数损失函数,通常称为交叉熵损失(Cross-Entropy Loss),以最小化实际类别和预测概率之间的差异。
- 输出:Logistic回归输出表示输入属于每个类别的概率,可以进行阈值化来进行二元分类。
-
感知机:
- 用途:感知机是一个简单的二元分类算法,用于将输入特征分为两个类别。感知机可以看作是神经网络的早期形式。
- 模型:感知机模型由权重和阈值组成,基于输入的线性组合来做出二元分类决策。如果线性组合大于阈值,则为一个类别,否则为另一个类别。
- 损失函数:感知机使用误分类点到决策边界的距离作为损失函数,目标是最小化误分类点的数量。
- 输出:感知机输出是二元的,表示输入属于两个类别之一。
区别:
-
主要区别在于应用和问题类型。线性回归用于回归问题,Logistic回归用于分类问题,而感知机也用于分类问题但是限于二元分类。
-
线性回归输出是连续值,而Logistic回归输出是表示概率的0到1之间的值。
-
在损失函数上,线性回归使用均方误差,Logistic回归使用交叉熵损失,感知机使用误分类点到决策边界的距离。
-
感知机是一个相对简单的模型,不能解决线性不可分的问题,而Logistic回归可以处理非线性关系,并且在实践中更常见。
正文
主要是代码实现,坚持手打
1.手撕
#%%
print("线性回归\n"
"线性模型,可以看做单层的神经网络或者神经元,y=w1x1+w2x2+b\n"
"神经网络最开始是从类人神经元开始的\n"
"比较真实值和预测值来不断进化模型\n"
"也就是建立所谓的损失函数")
#%%
print("基础优化方法\n"
"最常见的就是梯度下降,沿反梯度可以最小化损失函数值\n"
"小批量随机梯度下降,整个样本计算梯度计算太贵,所以一般都是随机采样小批量\n"
"批量大小这种就是超参数batch size,决定了一次使用多少样本来进行拟合计算"
"以及学习率")
#%%
print("线性回归从0开始"
"复杂模型一般情况是没有显示解的,所以通过迭代拟合实现")
import random
import torch
from d2l import torch as d2l
def synthetic_data(w,b,numof_exam):
x=torch.normal(0,1,(numof_exam,len(w)))
y=torch.matmul(x,w)+b
noise=torch.normal(0,0.01,y.shape)
y+=noise
return x,y.reshape((-1,1)) #-1自动行数,1列
true_w=torch.tensor([2.5,-3.6])
print(true_w)
true_b=1.1
print("start")
features,labels=synthetic_data(true_w,true_b,1000)
# print(features,labels)
print("第一个维度的特征和labels的图示")
d2l.plt.scatter(features[:,1].numpy(),labels.numpy(),1)
print("创建数据集迭代器")
def data_iter(batch_size,features,labels):
numof_exam=len(features)
indices=list(range(numof_exam))
#打乱索引
random.shuffle(indices)
#每隔batchsize个取一次样
for i in range(0,numof_exam,batch_size):
batch_indices=torch.tensor(indices[i:min(i+batch_size,numof_exam)])
yield features[batch_indices],labels[batch_indices] #yield每次暂停函数记录返回再继续执行,最后会返回一个结果列表
batch_size=10
for x,y in data_iter(batch_size,features,labels):
print("其中一个batch的样本和标签")
print(x,y)
break
#%%
#初始化待训练模型参数
print("初始化待训练模型参数")
w=torch.normal(0,0.01,(2,1),requires_grad=True)
print(w)
b=torch.zeros(1,requires_grad=True)
print(b)
#线性模型
def lin_model(X,w,b):
return torch.matmul(X,w)+b
#损失函数
def squared_loss(y_pre,y):
return (y.reshape(y_pre.shape)-y_pre)**2/2
#小批量梯度下降,优化算法
def sgd(params,lr,batch_size):
#更新参数不计算梯度,只使用之前计算的梯度
with torch.no_grad():
for param in params:
param-=lr*param.grad/batch_size #更新参数并求均值
param.grad.zero_() #梯度清零,否则默认累加
#%%
#开始训练
lr=0.02
num_epochs=3
net=lin_model
loss=squared_loss
for epoch in range(num_epochs):
for x,y in data_iter(batch_size,features,labels):
l=loss(net(x,w,b),y)
l.sum().backward() #反向传播计算梯度
sgd([w,b],lr,batch_size)
#每一个epoch的训练损失
print('with torch.no_grad():用于将计算图的梯度传播简化,隔绝不需要的部分,'
'可以理解为全体的detach')
with torch.no_grad():
train_l=loss(net(features,w,b),labels)
print(f'epoch{epoch+1},loss{train_l.mean()}')
print(w,b)
2.torch模块化
torch上场的简化版本
#%%###############################################################################
#torch上场
import numpy as np
import torch
from torch.utils import data #data module
from d2l import torch as d2l
true_w=torch.tensor([2.5,-3.6])
print(true_w)
true_b=1.1
print("1、生成数据集")
features,labels=synthetic_data(true_w,true_b,1000)
#dataloder 的使用,是针对dataset、dataframe类型的数据,生成迭代器
print("2、加载数据集生成批量迭代器")
def load_array(data_arrays,batch_size,is_train=True):
dataset=data.TensorDataset(*data_arrays)#转化为dataset
return data.DataLoader(dataset,batch_size,is_train)
batch_size=10
data_iter_new=load_array([features,labels],batch_size)
print(data_iter_new)
print("批量迭代器的调用实例")
next(iter(data_iter_new))
print('3、模型结构构建')
from torch import nn
#线性层,输入2输出1,Sequential是网络构建容器,可以理解为转载各个层的list
net=nn.Sequential(nn.Linear(2,1))
print('4、初始化模型参数')
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0)
print('5、定义损失函数')
loss=nn.MSELoss()
print('6、定义优化算法')
trainer=torch.optim.SGD(net.parameters(),lr=0.03)
print('7、开始训练')
num_epochs=3
for epoch in range(num_epochs):
for x,y in data_iter_new:
l=loss(net(x),y)
trainer.zero_grad()
l.backward() #损失的梯度计算之前默认会求sum
trainer.step() #模型参数更新
l=loss(net(features),labels)
print(f'epoch{epoch+1},loss{l:f}')
print(net[0].weight.data,net[0].bias.data)\
print("提到的优化方法有"
"优化算法的选择"
"学习率的动态调整"
"收敛的判断 ")
补充
之后会在softmax回归谈到logistic回归,就不多加以赘述。
线性回归在机器学习中具有重要地位,它是一种基本且经典的监督学习算法,通常用于解决回归问题。以下是线性回归在机器学习中的地位和关键特点:
基础模型: 线性回归是机器学习中最基础的模型之一。它建立了自变量(特征)与因变量(目标)之间的线性关系,通过拟合一条直线(对于简单线性回归)或一个超平面(对于多元线性回归)来进行预测。因此,它为理解和入门机器学习提供了良好的起点。
可解释性: 线性回归具有很高的可解释性,因为它的模型参数表示自变量与因变量之间的线性关系。这使得我们可以直观地理解不同特征对目标的影响程度,以及预测结果如何受到不同特征的影响。
广泛应用: 线性回归广泛应用于各种领域,包括经济学、社会科学、自然科学、工程学以及医学等。它可以用于预测房价、股市趋势、销售量、疾病发病率等各种连续性的数值预测问题。
基准模型: 线性回归常常被用作其他复杂模型的基准,用于比较新模型的性能。如果一个更复杂的模型不能显著优于线性回归,那么采用线性回归可能更为合适,因为它具有较低的计算复杂性和过拟合的风险。
拓展和改进: 虽然线性回归本身是一种简单的模型,但已经有很多拓展和改进的方法,如岭回归、Lasso回归、弹性网络等,用于应对线性关系假设的不足。这些方法允许在线性框架内进行正则化,以提高模型的性能和泛化能力。
机器学习教育: 线性回归通常是机器学习课程的一部分,因为它可以帮助学生理解基本的机器学习概念,如目标函数、损失函数、优化算法等。它也有助于培养数据分析和建模的思维方式。
尽管线性回归在处理复杂问题时可能过于简单,但它仍然是机器学习的重要组成部分,有助于建立坚实的基础知识,为进一步学习更高级的模型和技术奠定基础。