1 什么是pytorch?
PyTorch是一个基于Numpy的科学计算包,它主要有两个特点:第一,是GPU加速的张量计算;第二,是构建和训练神经网络的强大支持。PyTorch是Facebook人工智能研究团队开源的一个机器学习框架,它支持动态计算图,这意味着可以按照想要的方式定义、修改和执行计算图,而不是预先定义静态计算图。这样,PyTorch可以灵活地支持不同形式的计算图,并且非常适合用于研究和实验。同时,PyTorch也具有很好的可视化工具,方便用户对模型进行调试和优化。
2 张量
概念:几何代数中定义的张量是基于向量和矩阵的推广,比如我们可以将标量视为零阶张量,矢量可以视为一阶张量,矩阵就是二阶张量
2.1张量创建
import torch
# 创建一个2x3的张量
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 打印张量的形状和数据类型
print(x.shape) # 输出: torch.Size([2, 3])
print(x.dtype) # 输出: torch.int64
# 创建一个随机初始化的3x3浮点数张量
y = torch.rand(3, 3)
print(y)
# 创建一个随机初始化的3x3浮点数张量,符合正态分布
y = torch.randn(3, 3)
print(y)
# 创建一个全0的5x5张量
z = torch.zeros(5, 5)
print(z)
# 创建一个全1的4x4张量
w = torch.ones(4, 4)
print(w)
# 创建一个等差数列的张量
a = torch.linspace(0, 1, 5)
print(a)
# 创建一个随机整数的张量
b = torch.randint(low=0, high=10, size=(3, 3))
print(b)
x = x.new_ones(4, 3, dtype=torch.double)
# 创建一个新的全1矩阵tensor,返回的tensor默认具有相同的torch.dtype和torch.device
# 也可以像之前的写法 x = torch.ones(4, 3, dtype=torch.double)
print(x)
x = torch.randn_like(x, dtype=torch.float)
# 重置数据类型
print(x)
# 结果会有一样的size
# 获取它的维度信息
print(x.size())
print(x.shape)
2.2 张量的操作
import torch
# 创建两个张量
a = torch.tensor([[1, 2, 3], [4, 5, 6]])
b = torch.tensor([[2, 3, 4], [5, 6, 7]])
# 加法方式1
c = a + b
print(c)
# 方式2
print(torch.add(a, b))
# 方式3 in-place,原值修改
a.add_(b)
print(a)
# 减法
d = b - a
print(d)
# 乘法
e = a * b
print(e)
# 除法
f = b / a
print(f)
# 矩阵乘法
g = torch.matmul(a, b.T)
print(g)
# 求和
h = a.sum()
print(h)
# 求平均值
i = b.mean()
print(i)
# 求最大值
j = a.max()
print(j)
# 求最小值
k = b.min()
print(k)
# 如果x中只有一个元素,可以把x的数值取出来
print(type(x.item()))
# 怎么改变张量的形状
a = b.view(16)
c = a.view(-1, 8) # -1是指这一维的维数由其他维度决定
print(a.size(), b.size(), c.size())
# Torch Tensors和Numpy array 共享底层的内存空间,当改变其中的一个值,另外一个值也随之被改变
a = torch.ones(5);# 5个1
print (a)
b = a.numpy(); #将tensor 转 numpy array
print (b)
a.add_(1); #改变a的值
print (a);
print (b);
a = np.ones(5);
print (a)
b = torch.from_numpy(a); # 将numpy array 转tensor
print (b);
b.add_(1);
print (b);
print (a);
另外张量的计算时候需要注意在哪个设备上,若不同设备是不能参与计算的。
#判断服务器上已经安装了cuda和GPU
if torch.cuda.is_available():
#将设备指定为GPU
device = torch.device("cuda");
#直接在GPU创建张量y,在CPU上创建张量X
x = torch.randn(1);
y = torch.ones_like(x,device=device);
#将X转移到GPU上
x = x.to(device);
z = x.add(y); #此时和的结果z在GPU上
print (z);
print(z.to("cpu"),torch.double);
2.3 张量的实际意义
在电商中,通常需要对用户-品牌-时间-购买行为等多维数据进行建模和分析。这些数据可以被理解为张量的不同维度,每个维度都代表着不同的特征或属性。例如,假设我们需要对用户-品牌-时间-购买行为进行建模,我们可以构建一个四维张量来存储这些数据。其中,第一维表示用户,第二维表示品牌,第三维表示时间,第四维表示购买行为。张量中的每个元素则代表着对应维度上的具体数值,例如张量中[i, j, k, l]元素代表着第i个用户在第j个品牌上在第k个时间点的购买行为。
通过这种方式,我们可以在PyTorch中轻松地对这些张量进行各种数学操作和函数,例如对购买行为进行求和、求平均值、求最大值、求最小值等,或者对用户-品牌-时间进行矩阵运算,以便提取特征和进行预测。通过PyTorch中的张量,我们可以将复杂的电商数据转化为多维数组,从而更好地进行建模和分析,帮助电商企业实现数据驱动决策和智能化运营。
import torch
# 创建一个四维张量表示用户-品牌-时间-购买行为
tensor = torch.randn(10, 5, 20, 2)
# 求购买行为的总和
buy_sum = tensor[:, :, :, 1].sum()
print("购买行为总和:", buy_sum)
# 求用户-品牌的交叉统计
user_brand_count = tensor.sum(dim=2)
print("用户-品牌交叉统计:\n", user_brand_count)
# 对时间进行降维,求平均值
time_mean = tensor.mean(dim=2)
print("时间降维后的平均值:\n", time_mean)
# 对用户-品牌进行矩阵运算
user_brand_tensor = tensor[:, :, 0, :]
user_tensor = user_brand_tensor.sum(dim=1)
brand_tensor = user_brand_tensor.sum(dim=0)
user_brand_matrix = torch.matmul(user_tensor.T, brand_tensor)
print("用户-品牌矩阵:\n", user_brand_matrix)
上述代码中,我们首先创建了一个四维张量tensor,表示用户-品牌-时间-购买行为。然后,我们对这个张量进行了各种数学操作和函数。具体来说,我们使用sum()函数对购买行为进行求和,使用sum(dim=2)函数对用户-品牌进行交叉统计,使用mean(dim=2)函数对时间进行降维,使用matmul()函数对用户-品牌进行矩阵运算,以获得用户-品牌之间的相关性。这些操作可以帮助我们更好地理解和分析电商数据。
import torch
# 创建一个2x3的张量
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 创建一个1x3的张量
y = torch.tensor([10, 20, 30])
# 对x和y进行加法
z = x + y
print(z)
#输出如下
tensor([[1, 2, 3],
[4, 5, 6]])
tensor([10, 20, 30])
tensor([[11, 22, 33],
[14, 25, 36]])
在这个示例中,我们创建了一个2x3的张量x和一个1x3的张量y。两个张量在第一维上的形状不一致,但由于PyTorch支持广播机制,系统会自动地将y进行扩展,使得它的形状变为2x3,然后再和x进行加法运算。最终的结果是一个2x3的张量z,其中每个元素都是对应位置上x和y元素的和。在实际应用中,广播机制可以大大简化计算过程,避免了对数据进行显式的扩展和复制。例如,在深度学习中,广播机制可以使得模型对不同形状的输入数据进行处理,从而提高模型的通用性和适用性。同时,广播机制还可以使得模型的参数共享,从而减少模型的参数量,提高模型的训练效率。
3 自动求导和梯度
PyTorch中的自动求导机制是通过autograd模块实现的,该模块可以自动地对张量进行求导,同时还支持高阶求导和自定义求导函数。在PyTorch中,每个张量都有一个requires_grad属性,当设置为True时,表示需要对该张量进行求导。
下面是一个简单的示例,说明如何使用PyTorch中的自动求导机制
import torch
# 创建一个张量,并设置requires_grad=True
x = torch.tensor([2.0], requires_grad=True)
# 定义一个函数y=x^2+2x+1
y = x ** 2 + 2 * x + 1
# 对y进行求导
y.backward()
# 打印x的梯度
print(x.grad)
在这个示例中,我们创建了一个张量x,并将requires_grad属性设置为True,表示需要对它进行求导。然后,我们定义一个函数y=x^2+2x+1,并对它进行求导,即调用backward()函数。最后,我们打印x的梯度,即可得到y对x的导数,即4。这里的梯度,需要重点总结一下,梯度是指函数在某一点处的变化率,它是一个向量,包含了函数在每个自变量维度上的偏导数。
我们可以看一个稍微更复杂的函数,z= y^2 - x^2,那么z在自变量x上的倒数是-2x,在y自变量上的倒数是-2y。
import torch
# 创建一个张量,并设置requires_grad=True
x = torch.tensor([2.0], requires_grad=True)
y = torch.tensor([3.0], requires_grad=True)
# 定义一个函数z=y^2 - x^2
z = y ** 2 - x ** 2;
# 对y进行求导
z.backward()
# 打印x的梯度
print (z)
print(y.grad)
print(x.grad)
print ('x.requires_grad=',x.requires_grad,'y.requires_grad=',y.requires_grad,'z.requires_grad=',z.requires_grad)
# 输出
tensor([5.], grad_fn=<SubBackward0>)
tensor([6.])
tensor([-4.])
x.requires_grad= True y.requires_grad= True z.requires_grad= True
关于自动求导的”自动“怎么理解?z并没有指定requires_grad = true, 但是由于x和y被设置了,z也被自动的设置为了requires_grad = true。
4 线性回归模型
这段代码定义了一个简单的线性模型(LinearModel),并使用均方差损失函数(mean_squared_error)和梯度下降法(train)进行训练。训练数据是输入x_train和输出y_train。在训练过程中,首先通过正向传播(model.forward)计算模型的预测输出(y_pred),然后计算损失(loss),接着通过反向传播(计算梯度dW和db)更新模型的权重和偏置(model.W和model.b)。训练过程会迭代num_epochs次,每10次输出当前的损失值。最终训练得到的模型可以用于预测新的输入数据。
import torch
import numpy as np
# 模型定义
class LinearModel:
def __init__(self, input_size, output_size):
self.W = np.random.randn(input_size, output_size) # 随机初始化权重
self.b = np.zeros((output_size, 1)) # 初始化偏置
def forward(self, x):
return np.dot(x, self.W) + self.b
# 损失函数
def mean_squared_error(y_true, y_pred):
return np.mean((y_true - y_pred) ** 2)
# 训练过程
def train(model, x_train, y_train, learning_rate, num_epochs):
for epoch in range(num_epochs):
# 正向传播
y_pred = model.forward(x_train)
# 计算损失
loss = mean_squared_error(y_train, y_pred)
# 反向传播(梯度下降法更新参数)
dW = np.dot(x_train.T, (y_pred - y_train)) / x_train.shape[0] # 权重梯度
db = np.mean(y_pred - y_train, axis=0, keepdims=True).T # 偏置梯度
model.W -= learning_rate * dW
model.b -= learning_rate * db
if epoch % 10 == 0:
print(f"Epoch {epoch}, Loss: {loss}")
if __name__ == '__main__':
x_train = np.array([[1, 2, 3], [4, 5, 6]])
y_train = np.array([[3], [7]])
model = LinearModel(input_size=3, output_size=1)
train(model, x_train, y_train, learning_rate=0.01, num_epochs=100)
输出:
Epoch 0, Loss: 153.96475781916735
Epoch 10, Loss: 0.5371193011886801
Epoch 20, Loss: 0.49120240483116584
Epoch 30, Loss: 0.4497690875642887
Epoch 40, Loss: 0.41183070630810104
Epoch 50, Loss: 0.3770924577692135
Epoch 60, Loss: 0.34528440820059597
Epoch 70, Loss: 0.3161593929820811
Epoch 80, Loss: 0.28949109602634426
Epoch 90, Loss: 0.2650722911885265