Lesson 4 P1 - FastAI
path = untar_data(URLs.MNIST_SAMPLE) #path for data
path.ls()
(path/'train').ls()
threes = (path/'train'/'3').ls().sorted() #getting 3's data from path
sevens = (path/'train'/'7').ls().sorted() #getting 7's data from path
threes
im3_path = threes[1]
im3 = Image.open(im3_path) #shows image
im3
array(im3)[4:10,4:10] #numpy to convert image into quantitative rep
tensor(im3)[4:10,4:10] #same thing as numpy array but work better on GPU's (preferred)
im3.shape
im3_t = tensor(im3)
df = pd.DataFrame(im3_t[4:15,4:22])
df.style.set_properties(**{'font-size':'6pt'}).background_gradient('Greys') #Using panda's framework
seven_tensors = [tensor(Image.open(o)) for o in sevens]
three_tensors = [tensor(Image.open(o)) for o in threes]
len(three_tensors), len(seven_tensors)
show_image(three_tensors[1]);
type(three_tensors)
Right now our tensors are lists. We must fix this by stacking them.
stacked_sevens = torch.stack(seven_tensors).float()/255
stacked_threes = torch.stack(three_tensors).float()/255
stacked_threes.shape
len(stacked_threes.shape) #Returns rank. Rank means it has n dementions
stacked_threes.ndim
mean3 = stacked_threes.mean() #notice taking mean gives a number
mean3
mean3 = stacked_threes.mean(0) #the 0 represents the axis we are doing the mean across (In this case across the first axis 6131)
show_image(mean3);
Here's our ideal 3
mean7 = stacked_sevens.mean(0)
show_image(mean7);
And our ideal 7, which we will also be using as a comparison
a_3 = stacked_threes[1]
show_image(a_3);
dist_3_abs = (a_3 - mean3).abs().mean() #L1 norm
dist_3_sqr = ((a_3 - mean3)**2).mean().sqrt() #RMSE or L2 norm
dist_3_abs,dist_3_sqr
dist_7_abs = (a_3 - mean7).abs().mean()
dist_7_sqr = ((a_3 - mean7)**2).mean().sqrt()
dist_7_abs,dist_7_sqr
F.l1_loss(a_3.float(),mean7), F.mse_loss(a_3,mean7).sqrt()
data = [[1,2,3],[4,5,6]]
arr = array (data)
tns = tensor(data)
arr # numpy
tns # pytorch
tns[1]
tns[:,1]
tns[1,1:3]
tns+1
tns.type()
tns*1.5
valid_3_tens = torch.stack([tensor(Image.open(o))
for o in (path/'valid'/'3').ls()])
valid_3_tens = valid_3_tens.float()/255
valid_7_tens = torch.stack([tensor(Image.open(o))
for o in (path/'valid'/'7').ls()])
valid_7_tens = valid_7_tens.float()/255
valid_3_tens.shape, valid_7_tens.shape
def mnist_distance(a,b):
return (a-b).abs().mean((-1,-2)) #mean across 2nd and last axis (28,28)
mnist_distance(a_3, mean3)
valid_3_dist = mnist_distance(valid_3_tens, mean3) #broadcast method across entire validation set
valid_3_dist, valid_3_dist.shape
tensor([1,2,3]) + tensor([1]) #broadcasting example
(valid_3_tens-mean3).shape
def is_3(x): return mnist_distance(x,mean3) < mnist_distance(x,mean7)
a_7 = stacked_sevens[1]
a_7
show_image(a_7)
is_3(a_7), is_3(a_7).float() #tensor val is 0
Nice it's working!
is_3(valid_3_tens) #Broadcasting
accuracy_3s = is_3(valid_3_tens).float() .mean()
accuracy_7s = (1 - is_3(valid_7_tens).float()).mean()
accuracy_3s,accuracy_7s,(accuracy_3s+accuracy_7s)/2
Wow 95% accuracy! You just created your very first model from scratch!
uploader = widgets.FileUpload()
uploader
img = PILImage.create(uploader.data[0])
img.to_thumb(40)
I drew this in paint
img = img.resize((28,28)) #Resizing img
t_3 = tensor(img) #converting to tensor
t_3.shape
t_3 = t_3[:,:,0] #dropping channels
show_image(t_3) #Awesome now it looks like an image from our dataset
t_3.shape
is_3(t_3) #Nice, it got it right!
time = torch.arange(0,20).float(); time
speed = torch.randn(20)*3 + 0.75*(time-9.5)**2 + 1
plt.scatter(time,speed);
Lets assume we have this data given
def f(t, params):
a,b,c = params
return a*(t**2) + (b*t) + c
def mse(preds, targets):
return ((preds-targets)**2).mean().sqrt() #mean squared error
params = torch.randn(3).requires_grad_() #Getting random weights and requiring gradient
params
We are requiring gradients because this is what we will be using to improve our weights
preds = f(time, params)
def show_preds(preds, ax=None):
if ax is None: ax=plt.subplots()[1]
ax.scatter(time, speed)
ax.scatter(time, to_np(preds), color='red')
ax.set_ylim(-300,100)
show_preds(preds) #Red is our predictions, Blue is the labels
Not bad for an initial prediction
loss = mse(preds, speed) #Current loss
loss
loss.backward()
params.grad
params.grad * 1e-5 #1e-5 is the learning rate
lr = 1e-4
params.data -= lr * params.grad.data
params.grad = None
preds = f(time,params)
mse(preds, speed) #loss improved
Notice that our loss has improved with these new weights
show_preds(preds)
def apply_step(params, prn=True):
preds = f(time, params)
loss = mse(preds, speed)
loss.backward()
params.data -= lr * params.grad.data
params.grad = None
if prn: print(loss.item())
return preds
for i in range(10): apply_step(params) #running it 10 times (Notice loss improving)
_,axs = plt.subplots(1,4,figsize=(12,3))
for ax in axs: show_preds(apply_step(params, False), ax)
plt.tight_layout()
Conclusion
Compare this approach to the pixel similerity example. You will notice that here it truly seems like the model is learning: This is the approach we will be using from now on as it better fits the ideal ML model.
I have chosen to split this lesson into 2 parts. On the next lesson we will apply what we have learned to the MNIST dataset once again. This time using the more approriate ML approach.