一、前言
数据集是 MNIST手写数字 数据集,自取 https://download.csdn.net/download/weixin_43721000/87708518 网络结构为两层卷积两层线性层
二、实现方法
1.导包
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import torch
import torch. nn as nn
from torch. utils. data import Dataset, DataLoader
2. 使用gpu
print ( torch. cuda. is_available( ) )
device = torch. device( "cuda" )
print ( device)
3. 定义数据读取方法
class MNISTDataset ( Dataset) :
def __init__ ( self, data_type) :
self. data_type = data_type
if self. data_type not in [ 'train' , 'test' ] : raise Exception( '数据集类型有误!' )
if self. data_type == 'train' :
self. data_path = "/kaggle/input/digit-recognizer/train.csv"
elif self. data_type == 'test' :
self. data_path = "/kaggle/input/digit-recognizer/test.csv"
df = pd. read_csv( self. data_path)
if self. data_type == 'train' :
self. label = df[ 'label' ] . to_numpy( ) . reshape( - 1 , 1 )
self. image = df. drop( columns= 'label' ) . to_numpy( ) . reshape( - 1 , 1 , 28 , 28 ) / 255
elif self. data_type == 'test' :
self. image = df. to_numpy( ) . reshape( - 1 , 1 , 28 , 28 ) / 255
def __len__ ( self) :
return len ( self. image)
def __getitem__ ( self, index) :
image = torch. FloatTensor( self. image[ index] )
if self. data_type == 'train' :
label = torch. zeros( 10 , dtype= torch. float )
label[ int ( self. label[ index] ) ] = 1.0
return image, label
else :
return image
train_datasets = MNISTDataset( "train" )
train_dataloader = DataLoader( train_datasets, batch_size= 100 , shuffle= True )
test_datasets = MNISTDataset( "test" )
test_dataloader = DataLoader( test_datasets, batch_size= 100 , shuffle= False )
4.定义模型、损失函数、优化器
class SimpleCNN ( nn. Module) :
def __init__ ( self) :
super ( SimpleCNN, self) . __init__( )
self. seq1 = nn. Sequential(
nn. Conv2d( 1 , 32 , kernel_size= 3 , stride= 1 , padding= 1 ) ,
nn. ELU( inplace= True ) ,
nn. MaxPool2d( kernel_size= 2 , stride= 2 )
)
self. seq2 = nn. Sequential(
nn. Conv2d( 32 , 64 , kernel_size= 3 , stride= 1 , padding= 1 ) ,
nn. ELU( inplace= True ) ,
nn. MaxPool2d( kernel_size= 2 , stride= 2 )
)
self. seq3 = nn. Sequential(
nn. Linear( 7 * 7 * 64 , 32 , bias= True ) ,
nn. ELU( inplace= True ) ,
nn. Linear( 32 , 10 , bias= True ) ,
nn. ELU( )
)
def forward ( self, x) :
x = self. seq1( x)
x = self. seq2( x)
x = x. view( x. size( 0 ) , - 1 )
x = self. seq3( x)
return x
model = SimpleCNN( )
model = model. to( device)
criterion = nn. CrossEntropyLoss( ) . to( device)
optimizer = torch. optim. Adam( model. parameters( ) , lr= 0.001 )
5.训练
history_loss = [ ]
EPOCH = 100
for epoch in range ( EPOCH) :
loss_tmp = [ ]
for i, ( image, label) in enumerate ( train_dataloader) :
image, label = image. to( device) , label. to( device)
y_pred = model( image)
loss = criterion( y_pred, label)
optimizer. zero_grad( )
loss. backward( )
optimizer. step( )
loss_tmp. append( loss. item( ) )
history_loss. append( np. mean( loss_tmp) )
print ( f"\rEPOCH: [ { epoch+ 1 } / { EPOCH} ], LOSS: { history_loss[ - 1 ] : 1.6f } " , end= "" )
6.绘制损失值图像
plt. plot( history_loss, label= "Cross Entropy Loss" )
plt. xlabel( "Epoch" )
plt. ylabel( "Loss" )
plt. legend( )
plt. show( )
7.预测
result = [ ]
for i, image in enumerate ( test_dataloader) :
image = image. to( device)
y_pred = model( image)
label_pred = torch. argmax( y_pred, dim= 1 )
result += label_pred. cpu( ) . tolist( )
8.绘制测试集图像与预测结果的对照图
height, width = 5 , 6
fig, axes = plt. subplots( height, width, figsize= ( 10 , 10 ) )
for i in range ( height) :
for j in range ( width) :
idx = height * i + j
axes[ i] [ j] . imshow( test_datasets[ idx] [ 0 ] , cmap= 'gray' )
axes[ i] [ j] . set_title( result[ idx] )
axes[ i] [ j] . axis( 'off' )
plt. show( )