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.js Image Class Object Detection Pose Detection Face Detection Text Analysis Custom 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 روشن است.
٪۴۱
دوره اختصاصی INZIP
آموزش حرفه ای HTML از صفر در ۱۶ ویدیو: سند، متن، لینک، تصویر، جدول، فرم، معناییسازی، دسترسپذیری و سئو، تا پروژهٔ کامل صفحهٔ فروشگاه محصول.
تماشای آنلاین + دانلود
دسترسی آنی و همیشگی
بهروزرسانی رایگان
کیفیت Full HD
۹۹۰,۰۰۰ تومان
۵۹۰,۰۰۰ تومان
سود شما ۴۰۰,۰۰۰ تومان
مشاهده سریال