Machine Learning در مرورگر با Vue و TensorFlow.js

۱۴۰۵/۰۸/۱۳ | چهارشنبه، ۱۳ آبان
دوره آموزشی ویژه 4 اپیزود اول تمام دوره های آموزشی ویدیویی رایگان میباشد دانلود رایگان

دورهٔ جامع CSS از صفر

آموزش CSS از صفر در ۲۲ ویدیو: مدل جعبه، انتخاب‌گر، فلکس‌باکس، گرید، واکنش‌گرایی، متغیرها، انیمیشن و معماری، تا پروژهٔ کامل صفحهٔ محصول؛ کد کنار خروجی ...

مدرس دوره : تیم 22 اپیزود ویدیویی 03 ساعت و 33 دقیقه و 59 ثانیه آموزش ویدیویی
متن پرونده شماره 486 - ویو جی اس

TensorFlow.js امکان اجرای مدل‌های Machine Learning را مستقیماً در مرورگر فراهم می‌کند. در این مقاله، یاد می‌گیریم چگونه با Vue و TensorFlow.js اپلیکیشن‌های هوشمند بسازیم - از image classification تا pose detection و object recognition در real-time.

چرا ML در مرورگر

اجرای Machine Learning در مرورگر مزایای چشمگیری دارد. اول، privacy. داده‌های کاربر هرگز سرور را ترک نمی‌کنند. برای اپ‌هایی مانند تشخیص چهره یا پزشکی، این بسیار مهم است. دوم، latency. بدون نیاز به round-trip به سرور، نتایج فوری هستند.

سوم، cost. بدون نیاز به سرورهای GPU گران‌قیمت. محاسبات روی device کاربر انجام می‌شود. چهارم، offline capability. اپ حتی بدون اینترنت کار می‌کند. پنجم، scalability. با افزایش کاربران، نیازی به scale کردن سرور نیست.

البته محدودیت‌هایی هم وجود دارد. mobile devices قدرت پردازش کمتری دارند. مدل‌های بزرگ قابل اجرا در مرورگر نیستند. برای این موارد، باید از cloud services استفاده کنید. اما برای بسیاری از use cases، TensorFlow.js کاملاً کافی است.

نصب و شروع

TensorFlow.js چندین backend دارد که performance متفاوتی ارائه می‌دهند. WebGL سریع‌ترین است و WASM برای سازگاری بهتر.

npm install @tensorflow/tfjs

# برای models آماده
npm install @tensorflow-models/mobilenet
npm install @tensorflow-models/coco-ssd
npm install @tensorflow-models/pose-detection
npm install @tensorflow-models/face-detection

// composables/useTensorflow.js
import { ref, onMounted } from "vue"
import * as tf from "@tensorflow/tfjs"

export function useTensorflow() {
  const isReady = ref(false)
  const backend = ref("")

  onMounted(async () => {
    // تنظیم backend
    await tf.setBackend("webgl")
    await tf.ready()

    backend.value = tf.getBackend()
    isReady.value = true

    console.log("TensorFlow.js ready!")
    console.log("Backend:", backend.value)
    console.log("Version:", tf.version.tfjs)
  })

  return { isReady, backend, tf }
}
WebGL backend از GPU کاربر برای acceleration استفاده می‌کند و معمولاً 10-100 برابر سریع‌تر از CPU است. اما در برخی mobile devices ممکن است مشکل داشته باشد که در این صورت به WASM یا CPU fallback می‌شود.

Image Classification با MobileNet

MobileNet یک مدل سبک برای classification تصاویر است. در تنها چند خط کد می‌توانید تصاویر را به 1000 کلاس مختلف طبقه‌بندی کنید.

// composables/useImageClassifier.js
import { ref, shallowRef } from "vue"
import * as mobilenet from "@tensorflow-models/mobilenet"

