mirror of
https://github.com/datawhalechina/llms-from-scratch-cn.git
synced 2026-10-13 12:37:26 +00:00
30 KiB
30 KiB
In [ ]:
import torch
# 显示PyTorch的版本
print(torch.__version__)2.0.1
In [ ]:
# 显示PyTorch是否是GPU版本,False表示CPU版本,True表示GPU版本
print(torch.cuda.is_available())False
In [3]:
import torch
import numpy as np
# 用Python整数创建一个0维张量
tensor0d = torch.tensor(1)
# 用Python列表创建一个1维张量(向量)
tensor1d = torch.tensor([1, 2, 3])
# 用Python列表创建一个2维张量(向量)
tensor2d = torch.tensor([[1, 2], [3, 4]])
# 用嵌套的Python列表创建一个3维张量
tensor3d_1 = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
# 从NumPy数组创建一个3维张量
ary3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
tensor3d_2 = torch.tensor(ary3d) # 复制NumPy数组
tensor3d_3 = torch.from_numpy(ary3d) # 与NumPy数组共享内存In [4]:
ary3d[0, 0, 0] = 999
print(tensor3d_2) # 保持不变tensor([[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]])
In [5]:
print(tensor3d_3) # 由于内存共享需要改变tensor([[[999, 2],
[ 3, 4]],
[[ 5, 6],
[ 7, 8]]])
In [6]:
tensor1d = torch.tensor([1, 2, 3])
print(tensor1d.dtype)torch.int64
In [7]:
floatvec = torch.tensor([1.0, 2.0, 3.0])
print(floatvec.dtype)torch.float32
In [8]:
floatvec = tensor1d.to(torch.float32)
print(floatvec.dtype)torch.float32
In [9]:
tensor2d = torch.tensor([[1, 2, 3], [4, 5, 6]])
tensor2dOut [9]:
tensor([[1, 2, 3],
[4, 5, 6]])In [10]:
tensor2d.shape # 张量形状Out [10]:
torch.Size([2, 3])
In [11]:
tensor2d.reshape(3, 2) # 修改形状Out [11]:
tensor([[1, 2],
[3, 4],
[5, 6]])In [12]:
tensor2d.view(3, 2) # 查看张量Out [12]:
tensor([[1, 2],
[3, 4],
[5, 6]])In [13]:
tensor2d.T # 转置张量Out [13]:
tensor([[1, 4],
[2, 5],
[3, 6]])In [14]:
tensor2d.matmul(tensor2d.T) # 张量乘法:tensor2d与其转置相乘Out [14]:
tensor([[14, 32],
[32, 77]])In [15]:
tensor2d @ tensor2d.T # 张量乘法的另一种实现方式:tensor2d与其转置相乘Out [15]:
tensor([[14, 32],
[32, 77]])In [16]:
import torch.nn.functional as F
y = torch.tensor([1.0]) # 真实样本
x1 = torch.tensor([1.1]) # 输入特征
w1 = torch.tensor([2.2]) # 权重变量
b = torch.tensor([0.0]) # 偏置单元
z = x1 * w1 + b # 网络输入
a = torch.sigmoid(z) # 激活函数 & 输出
loss = F.binary_cross_entropy(a, y)
print(loss)tensor(0.0852)
In [17]:
import torch.nn.functional as F
from torch.autograd import grad
y = torch.tensor([1.0])
x1 = torch.tensor([1.1])
w1 = torch.tensor([2.2], requires_grad=True)
b = torch.tensor([0.0], requires_grad=True)
z = x1 * w1 + b
a = torch.sigmoid(z)
loss = F.binary_cross_entropy(a, y)
grad_L_w1 = grad(loss, w1, retain_graph=True)
grad_L_b = grad(loss, b, retain_graph=True)
print(grad_L_w1)
print(grad_L_b)(tensor([-0.0898]),) (tensor([-0.0817]),)
In [18]:
loss.backward()# 反向传播
print(w1.grad)
print(b.grad)tensor([-0.0898]) tensor([-0.0817])
In [19]:
class NeuralNetwork(torch.nn.Module):
def __init__(self, num_inputs, num_outputs):
super().__init__()
self.layers = torch.nn.Sequential(
# 第一个隐藏层
torch.nn.Linear(num_inputs, 30),
torch.nn.ReLU(),
# 第二个隐藏层
torch.nn.Linear(30, 20),
torch.nn.ReLU(),
# 输出层
torch.nn.Linear(20, num_outputs),
)
def forward(self, x):
logits = self.layers(x)
return logitsIn [20]:
model = NeuralNetwork(50, 3)In [21]:
print(model)NeuralNetwork(
(layers): Sequential(
(0): Linear(in_features=50, out_features=30, bias=True)
(1): ReLU()
(2): Linear(in_features=30, out_features=20, bias=True)
(3): ReLU()
(4): Linear(in_features=20, out_features=3, bias=True)
)
)
In [22]:
num_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print("Total number of trainable model parameters:", num_params)# 打印训练模型的参数Total number of trainable model parameters: 2213
In [23]:
print(model.layers[0].weight) # 打印神经网络模型的第一层的权重Parameter containing:
tensor([[-0.0064, 0.0004, -0.0903, ..., -0.1316, 0.0910, 0.0363],
[ 0.1354, 0.1124, -0.0476, ..., 0.0578, 0.1014, 0.0008],
[ 0.0975, -0.0478, 0.0298, ..., 0.0416, 0.0849, 0.1314],
...,
[ 0.0118, 0.0240, 0.0420, ..., -0.1305, -0.0517, -0.0826],
[-0.0323, 0.1073, 0.0215, ..., -0.1264, -0.1100, 0.1232],
[ 0.0861, 0.0403, -0.0545, ..., 0.1352, 0.0817, -0.0938]],
requires_grad=True)
In [24]:
# 设置随机数种子,以确保可复现性
torch.manual_seed(123)
# 假设 NeuralNetwork 是一个神经网络类,且其构造函数接受两个参数,分别为输入特征的维度和输出特征的维度
model = NeuralNetwork(50, 3)
# 打印神经网络模型的第一层的权重
print(model.layers[0].weight)Parameter containing:
tensor([[-0.0577, 0.0047, -0.0702, ..., 0.0222, 0.1260, 0.0865],
[ 0.0502, 0.0307, 0.0333, ..., 0.0951, 0.1134, -0.0297],
[ 0.1077, -0.1108, 0.0122, ..., 0.0108, -0.1049, -0.1063],
...,
[-0.0787, 0.1259, 0.0803, ..., 0.1218, 0.1303, -0.1351],
[ 0.1359, 0.0175, -0.0673, ..., 0.0674, 0.0676, 0.1058],
[ 0.0790, 0.1343, -0.0293, ..., 0.0344, -0.0971, -0.0509]],
requires_grad=True)
In [25]:
# 打印神经网络模型的第一层权重的形状
print(model.layers[0].weight.shape)torch.Size([30, 50])
In [26]:
# 设置随机数种子,以确保可复现性
torch.manual_seed(123)
# 模型输入特征的维度为 50
X = torch.rand((1, 50))
# 使用模型进行前向传播计算输出
out = model(X)
# 打印输出结果
print(out)tensor([[-0.1262, 0.1080, -0.1792]], grad_fn=<AddmmBackward0>)
In [27]:
# 使用 torch.no_grad() 上下文管理器,以便在推断时不计算梯度
with torch.no_grad():
out = model(X)
print(out)tensor([[-0.1262, 0.1080, -0.1792]])
In [28]:
with torch.no_grad():
out = torch.softmax(model(X), dim=1)
print(out)tensor([[0.3113, 0.3934, 0.2952]])
In [29]:
# 定义输入特征张量 X_train
X_train = torch.tensor([
[-1.2, 3.1],
[-0.9, 2.9],
[-0.5, 2.6],
[2.3, -1.1],
[2.7, -1.5]
])
# 定义对应的标签张量 y_train
y_train = torch.tensor([0, 0, 0, 1, 1])In [30]:
X_test = torch.tensor([
[-0.8, 2.8],
[2.6, -1.6],
])
y_test = torch.tensor([0, 1])In [31]:
from torch.utils.data import Dataset
class ToyDataset(Dataset):
# 初始化 ToyDataset 类
def __init__(self, X, y):
self.features = X
self.labels = y
# 获取指定索引的数据
def __getitem__(self, index):
one_x = self.features[index]
one_y = self.labels[index]
return one_x, one_y
# 获取数据集的长度
def __len__(self):
return self.labels.shape[0]
# 创建训练数据集和测试数据集实例
train_ds = ToyDataset(X_train, y_train)
test_ds = ToyDataset(X_test, y_test)In [32]:
len(train_ds)Out [32]:
5
In [33]:
from torch.utils.data import DataLoader
torch.manual_seed(123)
# 创建训练数据加载器 train_loader
# dataset 参数传入了您定义的 ToyDataset 类的实例 train_ds
# batch_size 参数指定了每个批次包含的样本数量
# shuffle 参数指定是否在每个 epoch 之前对数据进行洗牌
# num_workers 参数指定用于数据加载的子进程数量
train_loader = DataLoader(
dataset=train_ds,
batch_size=2,
shuffle=True,
num_workers=0
)In [34]:
test_ds = ToyDataset(X_test, y_test)
# 创建测试数据加载器 test_loader
# dataset 参数传入了您定义的 ToyDataset 类的实例 test_ds
# batch_size 参数指定了每个批次包含的样本数量
# shuffle 参数指定是否在每个 epoch 之前对数据进行洗牌,这里设为 False 表示不洗牌
# num_workers 参数指定用于数据加载的子进程数量
test_loader = DataLoader(
dataset=test_ds,
batch_size=2,
shuffle=False,
num_workers=0
)In [35]:
# 迭代训练数据加载器 train_loader
for idx, (x, y) in enumerate(train_loader):
# 打印每个批次的索引、输入特征和对应的标签
print(f"Batch {idx+1}:", x, y)Batch 1: tensor([[ 2.3000, -1.1000],
[-0.9000, 2.9000]]) tensor([1, 0])
Batch 2: tensor([[-1.2000, 3.1000],
[-0.5000, 2.6000]]) tensor([0, 0])
Batch 3: tensor([[ 2.7000, -1.5000]]) tensor([1])
In [36]:
train_loader = DataLoader(
dataset=train_ds,
batch_size=2,
shuffle=True,
num_workers=0,
drop_last=True
)In [ ]:
for idx, (x, y) in enumerate(train_loader):
print(f"Batch {idx+1}:", x, y)In [38]:
import torch.nn.functional as F
torch.manual_seed(123)
model = NeuralNetwork(num_inputs=2, num_outputs=2)
optimizer = torch.optim.SGD(model.parameters(), lr=0.5)
num_epochs = 3
for epoch in range(num_epochs):
model.train()
for batch_idx, (features, labels) in enumerate(train_loader):
logits = model(features)
loss = F.cross_entropy(logits, labels) # 损失函数
optimizer.zero_grad()
loss.backward()
optimizer.step()
### 日志
print(f"Epoch: {epoch+1:03d}/{num_epochs:03d}"
f" | Batch {batch_idx:03d}/{len(train_loader):03d}"
f" | Train/Val Loss: {loss:.2f}")
model.eval()
# 可选的模型评估指标Epoch: 001/003 | Batch 000/002 | Train/Val Loss: 0.75 Epoch: 001/003 | Batch 001/002 | Train/Val Loss: 0.65 Epoch: 002/003 | Batch 000/002 | Train/Val Loss: 0.44 Epoch: 002/003 | Batch 001/002 | Train/Val Loss: 0.13 Epoch: 003/003 | Batch 000/002 | Train/Val Loss: 0.03 Epoch: 003/003 | Batch 001/002 | Train/Val Loss: 0.00
In [39]:
model.eval()
with torch.no_grad():
outputs = model(X_train)
print(outputs)tensor([[ 2.8569, -4.1618],
[ 2.5382, -3.7548],
[ 2.0944, -3.1820],
[-1.4814, 1.4816],
[-1.7176, 1.7342]])
In [40]:
# 设置 PyTorch 的打印选项,以关闭科学计数法
torch.set_printoptions(sci_mode=False)
# 假设 outputs 是模型的输出张量
# 对模型的输出进行 softmax 操作,计算类别概率
probas = torch.softmax(outputs, dim=1)
print(probas)
# 获取模型的预测结果,即具有最大概率的类别
predictions = torch.argmax(outputs, dim=1)
print(predictions)tensor([[ 0.9991, 0.0009],
[ 0.9982, 0.0018],
[ 0.9949, 0.0051],
[ 0.0491, 0.9509],
[ 0.0307, 0.9693]])
tensor([0, 0, 0, 1, 1])
In [41]:
# 使用 torch.argmax() 函数沿着 dim=1 维度获取每个样本最大值的索引,即模型的预测结果
predictions = torch.argmax(outputs, dim=1)
print(predictions)tensor([0, 0, 0, 1, 1])
In [42]:
predictions == y_trainOut [42]:
tensor([True, True, True, True, True])
In [43]:
torch.sum(predictions == y_train)Out [43]:
tensor(5)
In [44]:
def compute_accuracy(model, dataloader):
"""
计算模型在给定数据加载器上的准确率。
参数:
model (torch.nn.Module): 待评估的模型。
dataloader (torch.utils.data.DataLoader): 包含输入数据的数据加载器。
返回:
float: 准确率值。
"""
# 将模型设为评估模式
model = model.eval()
correct = 0.0
total_examples = 0
# 遍历数据加载器
for idx, (features, labels) in enumerate(dataloader):
# 使用 no_grad 上下文,以便不跟踪梯度
with torch.no_grad():
# 使用模型进行前向传播获取预测结果
logits = model(features)
# 获取预测结果并计算正确预测的数量
predictions = torch.argmax(logits, dim=1)
compare = labels == predictions
correct += torch.sum(compare)
total_examples += len(compare)
# 计算并返回准确率
return (correct / total_examples).item()In [45]:
compute_accuracy(model, train_loader)Out [45]:
1.0
In [46]:
compute_accuracy(model, test_loader)Out [46]:
1.0
In [47]:
torch.save(model.state_dict(), "model.pth")In [48]:
model = NeuralNetwork(2, 2) # 需要与原始模型完全匹配
model.load_state_dict(torch.load("model.pth"))Out [48]:
<All keys matched successfully>
In [ ]: