paint-brush
पायथन, न्यूरल नेटवर्क और लाइब्रेरीज़ के बिना स्विफ्ट पर एमएल कार्यद्वारा@pichukov
584 रीडिंग
584 रीडिंग

पायथन, न्यूरल नेटवर्क और लाइब्रेरीज़ के बिना स्विफ्ट पर एमएल कार्य

द्वारा Aleksei Pichukov15m2024/01/04
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

यह आलेख स्विफ्ट में कुछ लिखने के बारे में कोई मार्गदर्शिका नहीं है; बल्कि, यह कई डेवलपर्स की वर्तमान मानसिकता के बारे में एक विचार की तरह है जो पायथन को एमएल पुस्तकालयों के लिए अंतिम समाधान के पुल के रूप में देखते हैं जो उनके सामने आने वाली किसी भी समस्या या कार्य को हल करेगा, चाहे वे किसी भी भाषा का उपयोग कर रहे हों। मैं शर्त लगाता हूं कि अधिकांश डेवलपर्स पायथन पुस्तकालयों को उनके बिना वैकल्पिक समाधानों पर विचार करने के बजाय अपनी भाषा/पर्यावरण में एकीकृत करने के तरीके खोजने में अपना समय निवेश करना पसंद करते हैं। हालांकि यह स्वाभाविक रूप से बुरा नहीं है - पिछले कुछ दशकों में पुन: उपयोग आईटी में प्रगति का एक महत्वपूर्ण चालक रहा है - मुझे यह महसूस होने लगा है कि कई डेवलपर्स अब वैकल्पिक समाधानों पर भी विचार नहीं करते हैं। यह मानसिकता वर्तमान स्थिति और बड़े भाषा मॉडल में प्रगति के साथ और भी अधिक मजबूत हो गई है। हम एक क्लासिक एमएल कार्य लेंगे और स्विफ्ट भाषा और बिना लाइब्रेरी का उपयोग करके इसे हल करेंगे।
featured image - पायथन, न्यूरल नेटवर्क और लाइब्रेरीज़ के बिना स्विफ्ट पर एमएल कार्य
Aleksei Pichukov HackerNoon profile picture
0-item
1-item

न्यूरल नेटवर्क आज मशीन लर्निंग (एमएल) में सबसे आगे हैं, और पायथन निस्संदेह किसी भी एमएल कार्य के लिए पसंदीदा प्रोग्रामिंग भाषा है, भले ही कोई इसे हल करने के लिए न्यूरल नेटवर्क का उपयोग करने का इरादा रखता हो या नहीं। पायथन पुस्तकालयों की एक विशाल श्रृंखला उपलब्ध है जो एमएल कार्यों के पूरे स्पेक्ट्रम को कवर करती है, जैसे कि न्यूमपी, पांडा, केरस, टेन्सरफ्लो, पायटोरच, इत्यादि। ये लाइब्रेरी आमतौर पर हुड के तहत एमएल एल्गोरिदम और दृष्टिकोण के सी या सी ++ कार्यान्वयन पर भरोसा करते हैं क्योंकि पायथन उनके लिए बहुत धीमा है। हालाँकि, पायथन अस्तित्व में एकमात्र प्रोग्रामिंग भाषा नहीं है, और यह वह भाषा नहीं है जिसका उपयोग मैं अपने दैनिक कार्य में करता हूँ।