export function useImageClassifier() {
  const model = shallowRef(null)
  const loading = ref(false)
  const classifying = ref(false)
  const results = ref([])

  async function loadModel() {
    loading.value = true
    try {
      model.value = await mobilenet.load({
        version: 2,
        alpha: 1.0 // 0.25, 0.5, 0.75, 1.0 - دقت در برابر سرعت
      })
      console.log("Model loaded!")
    } finally {
      loading.value = false
    }
  }

  async function classify(imageElement) {
    if (!model.value) await loadModel()

    classifying.value = true
    try {
      const predictions = await model.value.classify(imageElement, 5)
      results.value = predictions.map(p => ({
        label: p.className,
        confidence: (p.probability * 100).toFixed(2)
      }))
      return results.value
    } finally {
      classifying.value = false
    }
  }

  return { model, loading, classifying, results, loadModel, classify }
}

// Component - آپلود تصویر و classify
<!-- components/ImageClassifier.vue -->
<script setup>
import { ref, onMounted } from "vue"
import { useImageClassifier } from "@/composables/useImageClassifier"

const { loading, classifying, results, loadModel, classify } = useImageClassifier()

const imagePreview = ref(null)
const imageRef = ref(null)

onMounted(loadModel)

function handleFileSelect(event) {
  const file = event.target.files[0]
  if (!file) return

  const reader = new FileReader()
  reader.onload = async (e) => {
    imagePreview.value = e.target.result
    // صبر برای load شدن image
    await new Promise(resolve => setTimeout(resolve, 100))
    if (imageRef.value) {
      await classify(imageRef.value)
    }
  }
  reader.readAsDataURL(file)
}
</script>

<template>
  <div class="image-classifier">
    <h2>تشخیص تصویر</h2>

    <div v-if="loading" class="status">در حال بارگذاری مدل...</div>

    <div v-else>
      <input
        type="file"
        accept="image/*"
        @change="handleFileSelect"
      />

      <div v-if="imagePreview" class="preview">
        <img
          ref="imageRef"
          :src="imagePreview"
          crossorigin="anonymous"
          alt="Preview"
        />

        <div v-if="classifying">در حال تشخیص...</div>

        <div v-else-if="results.length" class="results">
          <h3>نتایج:</h3>
          <div
            v-for="result in results"
            :key="result.label"
            class="result-item"
          >
            <div class="label">{{ result.label }}</div>
            <div class="bar">
              <div
                class="fill"
                :style="{ width: result.confidence + \"%\" }"
              ></div>
              <span>{{ result.confidence }}%</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
محصول اورجینال INZIP
قالب وردپرس باریستا مخصوص کافه تم نسکافه ای روشن (دو زبانه)

قالب وردپرس باریستا مخصوص کافه تم نسکافه ای روشن (دو زبانه)

دانلود پوسته وردپرس باریستا؛ قالب کافیشاپ، رُستری قهوه و فروشگاه قهوه دوزبانه با منوی رومیزی، رزرو آنلاین میز با کد پیامکی و ووکامرس. طراحی اختصاصی inzip.ir

تحویل آنی آپدیت رایگان بدون قفل لایسنس پشتیبانی واقعی
۳,۹۹۰,۰۰۰ تومان ۲,۹۶۰,۰۰۰ تومان
بازدید و دانلود آنی
٪۲۶
تخفیف ویژه
سود شما
۱,۰۳۰,۰۰۰ تومان

Object Detection با COCO-SSD

COCO-SSD می‌تواند multiple objects را در یک تصویر شناسایی کند و bounding box آن‌ها را برگرداند. فوق‌العاده برای camera applications.

// composables/useObjectDetection.js
import { ref, shallowRef } from "vue"
import * as cocoSsd from "@tensorflow-models/coco-ssd"

