生成一维行向量
import torch
import numpy as np
np.linspace(-1,1,10)
torch.linspace(-1, 1, 10)
# 生成[-1,1]之间的均匀的10个数(行向量)
tensor是什么
tensor可以理解成PyTorch 版的多维数组。他可以是标量,一维数组(向量),二维数组(行向量,列向量,矩阵),也可以是多维数组
dim是tensor的第几维,按从大到小,称作:行,列,层,块,?,?
# 例如
>>> torch.tensor([1,2,3,4,5,6,7,8]).reshape(2,2,2).max(dim=0)
torch.return_types.max(
values=tensor([[5, 6],
[7, 8]]),
indices=tensor([[1, 1],
[1, 1]]))
# 这是三维张量,具有2列2行2层
# dim=0意味着,从层那个维度的方向,将tensor切成一层一层,并比较每层同一位置的数的大小
# dim=1意味着,从列那个维度的方向,将tensor切成一层一层,并比较每层同一位置的数的大小
一些tensor的例子
>>> torch.tensor(1) # 标量
tensor(1)
>>> torch.tensor([1,2,3,4]) # 1维,向量
tensor([1, 2, 3, 4])
>>> torch.tensor([1,2,3,4]).unsqueeze(0) # 2维,行向量
tensor([[1, 2, 3, 4]])
>>> torch.tensor([1,2,3,4]).unsqueeze(1) # 2维,列向量
tensor([[1],
[2],
[3],
[4]])
>>> torch.tensor([1,2,3,4]).reshape(2,2) # 2维,矩阵
tensor([[1, 2],
[3, 4]])
>>>
对tensor的一些操作(tensor的方法,属性等)
shape
查看张量的维度情况(a行b列c层d块......)
unsqueeze(n)
在tensor的第n维插入一个维度,以达到升维 的效果。
reshape(a,b,c...)
将tensor重塑成a*b*c*......的张量,原始张量中元素个数要等于a*b*c*.....
max() min()
无参数时,取tensor中的最大/最小值
dim=n时,从第n维方向,将tensor切成n-1维的小tensor,再对比小tensor同一位置的大小,最终产生两个n-1维的tensor,一个存放最大/最小值,一个存放最大/最小值位置的索引。如果keepdim=True,则最终产生两个n维的tensor.
numpy()
将tensor转换为numpy的多维数组(两者其实结构一致),以方便后续使用matplotlib画图
torch.cat([tensor...],dim=k)
将一堆n维的张量,在第k维方向上,拼成一个n+1维的张量
torch.cat(tensors, dim=k)
要求所有拼接的张量在非拼接维度上形状相同。
只有在
dim
维度上可以长度不同(可以拼接)其他维度必须相同,否则报错
torch.no_grad()
with torch.no_grad():
y_plot = model(x_plot_poly)
# 这个块内的前向传播将不会计算梯度
多项式回归的基本步骤
1.归一化训练集X和验证集Y
归一化就是让不同数量级的特征“在同一量级”,保证梯度下降稳定,加快收敛,提高算法效果。
以下是几种归一化的方法,各有特点
# Min-Max 归一化(0~1)
x_min = x.min()
x_max = x.max()
x_norm = (x - x_min) / (x_max - x_min)
# 作用:把数据线性映射到 [0,1]
# 特点:保留原始数据分布比例,但对异常值敏感
# 标准化(Z-score,均值0方差1)
x_mean = x.mean()
x_std = x.std()
x_std_norm = (x - x_mean) / x_std
# 作用:让数据均值为 0,方差为 1
# 特点:对异常值比 Min-Max 稳定,常用于机器学习和深度学习
# L1 / L2 范数归一化(向量归一化)
import torch.nn.functional as F
x_normalized = F.normalize(x, p=2, dim=1) # 每行归一化
# 作用:把向量长度归一化为 1
# 特点:常用于特征向量、文本特征、图像特征
2.将XY值升维成2维列向量
# 转为 PyTorch Tensor
X = torch.from_numpy(x_np).unsqueeze(1) # shape: (100,1) 100行,1列
Y = torch.from_numpy(y_np).unsqueeze(1) # shape: (100,1)
如果需要多项式拟合,则需要对X进行特征扩展
例如,对于y=w1x^2+w2x+b,则需要X_poly = torch.cat([X, X**2], dim=1)
拼成一个N行3列的tensor
3.根据权重的个数,构造一个线性的神经网络并初始化
model = nn.Linear(2, 1) # 2 个输入特征,1 个输出,默认自带偏置,即y=Wx+b中的b
# 画成图就是两个输入球连着一个输出球
# 可选:初始化权重为 1,偏置为 1
with torch.no_grad():
model.weight.fill_(1.0)
model.bias.fill_(1.0)
4.定义损失函数和优化器
loss_fn = nn.MSELoss(reduction='mean') # MSE为均方误差
# 除此之外还有其他损失函数计算方法,mean表示取平均值,sum表示求和
optimizer = optim.SGD(model.parameters(), lr=0.1, weight_decay=0.01)
# SGD指随机梯度下降(也有别的优化方法),lr是学习率
# 可以使用正则化以防止过拟合,正则化是在损失函数中加入正则项,只需要设置weight_decay即可
5.开始训练
总结上述步骤,现在我们有了:
训练集tensor: X_poly
验证集tensor:Y
神经网络:model
损失函数:loss_fn
优化器:optimizer
现在我们可以开始训练了
cost_history = []
for _ in range(num_epochs):
optimizer.zero_grad() # 清空梯度,不清空梯度,则每次前向计算,梯度都会累加,这不符合要求
y_pred = model(X_poly) # 前向计算
loss = 0.5 * loss_fn(y_pred, Y) # 用均方误差求当前损失
cost_history.append(loss.item()) # 记录当前损失值,以便后续观察损失变化情况
loss.backward() # 自动求梯度
optimizer.step() # 更新权重
6.取得训练后的权重和偏置,并画图对比
w = model.weight.detach().numpy().flatten() # 取权重向量
b = model.bias.item() # 取偏置
常用matplotlib画图功能
import numpy as np
import matplotlib.pyplot as plt
plt.scatter(X.numpy(), Y.numpy(), color='blue', label='Data Points')
# 画散点图,输入x轴数据和y轴数据,长度需一致,可自定义样式
plt.plot(x_plot.numpy(), y_plot.numpy(), color='red', label='Fitted Cubic Curve')
# 画折线图,输入x轴数据和y轴数据,长度需一致,可自定义样式
# 画隐函数
x = np.linspace(-2, 2, 400)
y = np.linspace(-2, 2, 400)
X, Y = np.meshgrid(x, y)
# 将长度分别为a,b的两个向量交织成两个a*b的矩阵,取两个矩阵的相同位置,便是网格上一点的坐标
Z = X**2 + Y**2 - 1 # 用生成好的网格矩阵设好隐函数
plt.contour(X, Y, Z, levels=[0], colors='blue') # levels=[0] 表示 f(X,Y)=0
plt.title('Cubic Regression with PyTorch')
plt.xlabel('x (normalized)')
plt.ylabel('y (normalized)')
# 设定标题,x轴标题,y轴标题
plt.grid()
# 打开/关闭网格,同时也可设置网格样式
plt.legend()
# 显示图例
plt.show()
# 显示图像窗口
Scikit-Learn机器学习库
这个库专为机器学习入门者开发,目前我们用它来进行数据集的生成与加载,常见使用方法如下
make_classification
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=100, n_features=2, n_classes=2)
# make_classification:生成样本数为 n_samples 的二维特征数据(X.shape = (n, 2)),标签 y.shape = (n,),值为 0/1。
# 二维特征数据中的一项,代表一个点,对应过去的标签,根据值的不同(0/1)而分为两类
# noise:噪声,噪声越大,整体越无序
X, y = make_moons(n_samples=500, noise=0.1, random_state=42)
# 生成月牙形决策边界的二维特征数据
X, y = make_circles(n_samples=500, noise=0.05, factor=0.5, random_state=42)
# 生成同心圆决策边界的二维特征数据 factor:同心圆间距比例