softmax从零实现-逐行代码学习
代码来自B站的 跟着李沐学AI.,已学过吴恩达的深度学习,但是代码还是有很多看不懂,只好一步一步做记录了,分享的时候顺便学习,有不对的地方希望能替我指出来,或者说有更容易的理解方式也请帮帮忙。
import torch
from IPython import display
from d2l import torch as d2l
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
num_inputs = 784
num_outputs = 10
#返回一个从独立的正态分布中抽取的随机数的张量,正态分布的平均值为0,方差为0.01,784*10的矩阵,开启梯度保存
W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)
b = torch.zeros(num_outputs, requires_grad=True)
def softmax(X):#定义一个softmax函数,有人说这个写的有溢出的可能,目前我还不懂
X_exp = torch.exp(X) #对X中的每个值变成ex
partition = X_exp.sum(1, keepdim=True) #按列取和,保持维度不变
return X_exp / partition # 这里应用了广播机制
-----------------------------------------------------------------------------------------
解释
X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) #2*3矩阵 size[2,3]
X_exp = torch.exp(X)
X_exp #2*3矩阵 size[2,3]
>>tensor([[1.3673, 1.0601, 1.9367, 5.2293, 1.1470],
[1.2775, 1.2895, 1.2460, 0.5687, 0.4273]])
X_exp.sum(1, keepdim=True) #2*1矩阵,保证维度不变,size[2,1]并不会改变维度
>>tensor([[10.7405],
[ 4.8090]])
X_exp / partition
>>tensor([[0.1273, 0.0987, 0.1803, 0.4869, 0.1068],
[0.2656, 0.2681, 0.2591, 0.1183, 0.0888]])
def net(X):
return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)
#定义了一个网络,z=x*w+b ,a=softmax(z) ,return的a就是上面的 X_exp / partition
y = torch.tensor([0, 2]) #y是标签,假设有两个样本(图片0,图片1),有三个类别(猫,狗,鱼),图片0正确是猫,图片1正确是鱼
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])#y_hat是预测值张量,图片0的概率[猫=0.1,狗=0.3,鱼=0.6],图片1····
y_hat[[0, 1], y] #取出图片0对猫的预测,和图片1对鱼的预测值 tensor([0.1000, 0.5000])
>>测试一下 y_hat[[0, 1], [1, 1]]
>>tensor([0.3000, 0.2000])
def cross_entropy(y_hat, y):
return - torch.log(y_hat[range(len(y_hat)), y]) #返回损失函数值 损失函数的公式 -log(预测值),
cross_entropy(y_hat, y) #输出的是样本0的损失,以及样本1的损失
def accuracy(y_hat, y): #@save
"""计算预测正确的数量"""
if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
y_hat = y_hat.argmax(axis=1) #返回一个tensor,元素是每行中最大元素的索引
cmp = y_hat.type(y.dtype) == y #把y_hat的数据类型转换成与y相同的数据类型
return float(cmp.type(y.dtype).sum()) #计算预测对的总数
def evaluate_accuracy(net, data_iter): #@save
"""计算在指定数据集上模型的精度"""
if isinstance(net, torch.nn.Module):#判断net是不是nn.Module
net.eval() # 将模型设置为评估模式,这是在测试集使用,训练集要关闭
#神经网络模块存在两种模式,train模式(net.train())和eval模式(net.eval())。一种训练用,一种测试使用
#参考https://www.jianshu.com/p/ef2a7a78aa83
metric = Accumulator(2) # 正确预测数、预测总数
with torch.no_grad(): # 关闭梯度计算
for X, y in data_iter:
metric.add(accuracy(net(X), y), y.numel())#把预测对的个数,预测总数放入一个列表
return metric[0] / metric[1] #输出正确率
class Accumulator: #@save #具体用法参考这个博客https://blog.csdn.net/weixin_44556141/article/details/120116161
"""在n个变量上累加"""
def __init__(self, n):
self.data = [0.0] * n #[0.0]*2 ==>[0.0 , 0.0]
def add(self, *args): #*args的用法:当传入的参数个数未知,且不需要知道参数名称时。
self.data = [a + float(b) for a, b in zip(self.data, args)] #a是data中的数,b是args中的数
def reset(self):
self.data = [0.0] * len(self.data)
def __getitem__(self, idx):
return self.data[idx]
evaluate_accuracy(net, test_iter) #net参数是一个之前的网络函数,忘记python可以把函数作为参数传递了