目录
- 1 启动损失函数和优化器
- 2 训练模型
- 创建训练和测试循环
- 3 预测和评估模型
这篇是接着新手小白的pytorch学习第七弹------分类问题模型这一篇的,代码也是哟~
1 启动损失函数和优化器
对于我们的二分类问题,我们经常使用 binary cross entropy 作为损失函数
可以使用torch.optim.SGD()
和torch.optim.Adam()
作为优化器
有两个 binary cross entropy 函数
- torch.nn.BCELoss()-在label(target)和features(input)之间进行衡量
- torch.nn.BCEWithLogitsLoss()-这个和上面这个一样,不过它有一个sigmoid嵌入层(nn.Sigmoid)[之后我们会看这个方式的]
下面我们会创建损失函数和优化器,优化器我们使用SGD,优化器使用模型的参数,学习率为0.1
import torch.nn as nn
import torch.optim as optim
# 创建一个损失函数
loss_fn = nn.BCEWithLogitsLoss() # 嵌入sigmoid()函数
# 创建一个优化器
optimizer = optim.SGD(params=model_0.parameters(),
lr=0.1)
我们再引入一个新的东西,评估标准,它也可以像损失函数一样,来衡量你的模型怎么样。毕竟使用多个角度来衡量模型,能够让模型更加的公正客观。Accuracy准确度,可以看出在总样本中正确样本的数量,所以100%是最好的,毕竟我们期望它全部预测对,对吧。
# 创建一个计算准确率的accuracy函数
def accuracy_fn(y_true, y_pred):
correct = torch.eq(y_true, y_pred).sum().item() # torch.eq()计算两个相同的张量
acc = (correct/len(y_pred))*100
return acc
现在我们可以使用这个函数来衡量我们的模型啦。
2 训练模型
这里使用的损失函数是nn.BCEWithLogits()
,因此这个损失函数的输入是logits
.
什么是logits
呢,我的理解就是我们的模型输出的原始值,不经过处理的值,由于这个损失函数是有一个torch.sigmoid()
函数的,所以数据的转换有三个步骤:logits -> prediction probability -> prediction labels
# 查看测试数据的前5个输出
with torch.inference_mode():
y_logits = model_0(X_test.to(device))[:5]
y_logits
tensor([[0.6003],
[0.6430],
[0.5095],
[0.6260],
[0.5431]], device=‘cuda:0’)
因为我们的模型没有被训练,因此这些输出都是随机的。
并且我们模型的原始输出是logits
,这些数字难以解释,我们需要能够和真实数据相比较的数据。
我们可以使用torch.sigmoid()
激活函数来将数据转换为我们需要的形式.
# 使用 torch.sigmoid() 激活函数
y_pred_probs = torch.sigmoid(y_logits)
y_pred_probs
tensor([[0.6457],
[0.6554],
[0.6247],
[0.6516],
[0.6325]], device=‘cuda:0’)
y_pred_probs
现在是 prediction probability 预测概率的形式,概率就是有多大的可能,有多大的几率。在我们的情况中,我们理想的输出是0或1,所以这些值可以被看做一个决定的边界。比如说值越靠近零,那模型就将这个样本分类为0, 值越接近1,模型就将这个样本分类为1.
更具体地说:
if y_pred_probs >= 0.5, y=1(class 1)
if y_pred_probs < 0.5, y=0(class 0)
将预测概率转变成预测标签,我们四舍五入torch.sigmoid()
函数的输出即可
# 将概率转变为标签
y_preds = torch.round(y_pred_probs)
# 将刚才的过程连起来放在一起
y_preds_labels = torch.round(torch.sigmoid(model_0(X_test.to(device))[:5]))
# 查看预测值和标签相等
print(torch.eq(y_preds.squeeze(), y_preds_labels.squeeze()))
# 去掉额外的维度
y_preds.squeeze()
tensor([True, True, True, True, True], device=‘cuda:0’)
tensor([1., 1., 1., 1., 1.], device=‘cuda:0’)
y_test[:5]
y_test[:5]
创建训练和测试循环
# 设置随机种子,有利于代码的复现
torch.manual_seed(42)
epochs = 100
# 将数据放到指定的设备上
X_train, y_train = X_train.to(device), y_train.to(device)
X_test, y_test = X_test.to(device), y_test.to(device)
# 创建训练和测试循环
for epoch in range(epochs):
# 进入训练模式
model_0.train()
# 预测
y_logits = model_0(X_train).squeeze()
y_pred_prob = torch.sigmoid(y_logits)
y_pred = torch.round(y_pred_prob)
# 计算损失函数和准确率
loss = loss_fn(y_logits,
y_train)
acc = accuracy_fn(y_true = y_train,
y_pred = y_pred)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 测试
model_0.eval()
with torch.inference_mode():
test_logits = model_0(X_test).squeeze()
test_pred = torch.round(torch.sigmoid(test_logits))
test_loss = loss_fn(test_logits,
y_test)
test_acc = accuracy_fn(y_true = y_test,
y_pred = test_pred)
# 打印出内容
if epoch % 10 == 0:
print(f"Epoch:{epoch} | Loss:{loss:.5f} | Accuracy:{acc:.2f}% | Test loss:{test_loss:.2f} | Test accuracy:{test_acc:.2f}%")
Epoch:0 | Loss:0.69313 | Accuracy:51.75% | Test loss:0.69 | Test accuracy:48.50%
Epoch:10 | Loss:0.69310 | Accuracy:51.75% | Test loss:0.69 | Test accuracy:48.00%
Epoch:20 | Loss:0.69308 | Accuracy:51.25% | Test loss:0.69 | Test accuracy:49.00%
Epoch:30 | Loss:0.69307 | Accuracy:50.75% | Test loss:0.69 | Test accuracy:48.00%
Epoch:40 | Loss:0.69306 | Accuracy:50.38% | Test loss:0.69 | Test accuracy:48.00%
Epoch:50 | Loss:0.69305 | Accuracy:51.12% | Test loss:0.69 | Test accuracy:47.50%
Epoch:60 | Loss:0.69304 | Accuracy:51.12% | Test loss:0.69 | Test accuracy:48.00%
Epoch:70 | Loss:0.69303 | Accuracy:50.75% | Test loss:0.69 | Test accuracy:47.50%
Epoch:80 | Loss:0.69303 | Accuracy:50.75% | Test loss:0.69 | Test accuracy:47.00%
Epoch:90 | Loss:0.69303 | Accuracy:50.38% | Test loss:0.69 | Test accuracy:46.50%
通过上面的数据,损失函数几乎没变化,精确度50%左右,感觉模型啥也没有学到,这就意味着它分类是随机的。
3 预测和评估模型
从上面的数据,感觉我们的模型好像是随机猜测,我们来可视化一下看看究竟是怎么个事儿。
我们接着会写代码下载并导入helper_functions.py
script来自Learn PyTorch for Deep Learning repo.
在这里有一个叫做 plot_decision_boundary()
的函数,它来可视化我们模型的分类的不同的点
我们也会导入我们在 01 中自己写的 plot_predictions()
import requests
from pathlib import Path
# 从仓库下载文档
if Path("helper_functions.py").is_file():
print("helper_functions.py already exists, skipping download")
else:
print("Downloading helper_functions.py")
request = requests.get("https://raw.githubusercontent.com/mrdbourke/pytorch-deep-learning/main/helper_functions.py")
with open("helper_functions.py", "wb") as f:
f.write(request.content)
from helper_functions import plot_predictions, plot_decision_boundary
Downloading helper_functions.py
这里可能需要科学上网,我把文件helper_functions.py的代码放到文末了,可以自己创建一个.py文件粘进去。
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.title("Train")
plot_decision_boundary(model_0, X_train, y_train)
plt.subplot(1, 2, 2)
plt.title("Test")
plot_decision_boundary(model_0, X_test, y_test)
看中间这条白色的线,模型是通过这条直线来区分红色和蓝色的点,所以是50%的准确率,明显是不对的,因为我们的数据明显是圈圈。
从机器学习的方面看,我们的模型欠拟合(underfitting),即没有从数据中学习到数据的模式.
那我们如何改善呢?请听下回分解。
终于把今天的学习整理出来了,BB啊,今天中午吃了个超级物美价廉的套餐,里面的土豆炖牛腩和我平常吃的不一样,它这个带汤,尊嘟很好吃,熏过的香干一定要尝尝啊,皮蛋也很八错。还喝了一杯瑞幸的美式,一般般吧,室友说苦,我就喜欢喝这种苦苦的,嘻嘻嘻。
师姐通过一个电话说我喜欢一个男孩子,就说我喜欢他,哈哈哈哈,不知道咋听出来的,乌龙可是闹大了呢,话说,我们见面次数确实不多,但听到她的声音,莫名有点想她了,晚上就是多愁善感啊,别管我!
BB啊,今天就到这吧,不敢想象明天的学习有多开心,终于到了要改善模型啦~
如果文章对您有帮助的话,记得给俺点个赞呐!
靴靴,谢谢~