export function useObjectDetection() {
  const model = shallowRef(null)
  const loading = ref(false)
  const detections = ref([])

  async function loadModel() {
    loading.value = true
    try {
      model.value = await cocoSsd.load({
        base: "mobilenet_v2" // lite_mobilenet_v2, mobilenet_v1, mobilenet_v2
      })
    } finally {
      loading.value = false
    }
  }

  async function detect(imageOrVideo) {
    if (!model.value) await loadModel()
    detections.value = await model.value.detect(imageOrVideo)
    return detections.value
  }

  return { model, loading, detections, loadModel, detect }
}

// Real-time detection از webcam
<!-- components/ObjectDetector.vue -->
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue"
import { useObjectDetection } from "@/composables/useObjectDetection"

const { loading, loadModel, detect } = useObjectDetection()
const videoRef = ref(null)
const canvasRef = ref(null)
const isDetecting = ref(false)
const fps = ref(0)

let stream = null
let animationId = null

async function startCamera() {
  stream = await navigator.mediaDevices.getUserMedia({
    video: { facingMode: "user" }
  })
  videoRef.value.srcObject = stream

  await new Promise(resolve => {
    videoRef.value.onloadedmetadata = resolve
  })

  await loadModel()
  startDetection()
}

async function startDetection() {
  isDetecting.value = true
  let lastTime = performance.now()
  let frameCount = 0

  async function loop() {
    if (!isDetecting.value) return

    const predictions = await detect(videoRef.value)
    drawDetections(predictions)

    // محاسبه FPS
    frameCount++
    const now = performance.now()
    if (now - lastTime > 1000) {
      fps.value = frameCount
      frameCount = 0
      lastTime = now
    }

    animationId = requestAnimationFrame(loop)
  }

  loop()
}

function drawDetections(predictions) {
  const canvas = canvasRef.value
  const ctx = canvas.getContext("2d")
  canvas.width = videoRef.value.videoWidth
  canvas.height = videoRef.value.videoHeight

  ctx.drawImage(videoRef.value, 0, 0)

  predictions.forEach(pred => {
    const [x, y, width, height] = pred.bbox

    // Bounding box
    ctx.strokeStyle = "#660000"
    ctx.lineWidth = 3
    ctx.strokeRect(x, y, width, height)

    // Label background
    const label = pred.class + " " + Math.round(pred.score * 100) + "%"
    ctx.font = "16px sans-serif"
    const textWidth = ctx.measureText(label).width

    ctx.fillStyle = "#660000"
    ctx.fillRect(x, y - 25, textWidth + 10, 25)

    // Label text
    ctx.fillStyle = "#ffffff"
    ctx.fillText(label, x + 5, y - 7)
  })
}

function stopDetection() {
  isDetecting.value = false
  if (animationId) cancelAnimationFrame(animationId)
  stream?.getTracks().forEach(t => t.stop())
}

onMounted(startCamera)
onBeforeUnmount(stopDetection)
</script>

<template>
  <div class="object-detector">
    <div class="status">
      <span v-if="loading">در حال بارگذاری مدل...</span>
      <span v-else>FPS: {{ fps }}</span>
    </div>

    <div class="video-container">
      <video ref="videoRef" autoplay muted playsinline style="display: none;"></video>
      <canvas ref="canvasRef"></canvas>
    </div>
  </div>
</template>

Pose Detection

Pose Detection skeleton انسان را در real-time شناسایی می‌کند. فوق‌العاده برای fitness apps، AR filters و game development.

import * as poseDetection from "@tensorflow-models/pose-detection"

// composables/usePoseDetection.js
import { ref, shallowRef } from "vue"

