MNIST Classifier Model
path = untar_data(URLs.MNIST)
path.ls()
(path/"training/1").ls()
t = (path/"training/1").ls()
t_1 = Image.open(t[0])
t_1
show_image(tensor(t_1))
def load_data(folder):
dataList = []
labelList = []
for num in range(10):
data_path = (path/folder/f'{num}').ls().sorted() #getting path
stackedData = torch.stack([tensor(Image.open(o)) for o in data_path]) #Open each image and stack them
stackedData = stackedData.float()/255.0 #squishing between 0-1
dataList.append(stackedData) #adding to dataList
labelList.extend([num]*len(data_path))#extending labelList
#Convert so that each image data is in each row
train_x = torch.cat(dataList).view(-1, 28*28)
train_y = tensor(labelList)
return train_x, train_y
train_x, train_y = load_data("training")
test_x, test_y = load_data("testing")
train_dset = list(zip(train_x,train_y))
valid_dset = list(zip(test_x,test_y))
dl_train = DataLoader(train_dset, batch_size=256)
dl_test = DataLoader(valid_dset, batch_size=256)
Below is the functions we need to train and test the model
Most of these functions are copies and pasted from our previous MNIST model. The difference here is the loss function, which was swapped out for cross entropy (As we have multiple categories). And, our accuracy function has been adjusted due to switching out sigmoid for softmax (softmax ranges all values between 0-1).
def calc_grad(xb, yb, model):
preds = model(xb)
loss = F.cross_entropy(preds, yb)
loss.backward()
def train_epoch(model):
for xb,yb in dl_train:
calc_grad(xb, yb, model)
for p in params:
p.data -= p.grad.data * lr
p.grad.zero_()
def batch_accuracy(xb, yb):
pred = xb.softmax(1)
return batch_accuracy_helper(pred, yb)/float(yb.size(0))
def batch_accuracy_helper(preds, yb):
return preds.argmax(dim=1).eq(yb).sum().float()
def validate_epoch(model):
accs = [batch_accuracy(model(xb), yb) for xb,yb in dl_test]
return round(torch.stack(accs).mean().item(), 4)
def linear_layer(xb):
return xb@w + b
def init_params(x, var=1.0):
return (torch.randn(x)*var).requires_grad_()
lr = 1.
w = init_params((28*28,10))
b = init_params(10)
params = w, b
w.shape, b.shape
validate_epoch(linear_layer)
train_epoch(linear_layer)
validate_epoch(linear_layer)
Our loss improved, nice!
def train_model(model, epochs):
for i in range(epochs):
train_epoch(model)
print(validate_epoch(model), end=' ')
train_model(linear_layer, 20)
50% acc is not that bad, given there are 10 classes
dls = DataLoaders(dl_train, dl_test)
simple_net = nn.Sequential(
nn.Linear(28*28,30), #30 neurons
nn.ReLU(),
nn.Linear(30, 10) # 30neurons into 10 output neurons (10 classes)
)
learn = Learner(dls, simple_net, opt_func=SGD,
loss_func=F.cross_entropy, metrics=accuracy)
learn.fit(20, .01)
learn = Learner(dls, simple_net, opt_func=SGD,
loss_func=F.cross_entropy, metrics=accuracy)
learn.fine_tune(2, base_lr=0.1)
lr_min, lr_steep = learn.lr_find() #Finding best
print(f"Minimum/10: {lr_min:.2e}, steepest point: {lr_steep:.2e}")
learn.fine_tune(20, base_lr=3e-2) #Now lets train on the steepest