Tensor    

Tensor的索引和切片 

Tensor支持基本的索引和切片操作,不仅如此,它还支持ndarray中的高级索引(整数索引和布尔索引)操作。

torch.nonzero:用于返回非零的索引矩阵。

torch.where(condition, x, y): 判断condition的条件是否满足,当某个元素满足,则返回对应矩阵x相同位置的元素,否则返回矩阵y的元素。

Tensor的变换、拼接和拆分

PyTorch提供了大量的对Tensor进行操作的函数或方法,这些函数内部使用指针实现对矩阵的形状变换,拼接,拆分等操作,使得我们无须关心Tensor在内存的物理结构或者管理指针就可以方便且快速的执行这些操作。

Tensor.nelement(),Tensor.ndimension(),ndimension.size()可分别用来查看矩阵元素的个数,轴的个数(维度数)以及维度,属性Tensor.shape也可以用来查看Tensor的维度。

在PyTorch中,Tensor.reshape和Tensor.view都能被用来更改Tensor的维度。

它们的区别在于,Tensor.view要求Tensor的物理存储必须是连续的,否则将报错,而Tensor.reshape则没有这种要求。

但是,Tensor.view返回的一定是一个索引,更改返回值,则原始值同样被更改,Tensor.reshape返回的是引用还是拷贝是不确定的。

它们的相同之处都接收要输出的维度作为参数,切输出的矩阵元素个数不能改变,可以在维度中输入-1,PyTorch会自动推断它的数值。

torch.squeeze和torch.unsqueeze用来给Tensor去掉和添加轴(维度)。 torch.squeeze去掉维度为1的轴 torch.unsqueeze用于给Tensor的指定位置添加一个维度为1的轴。

torch.t和torch.transpose用于转置二维矩阵。这两个函数只接收二维Tensor,torch.t是torch.transpose的简化版。

转置矩阵

将矩阵的行列互换得到的新矩阵称为转置矩阵,转置矩阵的行列式不变。

     

对于高维度Tensor,可以使用permute方法来变换维度。

PyTorch提供了torch.cat和torch.stack用于拼接矩阵。

torch.cat(tensors, dim): tensors里不同张量对应的待拼接维度的size可以不一致,但是其他维度的size要保持一致。

torch.stack(tensors, dim):tensors里所有张量的维度要保持一致,否则会报错

区别: torch.cat会在dim的维度上进行合并,不会扩展出新的维度。

torch.stack则会在dim的维度上拓展出一个新的维度,然后进行拼接,该维度的大小为tensors的个数。

torch.split和torch.chunk用于拆分矩阵。 torch.chunk(input, chunks, dim):

chunks是均匀分割的份数,如果在进行分割的维度上的size不能被chunks整除,则最后一份tensor会略小(也可能为空)。

torch.split(input, split_size_or_sections, dim=0): torch.split()可以说是torch.chunk()的升级版,它不仅可以按份数均匀分割,还可以按特定的方案进行分割。 如果第二个参数是分割份数,这就和torch.chunk()一样了;

第二种是分割方案,是一个list类型的数据,待分割的张量将会被分割为len(list)份,每一份的大小取决于list中的元素。

import torch

a = torch.arange(9).view(3, 3)

# 基本索引

print(a[2, 2])

# 切片

print(a[1:, :-1])

# 带步长的切片

print(a[::2])

print(a[::2, ::2])

# 整数索引

rows = [0, 1]

cols = [2, 2]

print(a[rows, cols])

# 布尔索引

index = a > 4

print(index)

print(a[index])

a = torch.arange(9).view(3, 3)

index = torch.nonzero(a >= 8)

print(index)

a = torch.randint(0, 2, (3, 3))

print(a)

index = torch.nonzero(a)

print(index)

x = torch.randn(3, 2)

y = torch.ones(3, 2)

print(x)

print(torch.where(x > 0, x, y))

a = torch.rand(1, 2, 3, 4, 5)

