# TensorFlow.js Transfer Learning Tutorial

> Source: https://learn-javascript.org/tensorflow-transfer-learning/
> Part of Learn JavaScript, free to read.

## 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

          
```javascript
<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

          
```javascript
<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

          
```javascript
<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

          
```javascript
<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>
```
