- 文章来源:CSDN@LawsonAbs
- 从网上找到了一道面试题,花了我大半天的时间才写出来,还是太嫩了,不能熟练的给出代码,像下面这种代码我觉得最多30min吧。
- 作为一名算法工程师,pytorch的API接口都应该十分熟悉才行!接下来的任务包括背pytorch的接口!
真实面试题,请实现下面这个需求
对MNIST 手写数据集进行分类。神经网络需具备如下三个要求:(1)使用三层全连接;(2)具有非线性变化;(3)具有过拟合处理手法
基础知识
本文做的是使用前馈神经网络(DNN/FNN)来实现手写数字识别任务。需要注意如下几点:
- 在全连接之后,会有一个激活函数处理输入值,即
σ
(
f
(
z
=
W
T
x
+
b
)
)
\sigma(f(z=W^Tx+b))
σ(f(z=WTx+b)),然后每个神经元又会把这个活性值传递给下一层
- 如何使用交叉熵获取模型损失? 交叉熵内容可以参考我的之前的博客内容。
数据集
使用的数据集是MNIST 手写数字集,我们可以直接在torchvision 中获取,具体方法可以参考我下面的代码。
代码
我会针对代码逐行分析,然后给出可以优化的点(比如可视化损失下降;归一化处理输入等),查看有哪些东西需要注意。
'''
使用3层前馈神经网络完成图片分类训练。
'''
from visdom import Visdom
from tqdm import tqdm
import torchvision
from torchvision import transforms
import torch as t
from torch.utils.data import DataLoader,Dataset
import torch.nn as nn
from torchvision.datasets import mnist
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.1,), (0.34,))
])
class Model(nn.Module):
def __init__(self,in_1,out_1,in_2,out_2,in_3,out_3):
super().__init__()
self.linear_1 = nn.Linear(in_features= in_1, out_features= out_1)
self.linear_2 = nn.Linear(in_features= in_2, out_features= out_2)
self.linear_3 = nn.Linear(in_features= in_3, out_features= out_3)
self.active = nn.ReLU()
self.dropout = nn.Dropout()
def forward(self,x):
tempx = self.linear_1(x)
tempx = self.active(tempx)
tempx = self.linear_2(tempx)
tempx = self.active(tempx)
tempx = self.linear_3(tempx)
return tempx
if __name__ == "__main__":
mnist_data = torchvision.datasets.MNIST('./data/',download=True,train=True,transform=transform)
train_data = mnist_data.train_data.float()
print(train_data[0])
test_data = mnist_data.test_data.float()
train_labels = mnist_data.train_labels
test_labels = mnist_data.test_labels
batch_size = 16
train_data_loader = DataLoader(train_data,
batch_size=batch_size,
)
train_label_loader = DataLoader(train_labels,
batch_size=batch_size,
)
test_data_loader = DataLoader(test_data,
batch_size=batch_size,
)
test_label_loader = DataLoader(test_labels,
batch_size=batch_size,
)
model = Model(784,256,256,128,128,10)
train_epoch = 100
lr = 1e-3
opti = t.optim.Adam(model.parameters(),lr=lr)
criterion = nn.CrossEntropyLoss()
viz = Visdom()
win = "train_loss"
global_step = 0
model.train()
for epoch in tqdm(range(train_epoch)):
for data,gold in tqdm(zip(train_data_loader,train_label_loader)):
data = data.reshape(batch_size,-1)
pred = model(data)
loss = criterion(pred,gold)
loss.backward()
opti.step()
opti.zero_grad()
global_step+=1
viz.line([loss.item()], [global_step],win=win, update="append")
for param in model.named_parameters():
name,value = param
if "linear_3.weight" in name:
print(value.shape)
print(name)
print(f"value={value[0,0:10]}")
分析
平常写代码,都是能运行就可以了,也不管到底是几个意思,如果需要功能的时候直接从网上ctrl+c/v ,这样子肯定是不行的。有下面几个问题值得考虑:
loss.backward() 有什么作用? 如果去掉这行代码,为啥模型就不能优化了(模型参数就不再变化)?那opti 的作用又是什么?Normalize 的归一化操作具体是怎么执行的?
|