print("元素个数", a.nelement())

print("轴的个数", a.ndimension())

print("矩阵维度", a.size(), a.shape)

b = a.view(2 * 3, 4 * 5)

print(b.shape)

c = a.reshape(-1)

print(c.shape)

d = a.reshape(2 * 3, -1)

print(d.shape)

b = torch.squeeze(a)

print(b.shape)

print(torch.unsqueeze(b, 0).shape)

a = torch.tensor([[2]])

b = torch.tensor([[2, 3]])

print(torch.transpose(a, 1, 0))

print(torch.t(a))

print(torch.transpose(b, 1, 0))

print(torch.t(b))

a = torch.rand((1, 224, 224, 3))

print(a.shape)

b = a.permute(0, 3, 1, 2)

print(b.shape)

a = torch.rand(2, 3)

b = torch.rand(3, 3)

# 默认维度为dim=0

c = torch.cat((a, b))

d = torch.cat((b, b, b), dim=1)

print(c.shape)

print(d.shape)

c = torch.stack((b, b), dim=1)

d = torch.stack((b, b), dim=0)

print(c.shape)

print(d.shape)

a = torch.randn(10, 3)

for x in torch.split(a, [1, 2, 3, 4], dim=0):

print(x.shape)

for x in torch.split(a, 4, dim=0):

print(x.shape)

for x in torch.chunk(a, 4, dim=0):

print(x.shape)

梯度下降

对于一个学习系统来说,我们需要找到最适合数据的模型,模型有很多,

需要不断尝试,其中最简单的一个模型就是线性模型。

 

我们需要去找到一个

w