यह आलेख स्विफ्ट में कुछ लिखने के बारे में कोई मार्गदर्शिका नहीं है; बल्कि, यह कई डेवलपर्स की वर्तमान मानसिकता के बारे में एक विचार की तरह है जो पायथन को एमएल पुस्तकालयों के लिए अंतिम समाधान के पुल के रूप में देखते हैं जो उनके सामने आने वाली किसी भी समस्या या कार्य को हल करेगा, चाहे वे किसी भी भाषा का उपयोग कर रहे हों। मैं शर्त लगाता हूं कि अधिकांश डेवलपर्स पायथन पुस्तकालयों को उनके बिना वैकल्पिक समाधानों पर विचार करने के बजाय अपनी भाषा/पर्यावरण में एकीकृत करने के तरीके खोजने में अपना समय निवेश करना पसंद करते हैं। हालांकि यह स्वाभाविक रूप से बुरा नहीं है - पिछले कुछ दशकों में पुन: उपयोग आईटी में प्रगति का एक महत्वपूर्ण चालक रहा है - मुझे यह महसूस होने लगा है कि कई डेवलपर्स अब वैकल्पिक समाधानों पर भी विचार नहीं करते हैं। यह मानसिकता वर्तमान स्थिति और बड़े भाषा मॉडल में प्रगति के साथ और भी अधिक मजबूत हो गई है।


संतुलन की कमी है; हम एलएलएम से अपने मुद्दों को हल करने के लिए कह रहे हैं, कुछ पायथन कोड प्राप्त कर रहे हैं, उसे कॉपी कर रहे हैं, और अनावश्यक निर्भरता से संभावित रूप से महत्वपूर्ण ओवरहेड के साथ अपनी उत्पादकता का आनंद ले रहे हैं।


आइए केवल स्विफ्ट, गणित और किसी अन्य उपकरण का उपयोग करके कार्य को हल करने के लिए वैकल्पिक दृष्टिकोण का पता लगाएं।


जब लोग न्यूरल नेटवर्क सीखना शुरू करते हैं, तो दो क्लासिक हैलो वर्ल्ड उदाहरण होते हैं जिन्हें आप इसके लिए अधिकांश ट्यूटोरियल और परिचयात्मक सामग्रियों में पा सकते हैं। पहला हस्तलिखित अंक पहचान है। दूसरा डेटा वर्गीकरण है। मैं इस लेख में दूसरे पर ध्यान केंद्रित करूंगा, लेकिन मैं जिस समाधान से गुजरूंगा वह पहले वाले के लिए भी काम करेगा।


इसका बहुत अच्छा दृश्य उदाहरण TensorFlow Playground में पाया जा सकता है, जहां आप विभिन्न तंत्रिका नेटवर्क संरचनाओं के साथ खेल सकते हैं और देख सकते हैं कि परिणामी मॉडल कार्य को कितनी अच्छी तरह हल करता है।


TensorFlow खेल का मैदान उदाहरण


आप पूछ सकते हैं कि विभिन्न रंगों वाली छवि पर इन बिंदुओं का व्यावहारिक अर्थ क्या है? बात यह है कि यह कुछ डेटा सेटों का दृश्य प्रतिनिधित्व है। आप कई अलग-अलग प्रकार के डेटा को बिल्कुल एक ही या समान तरीके से प्रस्तुत कर सकते हैं, जैसे कि लोगों के सामाजिक समूह जो विशिष्ट उत्पाद खरीदते हैं या संगीत पसंद करते हैं। चूंकि मैं मुख्य रूप से मोबाइल आईओएस विकास पर ध्यान केंद्रित करता हूं, इसलिए मैं एक वास्तविक कार्य का उदाहरण भी दूंगा जिसे मैं हल कर रहा था जिसे दृश्यमान तरीके से दर्शाया जा सकता है: मोबाइल फोन पर जाइरोस्कोप और मैग्नेटोमीटर का उपयोग करके दीवारों के अंदर बिजली के तारों को ढूंढना। इस विशेष उदाहरण में, हमारे पास पाए गए तार से संबंधित मापदंडों का एक सेट है और दीवार के अंदर कुछ भी नहीं के लिए मापदंडों का एक और सेट है।


आइए उस डेटा पर एक नज़र डालें जिसका हम उपयोग करेंगे।

एमएल-टेस्ट


हमारे यहां दो प्रकार के डेटा हैं: लाल बिंदु और नीला बिंदु। जैसा कि मैंने ऊपर बताया है, यह किसी भी प्रकार के वर्गीकृत डेटा का दृश्य प्रतिनिधित्व हो सकता है। उदाहरण के लिए, आइए लाल क्षेत्र को उस स्थिति में लें जहां हमारे पास दीवार में बिजली का तार होने पर मैग्नेटोमीटर और जाइरोस्कोप से सिग्नल मिलता है, और यदि हमारे पास दीवार में बिजली का तार नहीं है तो नीले क्षेत्र को लेते हैं।


हम देख सकते हैं कि ये बिंदु किसी तरह एक साथ समूहीकृत हो गए हैं और कुछ प्रकार की लाल और नीली आकृतियाँ बनाते हैं। जिस तरह से ये बिंदु उत्पन्न किए गए थे वह निम्नलिखित छवि से यादृच्छिक बिंदु लेकर है:


बिन्दुओं को एक साथ समूहीकृत किया गया


हम मॉडल के प्रशिक्षण के लिए यादृच्छिक बिंदु और अपने प्रशिक्षित मॉडल के परीक्षण के लिए अन्य यादृच्छिक बिंदुओं को लेकर इस चित्र को अपनी ट्रेन प्रक्रिया के लिए एक यादृच्छिक मॉडल के रूप में उपयोग करेंगे।


मूल चित्र 300 x 300 पिक्सेल का है, जिसमें 90,000 बिंदु (बिंदु) हैं। प्रशिक्षण उद्देश्यों के लिए, हम इनमें से केवल 0.2% बिंदुओं का उपयोग करेंगे, जो 100 अंक से कम है। मॉडल के प्रदर्शन की बेहतर समझ हासिल करने के लिए, हम बेतरतीब ढंग से 3000 बिंदुओं का चयन करेंगे और चित्र पर उनके चारों ओर वृत्त बनाएंगे। यह दृश्य प्रतिनिधित्व हमें परिणामों का अधिक व्यापक विचार प्रदान करेगा। हम मॉडल की दक्षता को सत्यापित करने के लिए सटीकता का प्रतिशत भी माप सकते हैं।


हम एक मॉडल कैसे बनाएंगे? यदि हम इन दोनों छवियों को एक साथ देखें और अपने कार्य को सरल बनाने का प्रयास करें, तो हमें पता चलेगा कि कार्य, वास्तव में, हमारे पास मौजूद डेटा (लाल और नीले बिंदुओं का बैच) से मूल चित्र को फिर से बनाना है। और हम अपने मॉडल से मूल मॉडल के जितने करीब चित्र प्राप्त करेंगे, हमारा मॉडल उतना ही सटीक काम करेगा। हम अपने परीक्षण डेटा को अपनी मूल छवि के किसी प्रकार के अत्यधिक संपीड़ित संस्करण के रूप में भी मान सकते हैं और इसे वापस डीकंप्रेस करने का लक्ष्य रख सकते हैं।


हम जो करने जा रहे हैं वह अपने बिंदुओं को गणितीय कार्यों में बदलना है जिन्हें कोड में सरणी या वैक्टर के रूप में दर्शाया जाएगा (मैं यहां पाठ में वेक्टर शब्द का उपयोग सिर्फ इसलिए करूंगा क्योंकि यह गणित की दुनिया से फ़ंक्शन और सॉफ्टवेयर विकास से सरणी के बीच है)। फिर, हम प्रत्येक परीक्षण बिंदु को चुनौती देने और यह पहचानने के लिए इन वैक्टरों का उपयोग करेंगे कि यह किस वेक्टर से अधिक संबंधित है।


हमारे डेटा को बदलने के लिए, मैं एक डिस्क्रीट कोसाइन ट्रांसफॉर्म (डीसीटी) का प्रयास करूंगा। मैं इसके बारे में किसी गणितीय स्पष्टीकरण में नहीं जाऊंगा कि यह क्या है और यह कैसे काम करता है, क्योंकि आप चाहें तो वह जानकारी आसानी से पा सकते हैं। हालाँकि, मैं सरल शब्दों में समझा सकता हूँ कि यह हमारी कैसे मदद कर सकता है और यह क्यों उपयोगी है। DCT का उपयोग छवि संपीड़न (जैसे JPEG प्रारूप) सहित कई क्षेत्रों में किया जाता है। यह महत्वहीन विवरणों को हटाते हुए छवि के केवल महत्वपूर्ण हिस्सों को रखकर डेटा को अधिक कॉम्पैक्ट प्रारूप में बदल देता है। यदि हम केवल लाल बिंदुओं वाली अपनी 300x300 छवि पर DCT लागू करते हैं, तो हमें मानों का 300x300 मैट्रिक्स मिलेगा जिसे प्रत्येक पंक्ति को अलग से लेकर एक सरणी (या वेक्टर) में बदला जा सकता है।


आइए अंततः इसके लिए कुछ कोड लिखें। सबसे पहले, हमें एक साधारण वस्तु बनाने की आवश्यकता है जो हमारे बिंदु (बिंदु) का प्रतिनिधित्व करेगी।


 enum Category { case red case blue case none } struct Point: Hashable { let x: Int let y: Int let category: Category }


आप देख सकते हैं कि हमारे पास none नामक एक अतिरिक्त श्रेणी है। हम वास्तव में अंत में तीन वेक्टर बनाएंगे: एक red बिंदुओं के लिए, दूसरा blue बिंदुओं के लिए, और तीसरा किसी भी अन्य चीज़ के लिए जो none गया है। जबकि हमारे पास उनमें से सिर्फ दो ही हो सकते हैं, लाल और नीले नहीं के लिए एक प्रशिक्षित वेक्टर होने से चीजें थोड़ी आसान हो जाएंगी।


हमारे परीक्षण वेक्टर में समान निर्देशांक वाले बिंदुओं से बचने के लिए Set उपयोग करने के लिए हमारे पास `प्वाइंट` Hashable प्रोटोकॉल के अनुरूप है।


 func randomPoints(from points: [Point], percentage: Double) -> [Point] { let count = Int(Double(points.count) * percentage) var result = Set<Point>() while result.count < count { let index = Int.random(in: 0 ..< points.count) result.insert(points[index]) } return Array<Point>(result) }


अब हम इसका उपयोग अपनी मूल छवि से लाल, नीले और कोई भी अंक नहीं के लिए 0.2% यादृच्छिक अंक लेने के लिए कर सकते हैं।


 redTrainPoints = randomPoints(from: redPoints, percentage: 0.002) blueTrainPoints = randomPoints(from: bluePoints, percentage: 0.002) noneTrainPoints = randomPoints(from: nonePoints, percentage: 0.002)


हम डीसीटी का उपयोग करके इन प्रशिक्षण डेटा को बदलने के लिए तैयार हैं। इसका कार्यान्वयन यहां दिया गया है:


 final class CosTransform { private var sqrtWidthFactorForZero: Double = 0 private var sqrtWidthFactorForNotZero: Double = 0 private var sqrtHeightFactorForZero: Double = 0 private var sqrtHeightFactorForNotZero: Double = 0 private let cosLimit: Int init(cosLimit: Int) { self.cosLimit = cosLimit } func discreteCosTransform(for points: [Point], width: Int, height: Int) -> [[Double]] { if sqrtWidthFactorForZero == 0 { prepareSupportData(width: width, height: height) } var result = Array(repeating: Array(repeating: Double(0), count: width), count: height) for y in 0..<height { for x in 0..<width { let cos = cosSum( points: points, width: width, height: height, x: x, y: y ) result[y][x] = cFactorHeight(index: y) * cFactorWidth(index: x) * cos } } return result } func shortArray(matrix: [[Double]]) -> [Double] { let height = matrix.count guard let width = matrix.first?.count else { return [] } var array: [Double] = [] for y in 0..<height { for x in 0..<width { if y + x <= cosLimit { array.append(matrix[y][x]) } } } return array } private func prepareSupportData(width: Int, height: Int) { sqrtWidthFactorForZero = Double(sqrt(1 / CGFloat(width))) sqrtWidthFactorForNotZero = Double(sqrt(2 / CGFloat(width))) sqrtHeightFactorForZero = Double(sqrt(1 / CGFloat(height))) sqrtHeightFactorForNotZero = Double(sqrt(2 / CGFloat(height))) } private func cFactorWidth(index: Int) -> Double { return index == 0 ? sqrtWidthFactorForZero : sqrtWidthFactorForNotZero } private func cFactorHeight(index: Int) -> Double { return index == 0 ? sqrtHeightFactorForZero : sqrtHeightFactorForNotZero } private func cosSum( points: [Point], width: Int, height: Int, x: Int, y: Int ) -> Double { var result: Double = 0 for point in points { result += cosItem(point.x, x, height) * cosItem(point.y, y, width) } return result } private func cosItem( _ firstParam: Int, _ secondParam: Int, _ lenght: Int ) -> Double { return cos((Double(2 * firstParam + 1) * Double(secondParam) * Double.pi) / Double(2 * lenght)) } }


आइए CosTransform ऑब्जेक्ट का एक उदाहरण बनाएं और उसका परीक्षण करें।


 let math = CosTransform(cosLimit: Int.max) ... redCosArray = cosFunction(points: redTrainPoints) blueCosArray = cosFunction(points: blueTrainPoints) noneCosArray = cosFunction(points: noneTrainPoints)


हम यहां कुछ सरल सहायक कार्यों का उपयोग करते हैं:


 func cosFunction(points: [Point]) -> [Double] { return math.shortArray( matrix: math.discreteCosTransform( for: points, width: 300, height: 300 ) ) }


CosTransform में एक cosLimit पैरामीटर है जिसका उपयोग शॉर्टअरे फ़ंक्शन के अंदर किया जाता है, मैं इसका उद्देश्य बाद में बताऊंगा, अभी के लिए इसे अनदेखा करें और हमारे बनाए गए वेक्टर redCosArray , blueCosArray और noneCosArray के विरुद्ध मूल छवि से 3000 यादृच्छिक बिंदुओं के परिणाम की जांच करें। इसे काम करने के लिए, हमें मूल छवि से लिए गए एक बिंदु से एक और डीसीटी वेक्टर बनाने की आवश्यकता है। यह हम बिल्कुल उसी तरह से करते हैं और उन्हीं कार्यों का उपयोग करते हैं जो हमने पहले ही अपने Red , Blue और None कॉस वेक्टर के लिए किया था। लेकिन हम यह कैसे पता लगा सकते हैं कि यह नया वेक्टर किसका है? इसके लिए एक बहुत ही सरल गणित दृष्टिकोण है: Dot Product । चूँकि हमारे पास दो वेक्टरों की तुलना करने और सबसे समान जोड़ी खोजने का कार्य है, डॉट प्रोडक्ट हमें बिल्कुल यही देगा। यदि आप दो समान वेक्टरों के लिए एक डॉट उत्पाद ऑपरेशन लागू करते हैं, तो यह आपको कुछ सकारात्मक मूल्य देगा जो एक ही वेक्टर और किसी भी अन्य वेक्टर पर लागू होने वाले किसी भी अन्य डॉट उत्पाद परिणाम से अधिक होगा, जिसमें अलग-अलग मान हैं। और यदि आप ऑर्थोगोनल वेक्टर्स (ऐसे वेक्टर जिनमें एक-दूसरे के बीच कुछ भी सामान्य नहीं है) पर एक डॉट उत्पाद लागू करते हैं, तो आपको परिणामस्वरूप 0 मिलेगा। इसे ध्यान में रखते हुए, हम एक सरल एल्गोरिदम के साथ आ सकते हैं:


  1. हमारे सभी 3000 यादृच्छिक बिंदुओं को एक-एक करके देखें।
  2. DCT (असतत कोसाइन ट्रांसफॉर्म) का उपयोग करके केवल एक एकल बिंदु के साथ 300x300 मैट्रिक्स से एक वेक्टर बनाएं।
  3. इस वेक्टर के लिए redCosArray के साथ एक डॉट उत्पाद लागू करें, फिर blueCosArray के साथ, और फिर noneCosArray के साथ।
  4. पिछले चरण का सबसे बड़ा परिणाम हमें सही उत्तर की ओर संकेत करेगा: Red , Blue , None


