תארו לעצמכם שמשתמש מקליד "כלב על החוף" והאפליקציה מציגה מיד את כל התמונות של כלב על החוף—ללא תגיות, ללא סידור ידני. זהו חיפוש תמונות סמנטי המופעל על ידי CLIP (Contrastive Language-Image Pre-training) מבית OpenAI. אנו מיישמים אותו כולו על המכשיר: תמונות וטקסטים מומרים לוקטורים בני 512 ממדים, והדמיון הקוסינוסי ביניהם קובע את הרלוונטיות. שום נתון לא עוזב את המכשיר—פרטיות המשתמש נשמרת. הניסיון שלנו עם MobileCLIP-S0 ומאגרי וקטורים מאפשר לנו לפרוס פתרון כזה תוך 1–4 שבועות.
העריכו את הפוטנציאל עבור האפליקציה שלכם. החיסכון בהשוואה לחיפוש בענן מגיע ל-80% הודות לעלויות חיזוי אפסיות. חיפוש CLIP על המכשיר מהיר פי 5 מהענן הודות לחיזוי מקומי. ה-ROI עבור AI על המכשיר נע בדרך כלל בין 6 ל-12 חודשים. עלות פרויקט טיפוסית: מ-$5,000 לאינטגרציה בסיסית ועד $15,000 לפתרון מלא. קבלו ייעוץ לדיון בפרטים.
ארכיטקטורה ויתרונות של AI על המכשיר
הצינור מורכב משני שלבים עצמאיים. אינדוקס: חד-פעמי עבור כל הגלריה, ולאחר מכן אינקרמנטלי. עבור כל תמונה, חשבו CLIP Image Embedding (וקטור בן 512 ממדים) באמצעות עמוד שדרה ViT-B/32, נרמל ליחידת נורמה L2, ואחסנו אותו במאגר וקטורים מקומי. חיפוש: בכל שאילתת משתמש, המירו את שאילתת המשתמש ל-CLIP Text Embedding (אותו וקטור בן 512 ממדים), בצעו חיפוש ANN (לדוגמה, HNSW) עבור הוקטורים הקרובים ביותר במאגר, והחזירו תמונות ממוינות לפי דמיון קוסינוסי יורד.
| השוואה | על המכשיר | ענן |
|---|---|---|
| זמן השהיה | 15–20 אלפיות שנייה | 200–500 אלפיות שנייה |
| עלות לכל 10,000 שאילתות | $0 | $100–$500 |
| פרטיות | נתונים על המכשיר | נתונים על השרת |
AI על המכשיר עולה על הענן: ללא השהיית רשת, עלות חיזוי אפסית, פרטיות משתמש מלאה. עבור אפליקציה עם 10,000 משתמשים פעילים יומיים, עלויות הענן יכולות לעלות על $5,000 בחודש, בעוד שעל המכשיר זה עולה כלום—חיסכון של עד 80% בהשוואה לפתרונות ענן, ROI מהיר.
שילוב CLIP באמצעות CoreML
אפל לא כללה את CLIP במסגרת Vision הסטנדרטית, אבל Apple ML Research שחררה את ml-mobileclip—גרסה מזוקקת המיועדת במיוחד למכשירים ניידים. MobileCLIP-S0: 18 MB, 3–5 אלפיות שנייה לחיזוי תמונה ב-iPhone 14. מקור: Apple ML Research, MobileCLIP.
MobileCLIP ב-GitHub (מאגר רשמי עם קוד).
CLIP משתמש במטרת למידה קונטרסטיבית כדי ליישר הטמעות תמונה וטקסט במרחב מולטי-מודאלי משותף, מה שמאפשר סיווג ואחזור zero-shot. המודל משתמש בפונקציית הפסד קונטרסטיבית שמושכת זוגות תמונה-טקסט תואמים יחד ודוחפת זוגות לא תואמים זה מזה במרחב ההטמעות.
import CoreML
class MobileCLIPEmbedder {
private let imageEncoder: MobileCLIPImageEncoder
private let textEncoder: MobileCLIPTextEncoder
func embedImage(_ cgImage: CGImage) throws -> [Float] {
let resized = resize(cgImage, to: CGSize(width: 256, height: 256))
let input = MobileCLIPImageInput(image: MLMultiArray(from: resized))
let output = try imageEncoder.prediction(input: input)
return l2Normalize(output.embedding.toFloatArray())
}
func embedText(_ query: String) throws -> [Float] {
let tokens = tokenize(query) // BPE tokenizer
let input = MobileCLIPTextInput(tokens: MLMultiArray(from: tokens))
let output = try textEncoder.prediction(input: input)
return l2Normalize(output.embedding.toFloatArray())
}
}הטוקנייזר עבור CLIP הוא BPE (Byte Pair Encoding). יישום ב-Swift זמין במאגר ml-mobileclip. באנדרואיד: ONNX Runtime עם MobileCLIP—פחות פשוט אבל עובד.
איך לשלב את CLIP באפליקציית iOS?
מדריך שלב-אחר-שלב ליישום חיפוש סמנטי:
- הכינו את המודל. הורידו את MobileCLIP-S0 ממאגר Apple ML. המירו ל-CoreML באמצעות coremltools.
- שלבו את המקודדים. צרו מחלקות לעיבוד תמונות וטקסט, כמו בדוגמה למעלה. ודאו שהנורמליזציה והטוקניזציה תואמות.
- הגדירו אינדוקס. השתמשו ב-BGProcessingTask לאינדוקס רקע של הגלריה. שמרו הטמעות במאגר וקטורים (לדוגמה, sqlite-vss).
- יישמו חיפוש. בעת קבלת שאילתה, חשבו את הטמעת הטקסט ובצעו חיפוש ANN. החזירו תוצאות ממוינות.
דוגמה לאינדוקס רקע:
class GalleryIndexer {
private var lastIndexedDate: Date {
get {
UserDefaults.standard.object(forKey: "lastIndexedDate") as? Date ?? .distantPast
}
set {
UserDefaults.standard.set(newValue, forKey: "lastIndexedDate")
}
}
func indexNewPhotos() async {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "creationDate > %@", lastIndexedDate as CVarArg)
let newPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)
newPhotos.enumerateObjects { [weak self] asset, _, _ in
guard let self else { return }
if let embedding = self.computeEmbedding(for: asset) {
self.vectorDB.insert(assetId: asset.localIdentifier, embedding: embedding)
}
}
lastIndexedDate = Date()
}
}החיפוש מסתיים תוך ~20 אלפיות שנייה: הטמעת טקסט (5 אלפיות שנייה) + חיפוש ANN (15 אלפיות שנייה). התוצאות מיידיות.
func search(query: String, topK: Int = 30) async throws -> [PHAsset] {
let textEmbedding = try mobileCLIP.embedText(query)
let results = vectorDB.search(vector: textEmbedding, limit: topK)
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(
format: "localIdentifier IN %@", results.map { $0.assetId }
)
let assets = PHAsset.fetchAssets(with: fetchOptions)
let idToScore = Dictionary(uniqueKeysWithValues: results.map { ($0.assetId, $0.score) })
return assets.objects(at: IndexSet(0..<assets.count))
.sorted { idToScore[$0.localIdentifier, default: 0] > idToScore[$1.localIdentifier, default: 0] }
} איך אנו בוחרים מאגר וקטורים על המכשיר
לחיפוש בין 50,000 וקטורים, יש צורך באינדקס ANN. אינדקסי ANN כמו sqlite-vss משתמשים בקוונטיזציה ובגרפים של עולם קטן ניווט היררכי (HNSW) כדי להאיץ את החיפוש. שקלו שלוש אפשרויות עם מאפיינים קונקרטיים:
| טכנולוגיה | ביצועים | מורכבות אינטגרציה | גודל מאגר |
|---|---|---|---|
| SQLite + sqlite-vss | 15–20 אלפיות שנייה לחיפוש | בינונית (הרחבת SQL) | 10k–50k |
| FAISS (C++ דרך JNI/Swift) | 5–10 אלפיות שנייה לחיפוש | גבוהה (בנייה ספציפית לפלטפורמה) | 50k–500k |
| Flat L2 דרך Accelerate | 15 אלפיות שנייה לכל 10k וקטורים | נמוכה (ספרייה סטנדרטית) | עד 10k |
SQLite עם הרחבת sqlite-vss מוסיף טבלאות וירטואליות לחיפוש וקטורים. קומפקטי, עובד במצב משובץ:
CREATE VIRTUAL TABLE photo_embeddings USING vss0(embedding(512));
INSERT INTO photo_embeddings(rowid, embedding) VALUES (42, json('[0.1, -0.3, ...]'));
SELECT rowid, distance FROM photo_embeddings WHERE vss_search(embedding, json('[0.2, -0.1, ...]')) LIMIT 20;Flat L2/cosine פשוט דרך Accelerate עבור גלריות עד 10k תמונות מספיק ללא אינדקס ייעודי:
func cosineSimilarity(_ a: [Float], _ b: [Float]) -> Float {
var dotProduct: Float = 0
vDSP_dotpr(a, 1, b, 1, &dotProduct, vDSP_Length(a.count))
return dotProduct // После L2-нормализации = косинусное сходство
}חיפוש ברוט פורס של 10,000 וקטורים בני 512 ממדים ב-iPhone 14 דרך vDSP_dotpr לוקח ~15 אלפיות שנייה. מקובל עבור גלריות עד 20k.
חיפוש רב-לשוני
CLIP מאומן בעיקר על אנגלית. עבור שאילתה ברוסית "собака на пляже", האיכות גרועה יותר מאשר עבור "dog on beach". פתרון: תרגמו את השאילתה באמצעות מילון פשוט של מילים נפוצות או Google Translate API לפני ההטמעה. בפועל, תרגום של 100–200 שאילתות תכופות במצב לא מקוון מספיק.
מה כלול וכמה זמן זה לוקח?
| משימה | לוח זמנים |
|---|---|
| חיפוש CLIP בסיסי עם אינדקס שטוח לגלריות עד 10k | 1–1.5 שבועות |
| יישום ניתן להרחבה עם אינדקס ANN, עדכונים אינקרמנטליים, תמיכה רב-לשונית וחיפוש ויזואלי לפי תמונת ייחוס | 3–4 שבועות |
העלות מחושבת באופן אישי לפי מורכבות האינטגרציה והמכשירים המיועדים. קבלו ייעוץ להערכה מדויקת.
למה להפקיד בידינו את המשימה הזו?
לצוות שלנו יש ניסיון של 6+ שנים ב-ML לנייד והוא סיפק 15+ פרויקטים של AI על המכשיר, תוך ביסוס רקורד חזק מאז 2018. אנו מבטיחים עמידה בהנחיות סקירת ה-App Store (סעיפים 4.2 ו-5.1) ואבטחת נתוני משתמשים. אנו מספקים תיעוד מלא ותמיכה לאחר הפריסה.