export function usePoseDetection() {
  const detector = shallowRef(null)
  const loading = ref(false)
  const poses = ref([])

  async function loadDetector() {
    loading.value = true
    try {
      detector.value = await poseDetection.createDetector(
        poseDetection.SupportedModels.MoveNet,
        {
          modelType: poseDetection.movenet.modelType.SINGLEPOSE_LIGHTNING
        }
      )
    } finally {
      loading.value = false
    }
  }

  async function estimatePoses(image) {
    if (!detector.value) await loadDetector()
    poses.value = await detector.value.estimatePoses(image)
    return poses.value
  }

  function drawSkeleton(ctx, pose, color = "#660000") {
    const connections = [
      [5, 6], [5, 7], [7, 9], [6, 8], [8, 10], // arms
      [5, 11], [6, 12], [11, 12], // torso
      [11, 13], [13, 15], [12, 14], [14, 16] // legs
    ]

    const minConfidence = 0.3

    // Draw connections
    ctx.strokeStyle = color
    ctx.lineWidth = 3
    connections.forEach(([i, j]) => {
      const kp1 = pose.keypoints[i]
      const kp2 = pose.keypoints[j]

      if (kp1.score > minConfidence && kp2.score > minConfidence) {
        ctx.beginPath()
        ctx.moveTo(kp1.x, kp1.y)
        ctx.lineTo(kp2.x, kp2.y)
        ctx.stroke()
      }
    })

    // Draw keypoints
    pose.keypoints.forEach(kp => {
      if (kp.score > minConfidence) {
        ctx.beginPath()
        ctx.arc(kp.x, kp.y, 5, 0, 2 * Math.PI)
        ctx.fillStyle = "#F095A5"
        ctx.fill()
      }
    })
  }

  return { detector, loading, poses, loadDetector, estimatePoses, drawSkeleton }
}

// استفاده: Fitness app - شمارش squat
<script setup>
import { ref, computed } from "vue"
import { usePoseDetection } from "@/composables/usePoseDetection"

const { estimatePoses, drawSkeleton } = usePoseDetection()
const squatCount = ref(0)
const state = ref("up") // up or down

function detectSquat(pose) {
  const leftHip = pose.keypoints[11]
  const leftKnee = pose.keypoints[13]
  const leftAnkle = pose.keypoints[15]

  if (leftHip.score < 0.5 || leftKnee.score < 0.5) return

  // محاسبه زاویه زانو
  const angle = calculateAngle(leftHip, leftKnee, leftAnkle)

  if (angle < 90 && state.value === "up") {
    state.value = "down"
  } else if (angle > 160 && state.value === "down") {
    state.value = "up"
    squatCount.value++
  }
}

function calculateAngle(a, b, c) {
  const radians = Math.atan2(c.y - b.y, c.x - b.x) -
                  Math.atan2(a.y - b.y, a.x - b.x)
  let angle = Math.abs(radians * 180.0 / Math.PI)
  if (angle > 180) angle = 360 - angle
  return angle
}
</script>
کاربردهای TensorFlow.jsImage ClassObject DetectionPose DetectionFace DetectionText AnalysisCustom Models

Custom Models

علاوه بر مدل‌های آماده، می‌توانید custom models از Python/TensorFlow را به TensorFlow.js تبدیل و استفاده کنید.

# Convert Python Keras model to TF.js
pip install tensorflowjs
tensorflowjs_converter --input_format keras \
  model.h5 \
  web_model/

# استفاده در Vue
import * as tf from "@tensorflow/tfjs"

async function loadCustomModel() {
  const model = await tf.loadLayersModel("/models/my_model/model.json")
  return model
}

// پیش‌بینی با custom model
async function predict(input) {
  const model = await loadCustomModel()

  // Preprocess input
  const tensor = tf.browser.fromPixels(input)
    .resizeNearestNeighbor([224, 224])
    .toFloat()
    .div(255.0)
    .expandDims()

  // Prediction
  const prediction = await model.predict(tensor)
  const data = await prediction.data()

  // Cleanup
  tensor.dispose()
  prediction.dispose()

  return Array.from(data)
}

