这篇是接着新手小白的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]
创建练习和测试循环
- # 设置随机种子,有利于代码的复现
- 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啊,今天就到这吧,不敢想象来日诰日的学习有多开心,终于到了要改善模子啦~
假如文章对您有帮助的话,记得给俺点个赞呐!
靴靴,谢谢~
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |