Skip to content

Commit dfae47f

Browse files
committed
Merge branch 'main' of github.com:sajal2692/sajal2692.github.io
2 parents 6fdb538 + 29c5237 commit dfae47f

18 files changed

+764
-123
lines changed

astro.config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import remarkToc from "remark-toc";
55
import remarkCollapse from "remark-collapse";
66
import sitemap from "@astrojs/sitemap";
77
import { SITE } from "./src/config";
8+
import partytown from "@astrojs/partytown";
89

910
// https://astro.build/config
1011
export default defineConfig({
@@ -15,6 +16,11 @@ export default defineConfig({
1516
}),
1617
react(),
1718
sitemap(),
19+
partytown({
20+
config: {
21+
forward: ["dataLayer.push"],
22+
},
23+
}),
1824
],
1925
markdown: {
2026
remarkPlugins: [

package-lock.json

Lines changed: 29 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
},
1717
"dependencies": {
1818
"@astrojs/check": "^0.4.1",
19+
"@astrojs/partytown": "^2.0.4",
1920
"@astrojs/rss": "^4.0.1",
2021
"@resvg/resvg-js": "^2.6.0",
2122
"astro": "^4.1.1",
61.5 KB
Loading
236 KB
Loading
103 KB
Loading
294 KB
Loading
244 KB
Loading

src/config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { Site, SocialObjects } from "./types";
22

33
export const SITE: Site = {
4-
website: "https://sajal2692.github.io", // "https://sajalsharma.com/", // replace this with your deployed domain
4+
website: "https://sajalsharma.com/", // replace this with your deployed domain
55
author: "Sajal Sharma",
66
desc: "Internet home of Sajal Sharma, a software engineer specializing in AI and ML.",
77
title: "Sajal Sharma",
88
ogImage: "astropaper-og.jpg",
99
lightAndDarkMode: true,
10-
postPerPage: 3,
10+
postPerPage: 5,
1111
scheduledPostMargin: 15 * 60 * 1000, // 15 minutes
1212
};
1313

@@ -47,7 +47,7 @@ export const SOCIALS: SocialObjects = [
4747
name: "Twitter",
4848
href: "https://twitter.com/sajal2692",
4949
linkTitle: `${SITE.title} on Twitter`,
50-
active: true,
50+
active: false,
5151
},
5252
{
5353
name: "Twitch",

src/content/blog/building-image-classifier-fastai.md

Lines changed: 18 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "Building an Image Classifier Really Fast Using Fastai"
3-
author: "Your Name" # Replace with the actual author's name
3+
author: "Sajal Sharma" # Replace with the actual author's name
44
pubDatetime: 2022-10-28T00:00:00Z
55
slug: building-image-classifier-fastai
66
featured: false
@@ -10,7 +10,7 @@ tags:
1010
- Computer Vision
1111
- fastai
1212
description: "In this post, I demonstrate how to quickly build an image classifier using the fastai library, a powerful tool for practical deep learning. The project involves classifying images of fruit as either rotten or fresh."
13-
canonicalURL: "" # Add if the article is published elsewhere
13+
canonicalURL: "" # Add if the article is published elsewhere
1414
---
1515

1616
## Table of contents
@@ -19,15 +19,14 @@ canonicalURL: "" # Add if the article is published elsewhere
1919

2020
I recently started the [fast.ai](https://course.fast.ai/Lessons/lesson1.html) course to build up my practical deep learning skills. In order to better retain what I learn, I'm going to be writing a series of posts/notebooks, implementing my own models based on the course content. This notebook is written based on what I learned from the first week of the course.
2121

22-
In this notebook we'll build an image classifier using the [fastai](https://docs.fast.ai), a deep learning library built on top of Pytorch that provides both high-level and low-level components to quickly build state-of-the-art models for common deep learning domains.
22+
In this notebook we'll build an image classifier using the [fastai](https://docs.fast.ai), a deep learning library built on top of Pytorch that provides both high-level and low-level components to quickly build state-of-the-art models for common deep learning domains.
2323

2424
We'll build a model that can classify images of fruit into a binary category: rotten or not. You can imagine such a model being used inside refrigerators to detect if produce kept inside it has gone bad.
2525

2626
When I started learning ML in 2016, building such models was a non-trivial task. Libraries to build deep neural networks were still in their infancy (Pytorch was introduced in late 2016), and building accurate image classification models required a certain degree of specialized knowledge. All that has changed and, as you'll notice in the notebook, we can build an image classifier using just a few lines of code.
2727

2828
Let's get started!
2929

30-
3130
```python
3231
import os
3332
# !pip install -Uqq fastai duckduckgo_search
@@ -39,7 +38,6 @@ We'll be needing the `duckduckgo_search` package to quickly search for, and down
3938

4039
<br />
4140

42-
4341
```python
4442
from duckduckgo_search import ddg_images
4543
from fastcore.all import *
@@ -52,16 +50,14 @@ def search_images(term, max_images=40):
5250
urls = search_images('rotten fruit', max_images=1)
5351
urls[0]
5452
```
53+
5554
```output
5655
Searching for 'rotten fruit'
5756
'https://i.pinimg.com/originals/13/2e/48/132e481c0ef6f1516de2b5b80a553b6a.jpg'
5857
```
5958

60-
61-
6259
Let's download this image and open it.
6360

64-
6561
```python
6662
from fastdownload import download_url
6763
dest = 'rotten.jpg'
@@ -72,33 +68,23 @@ im = Image.open(dest)
7268
im.to_thumb(256,256)
7369
```
7470

75-
76-
77-
7871
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_8_0.png)
79-
80-
81-
8272

8373
Doing something similar for fresh fruit.
8474

85-
8675
```python
8776
download_url(search_images('fresh fruit', max_images=1)[0], 'fresh.jpg', show_progress=False)
8877
Image.open('fresh.jpg').to_thumb(256,256)
8978
```
79+
9080
```output
9181
Searching for 'fresh fruit'
9282
```
93-
94-
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_10_1.png)
95-
96-
9783

84+
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_10_1.png)
9885

9986
Now that we know what duckduckgo image search is working fine, we can download images for both rotten and fresh fruit and store them in their respective directories. We use time.sleep to avoid spamming the search API.
10087

101-
10288
```python
10389
searches = 'rotten', 'fresh'
10490
path=Path('rotten_or_fresh')
@@ -116,6 +102,7 @@ for o in searches:
116102
download_images(dest, urls=search_images(f'{o} vegetables'))
117103
resize_images(path/o, max_size=400, dest=path/o)
118104
```
105+
119106
```output
120107
Searching for 'rotten fruit'
121108
Searching for 'rotten apple'
@@ -127,14 +114,12 @@ Searching for 'fresh banana'
127114
Searching for 'fresh vegetables'
128115
```
129116

130-
131117
## Training our model
132118

133119
We have our images and the next step is to train a model. Again, it blows my mind how simple this is using fastai. I'll briefly explain what the below blocks of code are doing.
134120

135121
First, we check if all image files can be opened correctly using a fastai vision library utility verify_images. If it can't be opened, then we unlink it from our path so that is is not used in model training.
136122

137-
138123
```python
139124
# validate images
140125
failed=verify_images(get_image_files(path))
@@ -146,21 +131,18 @@ len(failed)
146131
0
147132
```
148133

149-
150-
151134
Next, we'll use another building block from the fastai library, the `DataBlock` class, which we can use to represent our training data, the labels, data splitting criteria, and any data transformations.
152135

153136
`blocks=(ImageBlock, CategoryBlock)` is used to specify what kind of data is in the DataBlock. We have images, and categories - hence a tuple of ImageBlock and CategoryBlock classes.
154137

155-
`get_items` takes the function `get_image_files` as its parameter. `get_image_files` is used to find the paths of our input images.
138+
`get_items` takes the function `get_image_files` as its parameter. `get_image_files` is used to find the paths of our input images.
156139

157-
`splitter=RandomSplitter(valid_pct=0.2, seed=42)` specifies that we want to randomly split our input data into training and validation sets, using 20% data for validation.
140+
`splitter=RandomSplitter(valid_pct=0.2, seed=42)` specifies that we want to randomly split our input data into training and validation sets, using 20% data for validation.
158141

159142
`get_y=parent_label` specifies that the labels for an image file is its parent (the directory that the file belongs to).
160143

161144
`item_tfms=[Resize(192, method='squish')]` specifies the transformation performed on each file. Here we are resizing each image to 192x192 pixels by squishing it. Another option could be to `crop` the image.
162145

163-
164146
```python
165147
dls = DataBlock(
166148
blocks=(ImageBlock, CategoryBlock),
@@ -173,18 +155,12 @@ dls = DataBlock(
173155
dls.show_batch(max_n=6)
174156
```
175157

176-
177-
178158
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_16_0.png)
179159

180-
181-
182-
183160
Above you can see a batch of images from our DataBlock, along with their labels. This is a nice way of quickly knowing if a sample from our data is correct (images/labels).
184161

185162
To train our model we will fine-tune the resnet18, which is one of the most widely used computer vision models, on our dataset.
186163

187-
188164
```python
189165
clf = vision_learner(dls, resnet18, metrics=error_rate)
190166
clf.fine_tune(5)
@@ -211,7 +187,6 @@ clf.fine_tune(5)
211187
</tbody>
212188
</table>
213189

214-
215190
<table border="1" class="dataframe">
216191
<thead>
217192
<tr style="text-align: left;">
@@ -261,17 +236,15 @@ clf.fine_tune(5)
261236
</tbody>
262237
</table>
263238

264-
265239
## Using the model
266240

267241
It's finally time to use our model and see how it does predicting if a fruit is rotten or not.
268242

269-
270243
```python
271244
Image.open('rotten.jpg').to_thumb(256,256)
272245
```
273-
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_20_0.png)
274246

247+
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_20_0.png)
275248

276249
<br />
277250

@@ -292,21 +265,14 @@ Probability it's rotten: 1.0000
292265
Image.open('fresh.jpg').to_thumb(256,256)
293266
```
294267

295-
296-
297-
298-
299268
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_22_0.png)
300-
301-
302-
303-
304269

305270
```python
306271
is_rotten,_,probs = clf.predict(PILImage.create('fresh.jpg'))
307272
print(f"This fruit/vegetable is: {is_rotten}.")
308273
print(f"Probability it's fresh: {probs[0]:.4f}")
309274
```
275+
310276
```output
311277
This fruit/vegetable is: fresh.
312278
Probability it's fresh: 1.0000
@@ -316,23 +282,19 @@ Probability it's fresh: 1.0000
316282

317283
Let's see if our model can predict if a given image is of a rotten orange or a fresh orange. We haven't explicitly downloaded images of fresh/rotten oranges for our training set, so it would be a good generalization on "unseen data".
318284

319-
320285
```python
321286
download_url(search_images('fresh orange', max_images=1)[0], 'fresh orange.jpg', show_progress=False)
322287
Image.open('fresh orange.jpg').to_thumb(256,256)
323288
```
324-
325-
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_25_1.png)
326-
327-
328-
329289

290+
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_25_1.png)
330291

331292
```python
332293
is_rotten,_,probs = clf.predict(PILImage.create('fresh orange.jpg'))
333294
print(f"This fruit/vegetable is: {is_rotten}.")
334295
print(f"Probability it's fresh: {probs[0]:.4f}")
335296
```
297+
336298
```output
337299
This fruit/vegetable is: fresh.
338300
Probability it's fresh: 0.9748
@@ -345,31 +307,31 @@ download_url(search_images('rotten orange', max_images=1)[0], 'rotten orange.jpg
345307
Image.open('rotten orange.jpg').to_thumb(256,256)
346308
```
347309

348-
349310
![rotten_or_not](@assets/images/blog/building-image-classifier-fastai/is-the-fruit-rotten-or-not_27_1.png)
350311

351-
352312
```python
353313
is_rotten,_,probs = clf.predict(PILImage.create('rotten orange.jpg'))
354314
print(f"This fruit/vegetable is: {is_rotten}.")
355315
print(f"Probability it's rotten: {probs[1]:.4f}")
356316
```
317+
357318
```output
358319
This fruit/vegetable is: rotten.
359320
Probability it's rotten: 0.9899
360321
```
361322

362-
Not bad at all. The model seems to generalize fine. Though, a more accurate measure of generalizability would involve creating a separate test set and calculating performance metrics.
323+
Not bad at all. The model seems to generalize fine. Though, a more accurate measure of generalizability would involve creating a separate test set and calculating performance metrics.
363324

364325
## Summary
365326

366327
There you have it! With a few lines of code we have created our own image classification model by fine-tuning off the shelf models with fastai. The high level apis that the library provides makes the process of building an initial model a breeze.
367-
If you want to run the notebook for yourself, you can check it out on Kaggle [here](https://www.kaggle.com/code/sajalsharma26/is-the-fruit-rotten-or-not). I urge you to try building your own
328+
If you want to run the notebook for yourself, you can check it out on Kaggle [here](https://www.kaggle.com/code/sajalsharma26/is-the-fruit-rotten-or-not). I urge you to try building your own
368329
classification model on images from duckduckgo search.
369330

370331
I'll be going over the rest of the fastai course in the coming weeks. Even though I have only done the first two weeks till now, I highly recommend it for anyone
371332
interested in Machine Learning, more so for people with a coding background.
372333

373334
## Resources
335+
374336
- fastai Course: https://course.fast.ai/
375-
- Notebook on Kaggle: https://www.kaggle.com/code/sajalsharma26/is-the-fruit-rotten-or-not
337+
- Notebook on Kaggle: https://www.kaggle.com/code/sajalsharma26/is-the-fruit-rotten-or-not

0 commit comments

Comments
 (0)