// Transfer learning - آموزش مدل جدید در مرورگر
async function trainModel(trainingData) {
  const model = tf.sequential({
    layers: [
      tf.layers.dense({ units: 128, activation: "relu", inputShape: [784] }),
      tf.layers.dropout({ rate: 0.2 }),
      tf.layers.dense({ units: 10, activation: "softmax" })
    ]
  })

  model.compile({
    optimizer: "adam",
    loss: "categoricalCrossentropy",
    metrics: ["accuracy"]
  })

  const { xs, ys } = trainingData

  await model.fit(xs, ys, {
    epochs: 10,
    batchSize: 32,
    validationSplit: 0.2,
    callbacks: {
      onEpochEnd: (epoch, logs) => {
        console.log("Epoch " + epoch + ":", logs)
      }
    }
  })

  // Save model
  await model.save("downloads://my-model")
}

Performance Optimization

برای performance بهتر، نکات زیر را رعایت کنید.

// Memory management
// همیشه tensors را dispose کنید
const tensor = tf.tensor([1, 2, 3])
// ... use it
tensor.dispose()

// یا با tidy برای cleanup خودکار
const result = tf.tidy(() => {
  const a = tf.tensor([1, 2, 3])
  const b = tf.tensor([4, 5, 6])
  return a.add(b) // فقط این باقی می‌ماند، a و b dispose می‌شوند
})

// Model warming - اولین prediction کند است
async function warmupModel(model) {
  const dummyInput = tf.zeros([1, 224, 224, 3])
  await model.predict(dummyInput).data()
  dummyInput.dispose()
}

// Reduce model size
await tf.loadLayersModel("/model.json", {
  weightPathPrefix: "/weights/",
  requestInit: { cache: "force-cache" }
})

// Monitor memory
console.log(tf.memory())
// { numTensors, numDataBuffers, numBytes, unreliable, reasons }

بهترین شیوه‌ها

برای ساخت ML apps موفق، این نکات را رعایت کنید. اول، به حجم مدل‌ها توجه کنید. مدل‌های بزرگ (>50MB) برای mobile مناسب نیستند. دوم، lazy loading مدل‌ها. فقط زمان نیاز load کنید.

سوم، به battery drain توجه کنید. ML محاسبات سنگینی دارد. وقتی نیاز ندارید، detection را متوقف کنید. چهارم، quantized models کوچک‌تر و سریع‌ترند. پنجم، به mobile GPU ها توجه کنید. برخی ضعیف هستند. CPU fallback داشته باشید.

ششم، UX مناسب. loading indicators ضروری هستند. اولین load چند ثانیه طول می‌کشد. هفتم، به accessibility توجه کنید. ML نباید جایگزین controls معمولی باشد. هشتم، به privacy اشاره کنید. حتی اگر data محلی پردازش می‌شود، به کاربر اطلاع دهید.

نهم، edge cases را handle کنید. مدل‌ها همیشه درست کار نمی‌کنند. دهم، به limitations واقعی مدل‌ها آگاه باشید. accuracy همیشه 100% نیست. یازدهم، continuous evaluation. accuracy در شرایط real-world ممکن است متفاوت باشد.

Machine Learning در مرورگر مرز جدیدی در توسعه وب است. با TensorFlow.js می‌توانید اپلیکیشن‌هایی بسازید که قابلیت‌های AI را به دست کاربران می‌رسانند بدون هزینه سرور. آینده client-side AI روشن است.
برچسب‌های این مقاله
  • Vue
  • TensorFlow.js
  • Machine Learning
  • AI
  • Image Classification
  • Object Detection
  • Pose Detection
٪۴۱
دوره اختصاصی INZIP

دورهٔ جامع HTML از صفر

آموزش حرفه ای HTML از صفر در ۱۶ ویدیو: سند، متن، لینک، تصویر، جدول، فرم، معنایی‌سازی، دسترس‌پذیری و سئو، تا پروژهٔ کامل صفحهٔ فروشگاه محصول.

تماشای آنلاین + دانلود دسترسی آنی و همیشگی به‌روزرسانی رایگان کیفیت Full HD
۹۹۰,۰۰۰ تومان ۵۹۰,۰۰۰ تومان سود شما ۴۰۰,۰۰۰ تومان
مشاهده سریال