यहां एकमात्र अनुपलब्ध कार्यक्षमता एक डॉट उत्पाद है, आइए इसके लिए एक सरल फ़ंक्शन लिखें:


 func dotProduct(_ first: [Double], _ second: [Double]) -> Double { guard first.count == second.count else { return 0 } var result: Double = 0 for i in 0..<first.count { result += first[i] * second[i] } return result }


और यहाँ एल्गोरिथ्म का कार्यान्वयन है:


 var count = 0 while count < 3000 { let index = Int.random(in: 0 ..< allPoints.count) let point = allPoints[index] count += 1 let testArray = math.shortArray( matrix: math.discreteCosTransform( for: [point], width: 300, height: 300 ) ) let redResult = dotProduct(redCosArray, testArray) let blueResult = dotProduct(blueCosArray, testArray) let noneResult = dotProduct(noneCosArray, testArray) var maxValue = redResult var result: Category = .red if blueResult > maxValue { maxValue = blueResult result = .blue } if noneResult > maxValue { maxValue = noneResult result = .none } fillPoints.append(Point(x: point.x, y: point.y, category: result)) }


अब हमें बस fillPoints से एक छवि बनानी है। आइए हमारे द्वारा उपयोग किए गए ट्रेन पॉइंट्स, हमारे ट्रेन डेटा से बनाए गए डीसीटी वैक्टर और हमें मिले अंतिम परिणाम पर एक नज़र डालें:

परिणाम

ख़ैर, यह बेतरतीब शोर जैसा लगता है। लेकिन आइए वैक्टर के दृश्य प्रतिनिधित्व पर एक नज़र डालें। आप वहां कुछ स्पाइक्स देख सकते हैं, यही वह जानकारी है जिस पर हमें ध्यान केंद्रित करने और अपने डीसीटी परिणाम से अधिकांश शोर को हटाने की आवश्यकता है। यदि हम डीसीटी मैट्रिक्स के सरल दृश्य प्रतिनिधित्व पर एक नज़र डालें, तो हम पाएंगे कि सबसे उपयोगी जानकारी (वह जो छवि की अनूठी विशेषताओं का वर्णन करती है) शीर्ष बाएं कोने पर केंद्रित है:


एकाग्रता


आइए अब एक कदम पीछे चलें और shortArray फ़ंक्शन को एक बार फिर से जांचें। हम यहां डीसीटी मैट्रिक्स के ऊपरी बाएं कोने को लेने और हमारे वेक्टर को अद्वितीय बनाने वाले सबसे सक्रिय पैरामीटर का उपयोग करने के लिए एक cosLimit पैरामीटर का उपयोग करते हैं।


 func shortArray(matrix: [[Double]]) -> [Double] { let height = matrix.count guard let width = matrix.first?.count else { return [] } var array: [Double] = [] for y in 0..<height { for x in 0..<width { if y + x <= cosLimit { array.append(matrix[y][x]) } } } return array }


आइए अलग-अलग cosLimit के साथ अपना math ऑब्जेक्ट बनाएं:


 let math = CosTransform(cosLimit: 30)


अब सभी 90,000 मानों का उपयोग करने के बजाय, हम डीसीटी मैट्रिक्स के ऊपरी बाएँ कोने से उनमें से केवल 30 x 30 / 2 = 450 उपयोग करेंगे। आइए प्राप्त परिणाम पर एक नजर डालें:

परिणाम

जैसा कि आप देख सकते हैं, यह पहले से बेहतर है। हम यह भी देख सकते हैं कि अधिकांश स्पाइक्स जो वेक्टर को अद्वितीय बनाते हैं वे अभी भी सामने के भाग में स्थित हैं (जैसा कि चित्र में हरे रंग के साथ चुना गया है), आइए CosTransform(cosLimit: 6) उपयोग करने का प्रयास करें जिसका अर्थ है कि हम केवल 6 x 6 / 2 = 18 का उपयोग करेंगे 90,000 में से 6 x 6 / 2 = 18 मान और परिणाम की जाँच करें:

सफलता

यह अब काफी बेहतर है, मूल छवि के बहुत करीब है। हालाँकि, केवल एक छोटी सी समस्या है - यह कार्यान्वयन धीमा है। आपको यह समझने के लिए एल्गोरिदम जटिलता में विशेषज्ञ होने की आवश्यकता नहीं होगी कि डीसीटी एक समय लेने वाला ऑपरेशन है, लेकिन यहां तक कि डॉट उत्पाद, जिसमें एक रैखिक समय जटिलता है, स्विफ्ट सरणियों का उपयोग करके बड़े वैक्टर के साथ काम करते समय पर्याप्त तेज़ नहीं है। अच्छी खबर यह है कि हम Apple के Accelerate फ्रेमवर्क से vDSP उपयोग करके इसे बहुत तेजी से और आसानी से लागू कर सकते हैं, जो हमारे पास पहले से ही एक मानक लाइब्रेरी के रूप में है। आप यहां vDSP के बारे में पढ़ सकते हैं, लेकिन सरल शब्दों में, यह डिजिटल सिग्नल प्रोसेसिंग कार्यों को बहुत तेज़ तरीके से निष्पादित करने के तरीकों का एक सेट है। इसमें हुड के नीचे बहुत सारे निम्न-स्तरीय अनुकूलन हैं जो बड़े डेटा सेट के साथ सही काम करते हैं। आइए vDSP का उपयोग करके अपने डॉट उत्पाद और DCT को लागू करें:


 infix operator • public func •(left: [Double], right: [Double]) -> Double { return vDSP.dot(left, right) } prefix operator ->> public prefix func ->>(value: [Double]) -> [Double] { let setup = vDSP.DCT(count: value.count, transformType: .II) return setup!.transform(value.compactMap { Float($0) }).compactMap { Double($0) } }


इसे कम कठिन बनाने के लिए, मैंने इसे अधिक पठनीय बनाने के लिए कुछ ऑपरेटरों का उपयोग किया है। अब आप इन फ़ंक्शंस का उपयोग निम्न प्रकार से कर सकते हैं:


 let cosRedArray = ->> redValues let redResult = redCosArray • testArray


हमारे वर्तमान मैट्रिक्स आकार के संबंध में नए डीसीटी कार्यान्वयन में एक समस्या है। यह हमारी 300 x 300 छवि के साथ काम नहीं करेगा क्योंकि इसे विशिष्ट आकारों के साथ काम करने के लिए अनुकूलित किया गया है जो 2 की शक्तियाँ हैं। इसलिए, हमें छवि को नई विधि में देने से पहले उसे स्केल करने के लिए कुछ प्रयास करने की आवश्यकता होगी।

सारांश

उन सभी को धन्यवाद जो अब तक इस पाठ को पढ़ने में कामयाब रहे या इतने आलसी थे कि बिना पढ़े स्क्रॉल कर सके। इस लेख का उद्देश्य यह दिखाना था कि कई कार्य जिन्हें लोग कुछ देशी उपकरणों से हल करने पर विचार नहीं करते, उन्हें न्यूनतम प्रयास से हल किया जा सकता है। वैकल्पिक समाधानों की तलाश करना आनंददायक है, और ऐसे कार्यों को हल करने के लिए अपने दिमाग को एकमात्र विकल्प के रूप में पायथन लाइब्रेरी एकीकरण तक सीमित न रखें।