TensorFlow.js Transfer Learning Tutorial
Transfer learning allows you to take a pre-trained model and adapt it for your specific use case with minimal training data.
Transfer Learning with TensorFlow.js#
Transfer learning allows you to take a pre-trained model and adapt it for your specific use case with minimal training data. This is one of the most powerful techniques in modern machine learning.
What You'll Learn#
- Understanding transfer learning concepts
- Using pre-trained models as feature extractors
- Fine-tuning existing models for custom datasets
- Building image classifiers with minimal data
- Real-time webcam classification
Installation#
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/knn-classifier"></script>1. Understanding Transfer Learning#
<script>
function explainTransferLearning() {
const explanation = `
<h4>๐ง Transfer Learning Explained:</h4>
<div style="background: #f0f8ff; padding: 20px; border-radius: 8px; margin: 15px 0;">
<h5>What is Transfer Learning?</h5>
<p>Transfer learning uses knowledge from a pre-trained model (trained on millions of images)
and applies it to your specific task with just a few examples.</p>
<h5>Why is it Powerful?</h5>
<ul>
<li><strong>Less Data:</strong> Need only 10-20 examples per class</li>
<li><strong>Faster Training:</strong> Minutes instead of hours/days</li>
<li><strong>Better Results:</strong> Leverages proven feature extraction</li>
<li><strong>Lower Compute:</strong> Runs in browser without GPU</li>
</ul>
<h5>How it Works:</h5>
<ol>
<li>Load pre-trained MobileNet (trained on ImageNet)</li>
<li>Remove the final classification layer</li>
<li>Use it as a feature extractor</li>
<li>Train a simple classifier on extracted features</li>
</ol>
</div>
`;
document.getElementById('explanation-output').innerHTML = explanation;
}
explainTransferLearning();
</script>
<div id="explanation-output"></div>2. Feature Extraction with MobileNet#
<script>
let mobilenet;
let isModelLoaded = false;
async function loadMobileNet() {
const statusDiv = document.getElementById('mobilenet-status');
statusDiv.innerHTML = '<p>๐ Loading MobileNet for feature extraction...</p>';
try {
mobilenet = await tf.loadLayersModel('https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/4/default/1', {fromTFHub: true});
isModelLoaded = true;
statusDiv.innerHTML = '<p>โ
MobileNet loaded! Ready for feature extraction.</p>';
console.log('MobileNet loaded for transfer learning');
} catch (error) {
console.log('Using alternative loading method...');
// Alternative: Use the mobilenet package
mobilenet = await mobilenet.load({version: 2, alpha: 1.0});
isModelLoaded = true;
statusDiv.innerHTML = '<p>โ
MobileNet loaded via alternative method!</p>';
}
}
async function extractFeatures(imageElement) {
if (!isModelLoaded) {
throw new Error('MobileNet not loaded yet');
}
// Preprocess image
const tensor = tf.browser.fromPixels(imageElement)
.resizeNearestNeighbor([224, 224])
.toFloat()
.div(255.0)
.expandDims();
// Extract features (remove last classification layer)
let features;
if (mobilenet.predict) {
// Using the layers model
features = mobilenet.predict(tensor);
} else {
// Using mobilenet package - get intermediate activations
features = mobilenet.infer(tensor, 'conv_preds');
}
tensor.dispose();
return features;
}
async function demonstrateFeatureExtraction() {
if (!isModelLoaded) {
await loadMobileNet();
}
const output = document.getElementById('features-output');
output.innerHTML = '<p>๐ Extracting features from sample images...</p>';
// Create sample images
const images = [
'https://images.unsplash.com/photo-1546598300-f5d62e0b7b9b?w=224&h=224&fit=crop',
'https://images.unsplash.com/photo-1495052384700-271d7c5f5e8c?w=224&h=224&fit=crop',
'https://images.unsplash.com/photo-1503803548695-c2a7b4a5b875?w=224&h=224&fit=crop'
];
const labels = ['Dog', 'Cat', 'Car'];
let resultHTML = '<h4>Feature Extraction Results:</h4>';
resultHTML += '<div style="display: flex; gap: 15px; flex-wrap: wrap;">';
for (let i = 0; i {
img.onload = async () => {
try {
const features = await extractFeatures(img);
const featureVector = features.dataSync();
resultHTML += `
<div style="border: 1px solid #ddd; padding: 10px; border-radius: 8px; text-align: center;">
<img src="${images[i]}" width="100" height="100" style="object-fit: cover; border-radius: 4px;">
<h6>${labels[i]}</h6>
<p>Features: ${featureVector.length}D vector</p>
<p>Sample values: [${featureVector.slice(0, 3).map(v => v.toFixed(3)).join(', ')}...]</p>
</div>
`;
features.dispose();
resolve();
} catch (error) {
console.error('Feature extraction failed:', error);
resolve();
}
};
img.src = images[i];
});
}
resultHTML += '</div>';
resultHTML += '<p><em>These feature vectors can now be used to train a custom classifier!</em></p>';
output.innerHTML = resultHTML;
}
loadMobileNet();
</script>
<div id="mobilenet-status"></div>
<button onclick="demonstrateFeatureExtraction()"
style="padding: 10px 20px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; margin: 10px 0;">
Extract Features from Sample Images
</button>
<div id="features-output"></div>3. K-Nearest Neighbors Classifier#
<script>
let knnClassifier;
let customModel = {
mobilenet: null,
knn: null,
isReady: false
};
async function initializeKNN() {
const output = document.getElementById('knn-output');
output.innerHTML = '<p>๐ Initializing KNN classifier...</p>';
try {
// Load MobileNet for feature extraction
customModel.mobilenet = await mobilenet.load();
// Initialize KNN classifier
customModel.knn = knnClassifier.create();
customModel.isReady = true;
output.innerHTML = `
<div style="background: #e8f5e8; padding: 15px; border-radius: 8px;">
<h4>โ
Custom Classifier Ready!</h4>
<p>You can now train your own image classifier by adding examples below.</p>
<p><strong>Instructions:</strong></p>
<ol>
<li>Click "Add Example" buttons to train on different categories</li>
<li>Add at least 3-5 examples per category</li>
<li>Test your classifier with new images</li>
</ol>
</div>
`;
setupTrainingInterface();
} catch (error) {
output.innerHTML = '<p>โ Error initializing classifier. Please refresh and try again.</p>';
console.error('KNN initialization error:', error);
}
}
function setupTrainingInterface() {
const container = document.getElementById('training-interface');
container.innerHTML = `
<div style="border: 2px solid #ddd; padding: 20px; border-radius: 8px; margin: 20px 0;">
<h4>๐ฏ Train Your Custom Classifier</h4>
<div style="margin: 15px 0;">
<h5>Category 1: Dogs</h5>
<button onclick="addTrainingExample(0, 'https://images.unsplash.com/photo-1546598300-f5d62e0b7b9b?w=224')"
style="padding: 8px 16px; background: #FF9800; color: white; border: none; border-radius: 4px; margin: 5px;">
Add Dog Example 1
</button>
<button onclick="addTrainingExample(0, 'https://images.unsplash.com/photo-1548199973-03cce0bbc87b?w=224')"
style="padding: 8px 16px; background: #FF9800; color: white; border: none; border-radius: 4px; margin: 5px;">
Add Dog Example 2
</button>
<button onclick="addTrainingExample(0, 'https://images.unsplash.com/photo-1561037404-61cd46aa615b?w=224')"
style="padding: 8px 16px; background: #FF9800; color: white; border: none; border-radius: 4px; margin: 5px;">
Add Dog Example 3
</button>
<span id="dog-count" style="margin-left: 10px; font-weight: bold;">Examples: 0</span>
</div>
<div style="margin: 15px 0;">
<h5>Category 2: Cats</h5>
<button onclick="addTrainingExample(1, 'https://images.unsplash.com/photo-1495052384700-271d7c5f5e8c?w=224')"
style="padding: 8px 16px; background: #9C27B0; color: white; border: none; border-radius: 4px; margin: 5px;">
Add Cat Example 1
</button>
<button onclick="addTrainingExample(1, 'https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?w=224')"
style="padding: 8px 16px; background: #9C27B0; color: white; border: none; border-radius: 4px; margin: 5px;">
Add Cat Example 2
</button>
<button onclick="addTrainingExample(1, 'https://images.unsplash.com/photo-1516728778615-2d590ea185ee?w=224')"
style="padding: 8px 16px; background: #9C27B0; color: white; border: none; border-radius: 4px; margin: 5px;">
Add Cat Example 3
</button>
<span id="cat-count" style="margin-left: 10px; font-weight: bold;">Examples: 0</span>
</div>
<div style="margin: 20px 0; padding: 15px; background: #f9f9f9; border-radius: 6px;">
<h5>๐งช Test Your Classifier</h5>
<button onclick="testClassifier('https://images.unsplash.com/photo-1543466835-00a7907e9de1?w=224')"
style="padding: 8px 16px; background: #2196F3; color: white; border: none; border-radius: 4px; margin: 5px;">
Test Dog Image
</button>
<button onclick="testClassifier('https://images.unsplash.com/photo-1519052537078-e6302a4968d4?w=224')"
style="padding: 8px 16px; background: #2196F3; color: white; border: none; border-radius: 4px; margin: 5px;">
Test Cat Image
</button>
</div>
</div>
<div id="training-results"></div>
`;
}
let dogCount = 0;
let catCount = 0;
async function addTrainingExample(classId, imageUrl) {
if (!customModel.isReady) {
alert('Model not ready yet. Please wait...');
return;
}
const resultsDiv = document.getElementById('training-results');
resultsDiv.innerHTML = '<p>๐ Adding training example...</p>';
try {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = async () => {
// Get features from MobileNet
const features = customModel.mobilenet.infer(img, true);
// Add example to KNN classifier
customModel.knn.addExample(features, classId);
// Update counters
if (classId === 0) {
dogCount++;
document.getElementById('dog-count').textContent = `Examples: ${dogCount}`;
} else {
catCount++;
document.getElementById('cat-count').textContent = `Examples: ${catCount}`;
}
resultsDiv.innerHTML = `
<p>โ
Added example for ${classId === 0 ? 'Dogs' : 'Cats'}!
Total examples: Dogs(${dogCount}), Cats(${catCount})</p>
`;
features.dispose();
};
img.src = imageUrl;
} catch (error) {
resultsDiv.innerHTML = '<p>โ Error adding example. Please try again.</p>';
console.error('Training error:', error);
}
}
async function testClassifier(imageUrl) {
if (!customModel.isReady) {
alert('Model not ready yet. Please wait...');
return;
}
if (dogCount === 0 || catCount === 0) {
alert('Please add training examples for both categories first!');
return;
}
const resultsDiv = document.getElementById('training-results');
resultsDiv.innerHTML = '<p>๐ง Classifying image...</p>';
try {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = async () => {
// Extract features
const features = customModel.mobilenet.infer(img, true);
// Classify
const prediction = await customModel.knn.predictClass(features);
const className = prediction.label === '0' ? 'Dog' : 'Cat';
const confidence = Object.values(prediction.confidences);
const maxConfidence = Math.max(...confidence) * 100;
resultsDiv.innerHTML = `
<div style="background: #e3f2fd; padding: 15px; border-radius: 8px; margin: 10px 0;">
<h4>๐ฏ Classification Result</h4>
<div style="display: flex; align-items: center; gap: 15px;">
<img src="${imageUrl}" width="100" height="100" style="object-fit: cover; border-radius: 4px;">
<div>
<p><strong>Prediction: ${className}</strong></p>
<p>Confidence: ${maxConfidence.toFixed(1)}%</p>
<p>Dog: ${(prediction.confidences['0'] * 100).toFixed(1)}%</p>
<p>Cat: ${(prediction.confidences['1'] * 100).toFixed(1)}%</p>
</div>
</div>
</div>
`;
features.dispose();
};
img.src = imageUrl;
} catch (error) {
resultsDiv.innerHTML = '<p>โ Error classifying image. Please try again.</p>';
console.error('Classification error:', error);
}
}
// Initialize when page loads
initializeKNN();
</script>
<div id="knn-output"></div>
<div id="training-interface"></div>Exercise
Try it
Solution
<script>
// Challenge: Build a complete transfer learning application that:
// 1. Loads a pre-trained model
// 2. Allows users to upload training images
// 3. Trains a custom classifier
// 4. Evaluates performance
// 5. Exports the trained model
class TransferLearningPipeline {
constructor() {
this.baseModel = null;
this.classifier = null;
this.trainingData = {};
this.isReady = false;
}
async initialize() {
// TODO: Implement complete pipeline
document.getElementById('pipeline-output').innerHTML = 'TODO: Build complete transfer learning pipeline';
}
async uploadTrainingImages(files, className) {
// TODO: Handle file uploads
// TODO: Process images and extract features
// TODO: Store training data
}
async trainClassifier() {
// TODO: Train custom classifier on collected data
// TODO: Show training progress
// TODO: Validate performance
}
async exportModel() {
// TODO: Save trained model
// TODO: Generate deployment code
}
}
const pipeline = new TransferLearningPipeline();
// Uncomment to start the challenge
// pipeline.initialize();
</script>
<div style="border: 2px dashed #ccc; padding: 20px; margin: 20px 0; text-align: center;">
<h4>๐ Master Challenge: Complete Transfer Learning Pipeline</h4>
<p>Build a production-ready transfer learning application with file upload, training, and model export!</p>
<button onclick="pipeline.initialize()"
style="padding: 12px 24px; background: #673AB7; color: white; border: none; border-radius: 6px; cursor: pointer;">
Start Master Challenge
</button>
</div>
<div id="pipeline-output"></div>Get the JavaScript agent pack
A battle-tested AGENTS.md, the review checklist, and the failure-mode cheat sheet for JavaScript. One email, then occasional updates when the tooling shifts. No course pitch.
AGENTS.md now โ no email needed.