的取值,使得 (

y ^

y

2

最小。

y=w

x

可以采用穷举法求最优值

w

   

梯度下降算法

需要去计算每个点的

梯度

梯度

即微分(导数)

>0:

函数上升,损失值在增大,

w

应该减小(梯度的反方向运动);

<0

:函数在下降,损失值在减小(目标方向),

w

应该增大(梯度的反方向运动)。

所以

参数

w

的更新方向应该是梯度的负方向!

    

在算法开始时会给参数

w

取一个初 始值 ,然后不断更新,想要找到一个全局

最优值,使得

cost最小。

훼:学习率。决定你每一步更新走多大步。一般取值很小:0.1、0.01。

注意:梯度下降算法是一种贪心算法,得到的解不一定是全局最优。 解决:

运行多次,随机化初始点。(SGD:随机梯度下降)梯度下降法的初始点也是一个超参数。

    鞍点:梯度为0的点。会导致梯度无法继续更新。

import numpy as np

import matplotlib.pyplot as plt

x_data = [1.0, 2.0, 3.0]

y_data = [2.0, 4.0, 6.0]

def forward(x):

return x * w

def loss(x, y):

y_pred = forward(x)

return (y_pred - y) ** 2

w_list = []

mse_list = []

for w in np.arange(0.0, 4.1, 0.1):

print("w=", w)

l_sum = 0

for x_val, y_val in zip(x_data, y_data):

y_pred_val = forward(x_val)

loss_val = loss(x_val, y_val)

l_sum += loss_val

print("\t", x_val, y_val, y_pred_val, loss_val)

print('MSE=', l_sum / 3)

w_list.append(w)

mse_list.append(l_sum / 3)

plt.plot(w_list, mse_list)

plt.ylabel('Loss')

plt.xlabel('w')

plt.show()

yn​=w∗xn​

cost(w)=:

损失曲线图

一般来说,用下图这种epoch、cost(loss)的损失值变化曲线来表示训练情况。

# 导入matplotlib.pyplot库,用于绘制损失函数随迭代次数的变化曲线。

import matplotlib.pyplot as plt

# 定义数据点x_data和y_data,以及初始权重w。

x_data = [1.0, 2.0, 3.0]

y_data = [2.0, 4.0, 6.0]

w = 1.0

# 定义前向传播函数forward(x),用于计算线性模型的预测值。

def forward(x):

return x * w

# 定义损失函数cost(xs, ys),用于计算预测值与实际值之间的平方误差之和。

def cost(xs, ys):

cost = 0

for x, y in zip(xs, ys):

y_pred = forward(x)

cost += (y - forward(x)) ** 2

return cost / len(xs)

# 定义梯度函数gradient(xs, ys),用于计算损失函数关于权重w的梯度。

def gradient(xs, ys):

grad = 0

for x, y in zip(xs, ys):

grad += 2 * x * (x * w - y)

return grad / len(xs)

# 初始化两个列表epoch_list和cost_list,用于存储每次迭代的迭代次数和损失值。

epoch_list = []

cost_list = []

# 打印训练前的预测值。

print('predict(beforo training)', 4, forward(4))

for epoch in range(100):

cost_val = cost(x_data, y_data) # 计算当前权重w对预测结果的影响,即损失值(cost)。

grad_val = gradient(x_data, y_data) # 计算损失函数关于权重w的梯度。

w -= 0.01 * grad_val # 0.01是学习率,控制每次迭代中权重更新的速度。

print("epoch", epoch, 'w=', w, 'loss', cost_val) # 打印当前迭代次数、权重w和损失值。

epoch_list.append(epoch)

cost_list.append(cost_val)

print('w=', w)

print('predict(beforo training)', 4, forward(4))

# 画图

plt.plot(epoch_list, cost_list)

plt.ylabel('cost')

plt.xlabel('epoch')

plt.show()

在20 epoch以前,模型快速收敛,后面趋于稳定,损失值接近0.这是理想的训练情况。损失值随着训练越来越小,逐渐收敛,这次训练就是成功的。如果损失值随着训练还逐渐增大了,那么训练就失败了!

随机梯度下降(Stochastic Gradient Descent) 梯度下降算法:用所有样本的平均损失值cost来更新参数; 随机梯度下降算法:随机选取N个样本中的一个样本的loss来更新参数!

随机梯度下降算法能够更好的解决鞍点问题,因为是随机选取一个样本的loss,可能会跨过鞍点继续更新。

import matplotlib.pyplot as plt # plt是常用的绘制图像的库

# 训练集数据

x_data = [1.0, 2.0, 3.0] # 输入特征

y_data = [2.0, 4.0, 6.0] # 对应的目标值

w = 1.0 # 初始化权重w为1.0

# 定义线性模型y=wx

def forward(x):

return x * w

# 定义损失函数:loss=(y_predict-y)2=(x*w-y)2

def loss(x, y):

y_pred = forward(x)

return (y_pred - y) ** 2

# 计算梯度SGD

def gradient(x, y):

return 2 * x * (x * w - y)

# 创建两个空列表,分别用于存储每个训练周期

epoch_list = []

loss_list = []

# 打印预测结果

print("predict(after training", 4, forward(4))

for epoch in range(100): # 循环

for x, y in zip(x_data, y_data): # 内层循环,遍历所有的训练数据对 (x, y)

grad = gradient(x, y) # 计算当前训练数据对 (x, y) 的梯度。

w = w - 0.01 * grad

print("\tgrad:", x, y, grad)

l = loss(x, y) # 计算当前训练数据对 (x, y) 的损失值。

print("epoch", epoch, "w=", w, "loss=", l)

epoch_list.append(epoch) # 将当前训练周期的编号添加到 epoch_list 列表中。

loss_list.append(l) # 将当前训练周期的损失值添加到 loss_list 列表中。

# 画图

print("predict(after training", 4, forward(4))

plt.plot(epoch_list, loss_list)

plt.ylabel('Loss') # 设置纵坐标轴

plt.xlabel('epoch') # 设置横轴

plt.show()

比较梯度下降                                                随机梯度下降 整个训练集的cost计算梯度                    一个样本的loss计算梯度 性能低                                                    性能高 时间复杂度低                                          时间复杂度高 有一种折中的方法,性能高,时间复杂度又低采用Batch(Mini-Batch)的方法进行训练。

这里的线性模型是

y=wx

,如果换成

y=wx+b

,上述计算过程会变吗?会

影响参数更新吗?

请写出对应的代码。

• x_data = [1.0,2.0,3.0]          

• y_data = [4.5,7.5,10.5]

import numpy as np

import matplotlib.pyplot as plt

# 数据

x_data = np.array([1.0, 2.0, 3.0])

y_data = np.array([4.5, 7.5, 10.5])

# 参数设置

learning_rate = 0.01

max_iter = 1000

# 初始化权重和偏置

w = 0.0

b = 0.0

# 存储损失值

losses = []

# 梯度下降算法

for epoch in range(max_iter):

# 计算预测值

y_pred = w * x_data + b

# 计算损失值

loss = np.mean((y_pred - y_data) ** 2) / len(x_data)

losses.append(loss)

#

# 为了最小化损失函数,我们需要计算损失函数对参数w和b的偏导数,即梯度dw和db。根据链式法则,我们有:

# dw = (∂L/ ∂w) = (∂L/ ∂y_pred) * (∂y_pred/ ∂w)

# db = (∂L/ ∂b) = (∂L/ ∂y_pred) * (∂y_pred/ ∂b)

# 由于y_pred = w * x_data + b,我们可以计算出:

# ∂y_pred /∂w = x_data

# ∂y_pred /∂b = 1

# 将这些代入上面的偏导数公式中,我们得到:

# dw = (∂L/ ∂y_pred) * x_data = (2 / n) * Σ(y_pred - y_data) * x_data

# db = (∂L/ ∂y_pred) * 1 = (2 / n) * Σ(y_pred - y_data)

#

# dw = (2 / n) * Σ(y_pred - y_data) * x_data

# db = (2 / n) * Σ(y_pred - y_data)

# 计算梯度

dw = np.mean((y_pred - y_data) * x_data)

db = np.mean(y_pred - y_data)

# 更新权重和偏置

w -= learning_rate * dw

b -= learning_rate * db

# 绘制损失值与epoch遍历次数的关系图

plt.plot(range(max_iter), losses)

plt.xlabel('Epoch')

plt.ylabel('Loss')

plt.show()

逻辑回归(Logistic Regression)

回顾:Linear Regression

线性回归是用于预测连续值,做预测;而逻辑回归是预测离散值,即是用来分类的。

分类任务

在机器学习领域,分类任务是监督学习中的一个重要分支,它涉及到将输入数据映射到预定义的类别标签。以下是对不同类型分类任务的概述:

二分类:这是最简单的分类任务,涉及将数据集分为两个类别,如垃圾邮件检测中的“垃圾”与“非垃圾”。多类别分类:当有两个以上的类别需要预测时,这种任务称为多类别分类,例如图像识别中的区分不同的物体类别。多标签分类:在某些情况下,一个实例可能同时属于多个类别,这类问题被称为多标签分类,如一篇文章可以同时被标记为“科技”和“新闻”。不平衡分类:在现实世界的数据集中,类别分布往往是不平衡的,即某个类别的样本数量远多于其他类别,这对分类模型的学习提出了挑战。分类方法:为了解决这些分类任务,研究者和工程师们开发了多种算法,包括决策树、支持向量机、神经网络等。每种方法都有其适用的场景和优势。评估指标:为了衡量分类模型的性能,通常会使用准确率、精确率、召回率、F1分数等指标。这些指标有助于了解模型在不同方面的性能,如正确分类的比例、误报的情况等。实际应用:分类任务广泛应用于各个领域,包括但不限于金融欺诈检测、医疗诊断、文本分类、情绪分析等。每个应用都需要根据其特定问题选择合适的算法和模型。深度学习:随着深度学习的发展,深度神经网络在处理复杂的分类任务,如图像和语音识别方面表现出色。深度学习模型能够自动提取高级特征,从而提高分类的准确性。模型选择和评估:在选择分类模型时,需要考虑问题的性质、数据的复杂性以及计算资源。一旦选择了合适的模型,就需要通过交叉验证等方法来评估其性能,确保模型在未知数据上的泛化能力。持续优化:分类模型通常需要根据新收集的数据不断进行调整和优化,以适应数据分布的变化和新的分类需求。伦理和公平性:在使用分类模型时,还需要考虑模型可能带来的偏见和不公平性问题,确保模型的决策过程是透明和公正的。         

回归VS分类      在之前的回归任务中,我们是预测分值是多少,在分类任务中就可以变成根据学习时间判断是否能通过考试,即结果分为两类:fail、pass。我们的任务就是计算不同学习时间x分别是fail、pass的概率。(二分类问题其实只需要计算一个概率;另一个概况就是1-算的概率) 如果预测pass概率为0.6,fail概率就是0.4,那么判断为pass。 在分类问题中,模型输出的就是输入属于哪一个类别的概率! 概率取值[0,1],预测值y_hat不一定在这个取值区间。因此我们需要把得到的预测值y_hat通过激活函数隐射为[0,1]区间。 

逻辑回归模型 只是在线性回归之后加了一个sigmoid激活函数!将值映射在【0,1】之间。                                                        损失函数 MSE loss:计算数值之间的差异 BCE loss:计算分布之间的差异                       

分析:如果y=1,1-y=0,loss=-log y_hat,需要loss尽可能小,那么y_hat就要尽可能大,即尽可能接近1. 如果y=0,1-y=1,loss=-log(1-y_hat),需要loss尽可能小,那么y_hat值越接近0越好。(log 1=0) 对数函数图:

Mini-Batch loss:BCE loss 求均值

# 导入所需要的库

import torch

import torch.nn.functional as F

import numpy as np

import matplotlib.pyplot as plt

# 定义数据集x_data和y_data

x_data = torch.Tensor([[1.0], [2.0], [3.0]])

y_data = torch.Tensor([[0], [0], [1]])

# 定义一个名为LogisticRegressionModel的类

class LogisticRegressionModel(torch.nn.Module): # 继承自torch.nn.Module

#

def __init__(self):

super(LogisticRegressionModel, self).__init__()

self.linear = torch.nn.Linear(1, 1)

# 定义了一个线性层self.linear,并在forward方法中使用sigmoid函数将线性层的输出转换为概率值。

def forward(self, x):

y_pred = F.sigmoid(self.linear(x)) # 多了一个sigmid函数

return y_pred

# 接下来创建一个实例模型

model = LogisticRegressionModel()

# 定义损失函数

criterion = torch.nn.BCELoss(size_average=False)

optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(1000): # 进行循环

y_pred = model(x_data) # 对输入数据x_data进行预测,得到预测结果y_pred

loss = criterion(y_pred, y_data)

print(epoch, loss.item()) # 输出当前的迭代次数(epoch)和对应的损失值 #loss.item()张量转化为标量

optimizer.zero_grad() # 将优化器的梯度缓存清零,以便在下一次迭代时重新计算梯度

loss.backward() # 执行反向传播算法,根据损失函数计算出每个参数的梯度

optimizer.step() # 计算出的梯度更新模型的参数

x = np.linspace(0, 10, 200) # 生成一个包含200个元素的等差数列,范围从0到10

x_t = torch.Tensor(x).view((200, 1)) # 将转换为tensor,变成200行,1列

y_t = model(x_t) # 将x_t作为输入传递给模型,得到输出y_t

y = y_t.data.numpy() # tensor转化为numpy形式

# 绘制图形

plt.plot(x, y)

plt.plot([0, 10], [0.5, 0.5], c='r') # 在概率=0.5时画一条红色直线

plt.xlabel('Hours') # 设置横坐标轴的标签为“Hours”

plt.ylabel('Probability of Pass')

plt.grid() # 添加网络线

plt.show()

用PyTorch实现Logistic回归

import matplotlib.pyplot as plt

import numpy as np

import torch

from torch import nn

from torch.distributions import MultivariateNormal

from torch import optim

#设置两张不同的均值向量和协方差居住

mu1 = -3 * torch.ones(2)

mu2 = 3 * torch.ones(2)

sigma1 = torch.eye(2) * 0.5

sigma2 = torch.eye(2) * 2

#各从两个多远高斯分布中生成100个样本

m1 = MultivariateNormal(mu1, sigma1)

m2 = MultivariateNormal(mu2, sigma2)

x1 = m1.sample((100,))

x2 = m2.sample((100,))

#设置正负样本的标签

y = torch.zeros((200,1))

y[100:] = 1

#组合、打乱样本

x = torch.cat([x1,x2],dim=0)

idx = np.random.permutation(len(x))

x = x[idx]

y = y[idx]

#绘制样本

plt.scatter(x1.numpy()[:,0],x1.numpy()[:,1])

plt.scatter(x2.numpy()[:,0],x2.numpy()[:,1])

plt.show()

#线性方程

D_in,D_out = 2,1

linear = nn.Linear(D_in,D_out,bias=True)

output = linear(x)

print(x.shape,linear.weight.shape,linear.bias.shape,output.shape)

def my_linear(x,w,b):

return torch.mm(x,w.t())+b

print(torch.sum((output - my_linear(x,linear.weight,linear.bias))))

#激活函数

sigmoid = nn.Sigmoid()

scores = sigmoid(output)

def my_sigmoid(x):

x = 1 / (1 + torch.exp(-x))

return x

print(torch.sum(sigmoid(output) - my_sigmoid(output)))

loss = nn.BCELoss()

loss(sigmoid(output),y)

def my_loss(x,y):

loss = - torch.mean(torch.log(x) * y + torch.log(1 - x)* (1 - y))

return loss

print(loss(sigmoid(output),y) - my_loss(my_sigmoid(output),y))

class LogisticRegression(nn.Module):

def __init__(self, D_in):

super(LogisticRegression,self).__init__()

self.linear = nn.Linear(D_in,1)

self.sigmoid = nn.Sigmoid()

def forward(self, x):

x = self.linear(x)

output = self.sigmoid(x)

return output

lr_model = LogisticRegression(2)

loss = nn.BCELoss()

print(loss(lr_model(x), y))

class MyModel(nn.Module):

def __init__(self):

super(MyModel,self).__init__()

self.linear1= nn.Linear(1,1,bias=False)

self.linear2= nn.Linear(1,1,bias=False)

def forward(self):

pass

for param in MyModel().parameters():

print(param)

#优化算法

optimizer = optim.SGD(lr_model.parameters(),lr=0.03)

batch_size = 10

iters = 10

for i in range(iters):

for j in range(int(len(x)%batch_size)):

input = x[i*batch_size:(j+1)*batch_size]

target = y[i*batch_size:(j+1)*batch_size]

optimizer.zero_grad()

output = lr_model(input)

l = loss(output,target)

l.backward()

optimizer.step()

#测试

output = lr_model(x)

# 计算模型精确率并输出

correct = (lr_model(x).round() == y).float().sum()

accuracy = correct / len(y)

print("模型精确率为:", accuracy.item())

#模型可视化

pred_neg = (output<=0.5).view(-1)

pred_pos = (output>0.5).view(-1)

plt.scatter(x[pred_neg,0],x[pred_neg,1])

plt.scatter(x[pred_pos,0],x[pred_pos,1])

w = lr_model.linear.weight[0]

b = lr_model.linear.bias[0]

def draw_decision_boundary(w,b,x0):

x1 = (-b - w[0] * x0) / w[1]

plt.plot(x0.detach().numpy(),x1.detach().numpy(),'r')

plt.show()

draw_decision_boundary(w,b,torch.linspace(x.min(),x.max(),50))

文章来源

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。
大家都在看: