全体目光向我看齐!今天是day5!
好吧我错了,周末偷了个懒,今天我们继续。前几天把mnist指令集跑通了,还没细看。今天仔细的改一改
在GPU上运行代码
Pytorch似乎不说的话默认是在CPU上跑,跑起来还是有点慢的,而且CPU负载直接就拉满了。
最后跑了100s
上到GPU上,首先需要设置device为GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
然后将网络的参数放到device上,并且训练的data和target也要放上来。后面预测结果,就自动在device上面了
model = Net().to(device) # Net上的参数要在GPU上
...
for epoch in range(epochs):
for batch_idx, (data, target) in enumerate(train_loader): #自动打batch
data, target = data.to(device), target.to(device) # data和target要放在GPU上
optimizer.zero_grad()
output = model(data) # output自动算完在GPU上
loss = criterion(output, target)
loss.backward() # 回传的梯度,隐式生成,也放在GPU上
optimizer.step()
emmmm,GPU根本跑不满,最后也没有快特别多,估计是数据密度不够。以后找找有没有更大规模的例子吧。
调整网络结构
# 定义模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=3) #输入为1,输出为10,卷积核大小3
self.conv2 = nn.Conv2d(10, 20, kernel_size=4)
self.fc = nn.Linear(20 * 5 * 5, 10)
def forward(self, x):
batch_size = x.size(0) #第一个维度是batch维度,图片为1*28*28时,输入为64*1*28*28
x = torch.relu(self.conv1(x)) # 输入64*1*28*28, 输出64*10*26*26
x = torch.max_pool2d(x, 2, 2) # 输入64*10*26*26, 输出64*10*13*13,池化层
x = torch.relu(self.conv2(x)) # 输入64*10*13*13, 输出64*20*10*10
x = torch.max_pool2d(x, 2, 2) # 输入64*20*10*10, 输出64*20*5*5
x = x.view(batch_size, -1) # 输入64*20*5*5, 输出64*500
x = self.fc(x) # 输入64*500, 输出64*10
return x
可以看到12828是一张图片,size 1=1说明这是一张黑白照片。然后每个像素点,会被Conv2d展开成10个输出。而kernel_size是卷积的窗口大小,输入是2828而卷积窗口大小是5,输出就是2424。这里我稍微改了改网络规格,不过似乎精度影响不大
现在的情况是Adam这个优化算法,loss振荡还是比较明显的,我们把batch_size从64做大到128,然后学习率从0.01下降到1e-3,原来只学10epoch,现在学个30epoch。训练结果如下
好的精度上来了一点,想继续凹精度应该还可以,比如继续增加网络规模。
不过下面我们看看这个,标准化的函数
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
可以参考一下这篇博客 https://zhuanlan.zhihu.com/p/476220305
这里简单理解就是,第一个输入0.1307是均值,第二个输入0.3081是方差。我们尝试把均值改极端一点
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((300,), (0.3081,))
])
然后就成功的把他精度给玩坏了
疑惑点
最后这个我是有点不理解的
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=3) #输入为1,输出为10,卷积核大小5
self.conv2 = nn.Conv2d(10, 20, kernel_size=4)
self.fc = nn.Linear(20 * 5 * 5, 10)
def forward(self, x):
batch_size = x.size(0) #第一个维度是batch维度,图片为1*28*28时,输入为64*1*28*28
x = torch.relu(self.conv1(x)) # 输入64*1*28*28, 输出64*10*26*26
x = torch.max_pool2d(x, 2, 2) # 输入64*10*26*26, 输出64*10*13*13,池化层
x = torch.relu(self.conv2(x)) # 输入64*10*13*13, 输出64*20*10*10
x = torch.max_pool2d(x, 2, 2) # 输入64*20*10*10, 输出64*20*5*5
x = x.view(batch_size, -1) # 输入64*20*5*5, 输出64*500
x = self.fc(x) # 输入64*500, 输出64*10
return x
这里不是对数字分类吗?输出为啥是10?不应该是输出10是各个数字的概率,然后过个softmax啥的,最后预测是某种分类吗?
这…为啥呢?我手动给他加了让它输出成一维的
# 定义模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=3) #输入为1,输出为10,卷积核大小5
self.conv2 = nn.Conv2d(10, 20, kernel_size=4)
self.fc = nn.Linear(20 * 5 * 5, 10)
self.fc2 = nn.Linear(10, 1)
def forward(self, x):
batch_size = x.size(0) #第一个维度是batch维度,图片为1*28*28时,输入为64*1*28*28
x = torch.relu(self.conv1(x)) # 输入64*1*28*28, 输出64*10*26*26
x = torch.max_pool2d(x, 2, 2) # 输入64*10*26*26, 输出64*10*13*13,池化层
x = torch.relu(self.conv2(x)) # 输入64*10*13*13, 输出64*20*10*10
x = torch.max_pool2d(x, 2, 2) # 输入64*20*10*10, 输出64*20*5*5
x = x.view(batch_size, -1) # 输入64*20*5*5, 输出64*500
x = self.fc(x) # 输入64*500, 输出64*10
x = self.fc2(x)
return x
然后果不其然就挂掉了,不过这个好像确实也不对。浮点数的预测结果和target肯定数据类型就对不上
注释掉这两行
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=3) #输入为1,输出为10,卷积核大小5
self.conv2 = nn.Conv2d(10, 20, kernel_size=4)
self.fc = nn.Linear(20 * 5 * 5, 10)
#self.fc2 = nn.Linear(10, 1)
def forward(self, x):
batch_size = x.size(0) #第一个维度是batch维度,图片为1*28*28时,输入为64*1*28*28
x = torch.relu(self.conv1(x)) # 输入64*1*28*28, 输出64*10*26*26
x = torch.max_pool2d(x, 2, 2) # 输入64*10*26*26, 输出64*10*13*13,池化层
x = torch.relu(self.conv2(x)) # 输入64*10*13*13, 输出64*20*10*10
x = torch.max_pool2d(x, 2, 2) # 输入64*20*10*10, 输出64*20*5*5
x = x.view(batch_size, -1) # 输入64*20*5*5, 输出64*500
x = self.fc(x) # 输入64*500, 输出64*10
#x = self.fc2(x)
return x
回退到原来的结果了理论,但是实际上他居然又挂掉了
这次好像是…GPU出问题了,刚才被我玩坏了…重启了一下pyder又可以用了。好吧今天先到这里吧,洗漱去了~