নিউরাল নেটওয়ার্কগুলি আজ মেশিন লার্নিং (এমএল) এর অগ্রভাগে রয়েছে এবং পাইথন নিঃসন্দেহে যে কোনও এমএল টাস্কের জন্য গো-টু প্রোগ্রামিং ভাষা, তা নির্বিশেষে কেউ এটি সমাধানের জন্য নিউরাল নেটওয়ার্ক ব্যবহার করতে চায় বা না করে। পাইথন লাইব্রেরির একটি বিস্তীর্ণ অ্যারে উপলব্ধ রয়েছে যা ML টাস্কগুলির সম্পূর্ণ স্পেকট্রামকে কভার করে, যেমন NumPy, Pandas, Keras, TensorFlow, PyTorch ইত্যাদি। এই লাইব্রেরিগুলি সাধারণত ML অ্যালগরিদমগুলির C বা C++ বাস্তবায়নের উপর নির্ভর করে এবং হুডের নীচে পন্থা অবলম্বন করে কারণ পাইথন তাদের জন্য খুব ধীর। যাইহোক, পাইথন অস্তিত্বে একমাত্র প্রোগ্রামিং ভাষা নয়, এবং এটি আমি আমার দৈনন্দিন কাজে ব্যবহার করি না।
এই নিবন্ধটি কীভাবে সুইফটে কিছু লিখতে হয় তার নির্দেশিকা নয়; বরং, এটি অনেক ডেভেলপারদের বর্তমান মানসিকতা সম্পর্কে একটি চিন্তাধারার মতো, যারা পাইথনকে এমএল লাইব্রেরির চূড়ান্ত সমাধানের সেতু হিসাবে দেখেন যা তারা যে ভাষা ব্যবহার করছে তা নির্বিশেষে তাদের সম্মুখীন যে কোনও সমস্যা বা কাজ সমাধান করবে। আমি বাজি ধরতে চাই যে বেশিরভাগ বিকাশকারীরা তাদের ভাষা/পরিবেশে পাইথন লাইব্রেরিগুলিকে একীভূত করার উপায় খুঁজে বের করার জন্য তাদের সময় ব্যয় করতে পছন্দ করে না বরং তাদের ছাড়া বিকল্প সমাধানগুলি বিবেচনা করে। যদিও এটি সহজাতভাবে খারাপ নয় - গত কয়েক দশক ধরে আইটি-তে পুনঃব্যবহার একটি উল্লেখযোগ্য অগ্রগতি হয়েছে - আমি বুঝতে শুরু করেছি যে অনেক বিকাশকারী আর বিকল্প সমাধানগুলিও বিবেচনা করে না। এই মানসিকতা বর্তমান অবস্থা এবং বৃহৎ ভাষার মডেলগুলির অগ্রগতির সাথে আরও বেশি আবদ্ধ হয়ে ওঠে।
ভারসাম্যের অভাব রয়েছে; আমরা LLM-কে আমাদের সমস্যার সমাধান করার জন্য, কিছু Python কোড পেতে, এটি অনুলিপি করতে এবং অপ্রয়োজনীয় নির্ভরতা থেকে সম্ভাব্য উল্লেখযোগ্য ওভারহেড সহ আমাদের উত্পাদনশীলতা উপভোগ করার দিকে ছুটছি।
আসুন শুধুমাত্র সুইফ্ট, গণিত এবং অন্য কোন সরঞ্জাম ব্যবহার না করে হাতের কাজটি সমাধান করার বিকল্প পদ্ধতির অন্বেষণ করি।
যখন লোকেরা নিউরাল নেটওয়ার্ক শেখা শুরু করে, তখন দুটি ক্লাসিক হ্যালো ওয়ার্ল্ড উদাহরণ রয়েছে যা আপনি বেশিরভাগ টিউটোরিয়াল এবং এর জন্য পরিচিতিমূলক উপকরণগুলিতে খুঁজে পেতে পারেন। প্রথমটি একটি হাতে লেখা অঙ্কের স্বীকৃতি। দ্বিতীয়টি একটি ডেটা শ্রেণীবিভাগ। আমি এই নিবন্ধে দ্বিতীয়টির উপর ফোকাস করব, তবে আমি যে সমাধানটি দিয়ে যাব তা প্রথমটির জন্যও কাজ করবে।
এটির জন্য খুব ভাল ভিজ্যুয়াল উদাহরণটি টেনসরফ্লো প্লেগ্রাউন্ডে পাওয়া যেতে পারে, যেখানে আপনি বিভিন্ন নিউরাল নেটওয়ার্ক স্ট্রাকচারের সাথে চারপাশে খেলতে পারেন এবং ফলস্বরূপ মডেলটি কতটা ভালভাবে কাজটি সমাধান করে তা দৃশ্যত পর্যবেক্ষণ করতে পারেন।
আপনি জিজ্ঞাসা করতে পারেন বিভিন্ন রঙের একটি ছবিতে এই বিন্দুগুলির ব্যবহারিক অর্থ কী? জিনিসটি হল এটি কিছু ডেটা সেটের একটি চাক্ষুষ উপস্থাপনা। আপনি অনেকগুলি বিভিন্ন ধরণের ডেটা ঠিক একই বা অনুরূপভাবে উপস্থাপন করতে পারেন, যেমন নির্দিষ্ট পণ্য বা সঙ্গীত পছন্দ কেনার লোকদের সামাজিক গোষ্ঠী। যেহেতু আমি প্রাথমিকভাবে মোবাইল iOS ডেভেলপমেন্টে ফোকাস করি, তাই আমি একটি বাস্তব কাজের উদাহরণও দেব যা আমি সমাধান করছিলাম যা দৃশ্যত একইভাবে উপস্থাপন করা যেতে পারে: একটি মোবাইল ফোনে একটি জাইরোস্কোপ এবং ম্যাগনেটোমিটার ব্যবহার করে দেয়ালের ভিতরে বৈদ্যুতিক তারের সন্ধান করা। এই বিশেষ উদাহরণে, আমাদের কাছে পাওয়া তারের সাথে সম্পর্কিত পরামিতিগুলির একটি সেট রয়েছে এবং প্রাচীরের ভিতরে কিছুই নেই।
আসুন আমরা যে ডেটা ব্যবহার করব তা একবার দেখে নেওয়া যাক।
আমাদের এখানে দুটি ধরণের ডেটা রয়েছে: লাল বিন্দু এবং নীল বিন্দু। আমি উপরে বর্ণিত হিসাবে, এটি কোনো ধরনের শ্রেণীবদ্ধ ডেটার একটি চাক্ষুষ উপস্থাপনা হতে পারে। উদাহরণ স্বরূপ, দেয়ালে বৈদ্যুতিক তার থাকলে লাল এলাকাটিকে ধরা যাক যেখানে ম্যাগনেটোমিটার এবং জাইরোস্কোপ থেকে সংকেত পাওয়া যায় এবং না থাকলে নীল এলাকাটিকে ধরা যাক।
আমরা দেখতে পাচ্ছি যে এই বিন্দুগুলি একত্রে একত্রিত হয় এবং কিছু ধরণের লাল এবং নীল আকার তৈরি করে। এই বিন্দুগুলি যেভাবে তৈরি করা হয়েছিল তা হল নিম্নলিখিত চিত্র থেকে র্যান্ডম পয়েন্টগুলি নিয়ে:
আমরা এই ছবিটিকে আমাদের ট্রেন প্রক্রিয়ার জন্য একটি এলোমেলো মডেল হিসাবে ব্যবহার করব মডেলকে প্রশিক্ষণের জন্য র্যান্ডম পয়েন্ট এবং আমাদের প্রশিক্ষিত মডেল পরীক্ষা করার জন্য অন্যান্য র্যান্ডম পয়েন্টগুলি নিয়ে।
আসল ছবিটি হল 300 x 300 পিক্সেল, এতে 90,000 ডট (পয়েন্ট) রয়েছে। প্রশিক্ষণের উদ্দেশ্যে, আমরা এই বিন্দুগুলির মাত্র 0.2% ব্যবহার করব, যা 100 পয়েন্টের কম। মডেলের পারফরম্যান্স সম্পর্কে আরও ভাল বোঝার জন্য, আমরা এলোমেলোভাবে 3000 পয়েন্ট নির্বাচন করব এবং ছবির চারপাশে বৃত্ত আঁকব। এই চাক্ষুষ উপস্থাপনা আমাদের ফলাফলের আরও ব্যাপক ধারণা প্রদান করবে। আমরা মডেলের কার্যকারিতা যাচাই করতে নির্ভুলতার শতাংশও পরিমাপ করতে পারি।
আমরা কিভাবে একটি মডেল তৈরি করব? আমরা যদি এই দুটি চিত্রকে একসাথে দেখি এবং আমাদের কাজকে সহজ করার চেষ্টা করি, তাহলে আমরা জানতে পারব যে কাজটি আসলে আমাদের কাছে থাকা ডেটা (লাল এবং নীল বিন্দুর ব্যাচ) থেকে অরিজিন ছবি পুনরায় তৈরি করা। এবং আমরা আমাদের মডেল থেকে আসলটির যত কাছাকাছি ছবি পাব ততই আমাদের মডেলের কাজ তত বেশি নির্ভুল হবে। আমরা আমাদের পরীক্ষার ডেটাকে আমাদের আসল চিত্রের কিছু ধরণের অত্যন্ত সংকুচিত সংস্করণ হিসাবে বিবেচনা করতে পারি এবং এটিকে আবার ডিকম্প্রেস করার লক্ষ্য রাখতে পারি।
আমরা যা করতে যাচ্ছি তা হল আমাদের বিন্দুগুলিকে গাণিতিক ফাংশনে রূপান্তর করা যা কোডে অ্যারে বা ভেক্টর হিসাবে উপস্থাপন করা হবে (আমি এখানে ভেক্টর শব্দটি পাঠ্যে ব্যবহার করব কারণ এটি গণিত জগতের ফাংশন এবং সফ্টওয়্যার বিকাশের অ্যারের মধ্যে)। তারপর, আমরা এই ভেক্টরগুলিকে প্রতিটি পরীক্ষার পয়েন্টকে চ্যালেঞ্জ করার জন্য ব্যবহার করব এবং এটি কোন ভেক্টরের বেশি তা চিহ্নিত করব।
আমাদের ডেটা রূপান্তর করতে, আমি একটি ডিসক্রিট কোসাইন ট্রান্সফর্ম (ডিসিটি) চেষ্টা করব। এটি কী এবং এটি কীভাবে কাজ করে সে সম্পর্কে আমি কোনও গাণিতিক ব্যাখ্যায় যাব না, কারণ আপনি চাইলে সহজেই সেই তথ্যটি খুঁজে পেতে পারেন। যাইহোক, আমি সহজ ভাষায় ব্যাখ্যা করতে পারি কিভাবে এটি আমাদের সাহায্য করতে পারে এবং কেন এটি দরকারী। ডিসিটি ইমেজ কম্প্রেশন (যেমন 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
প্যারামিটার রয়েছে যা shortArray ফাংশনের ভিতরে ব্যবহার করা হয়, আমি পরে এর উদ্দেশ্য ব্যাখ্যা করব, আপাতত এটিকে উপেক্ষা করা যাক এবং আমাদের তৈরি ভেক্টর redCosArray
, blueCosArray
এবং noneCosArray
এর বিপরীতে আসল চিত্র থেকে 3000 র্যান্ডম পয়েন্টের ফলাফল পরীক্ষা করি। এটি কাজ করার জন্য, আমাদের মূল চিত্র থেকে নেওয়া একটি একক বিন্দু থেকে আরেকটি ডিসিটি ভেক্টর তৈরি করতে হবে। এটি আমরা ঠিক একইভাবে করি এবং একই ফাংশন ব্যবহার করে যা আমরা ইতিমধ্যে আমাদের Red
, Blue
এবং None
cos ভেক্টরের জন্য করেছি। কিন্তু কিভাবে আমরা খুঁজে পেতে পারি কোনটি এই নতুন ভেক্টরের অন্তর্গত? এটির জন্য একটি খুব সাধারণ গণিত পদ্ধতি রয়েছে: Dot Product
। যেহেতু আমাদের কাছে দুটি ভেক্টরের তুলনা করার এবং সবচেয়ে অনুরূপ জোড়া খুঁজে বের করার কাজ আছে, তাই ডট প্রোডাক্ট আমাদের ঠিক এটিই দেবে। আপনি যদি দুটি অভিন্ন ভেক্টরের জন্য একটি ডট প্রোডাক্ট অপারেশন প্রয়োগ করেন, তাহলে এটি আপনাকে কিছু ইতিবাচক মান দেবে যা একই ভেক্টরে প্রয়োগ করা অন্য যেকোনো ডট প্রোডাক্ট ফলাফলের চেয়ে বেশি হবে এবং অন্য কোনো ভেক্টর যার মান ভিন্ন। এবং যদি আপনি অর্থোগোনাল ভেক্টর (ভেক্টর যেগুলির একে অপরের মধ্যে সাধারণ কিছু নেই) তে একটি ডট পণ্য প্রয়োগ করেন তবে আপনি ফলাফল হিসাবে 0 পাবেন। এটি বিবেচনায় নিয়ে, আমরা একটি সাধারণ অ্যালগরিদম নিয়ে আসতে পারি:
redCosArray
, তারপর blueCosArray
এবং তারপর noneCosArray
এর সাথে একটি ডট পণ্য প্রয়োগ করুন।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
থেকে একটি ছবি আঁকতে হবে। আসুন আমরা যে ট্রেন পয়েন্টগুলি ব্যবহার করেছি, আমাদের ট্রেনের ডেটা থেকে আমরা তৈরি করেছি DCT ভেক্টর এবং আমরা যে শেষ ফলাফল পেয়েছি তা একবার দেখে নেওয়া যাক:
ওয়েল, এলোমেলো শব্দ মত দেখায়. তবে আসুন ভেক্টরের ভিজ্যুয়াল উপস্থাপনাটি একবার দেখে নেওয়া যাক। আপনি সেখানে কিছু স্পাইক দেখতে পাবেন, ঠিক এই তথ্যই আমাদের ফোকাস করতে হবে এবং আমাদের ডিসিটি ফলাফল থেকে বেশিরভাগ শব্দ অপসারণ করতে হবে। আমরা যদি ডিসিটি ম্যাট্রিক্সের সাধারণ ভিজ্যুয়াল উপস্থাপনাটি একবার দেখি, আমরা দেখতে পাব যে সবচেয়ে দরকারী তথ্য (যেটি চিত্রের অনন্য বৈশিষ্ট্যগুলি বর্ণনা করে) উপরের বাম কোণে কেন্দ্রীভূত:
এখন একধাপ পিছিয়ে যাওয়া যাক এবং shortArray
ফাংশনটি আবার পরীক্ষা করা যাক। আমরা এখানে একটি cosLimit
প্যারামিটার ব্যবহার করি যা DCT ম্যাট্রিক্সের উপরের বাম কোণে নেওয়ার জন্য এবং শুধুমাত্র সবচেয়ে সক্রিয় প্যারামিটারগুলি ব্যবহার করে যা আমাদের ভেক্টরকে অনন্য করে তোলে।
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 মান ব্যবহার করার পরিবর্তে, আমরা DCT ম্যাট্রিক্সের উপরের বাম কোণ থেকে শুধুমাত্র 30 x 30 / 2 = 450
ব্যবহার করব। আসুন আমরা যে ফলাফল পেয়েছি তা একবার দেখে নেওয়া যাক:
আপনি দেখতে পাচ্ছেন, এটি ইতিমধ্যেই ভাল। আমরা আরও লক্ষ্য করতে পারি যে ভেক্টরগুলিকে অনন্য করে তোলে এমন বেশিরভাগ স্পাইকগুলি এখনও সামনের অংশে অবস্থিত (ছবিতে সবুজ দিয়ে নির্বাচিত), আসুন CosTransform(cosLimit: 6)
ব্যবহার করার চেষ্টা করি যার মানে আমরা 6 x 6 / 2 = 18
ব্যবহার করব। 90,000 এর মধ্যে 6 x 6 / 2 = 18
মান এবং ফলাফল পরীক্ষা করুন:
এটা এখন অনেক ভালো, আসল ছবির খুব কাছাকাছি। যাইহোক, শুধুমাত্র একটি সামান্য সমস্যা আছে - এই বাস্তবায়ন ধীর। DCT একটি সময়সাপেক্ষ ক্রিয়াকলাপ উপলব্ধি করার জন্য আপনাকে অ্যালগরিদম জটিলতায় বিশেষজ্ঞ হতে হবে না, তবে সুইফট অ্যারে ব্যবহার করে বড় ভেক্টরগুলির সাথে কাজ করার সময় এমনকি ডট পণ্য, যার একটি রৈখিক সময় জটিলতা রয়েছে তা যথেষ্ট দ্রুত নয়। ভাল খবর হল আমরা অ্যাপলের 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
আমাদের বর্তমান ম্যাট্রিক্স আকার সম্পর্কিত নতুন DCT বাস্তবায়নে একটি সমস্যা রয়েছে। এটি আমাদের 300 x 300 চিত্রের সাথে কাজ করবে না কারণ এটি নির্দিষ্ট আকারের সাথে কাজ করার জন্য অপ্টিমাইজ করা হয়েছে যা 2 এর ক্ষমতা। তাই, নতুন পদ্ধতিতে দেওয়ার আগে আমাদের ছবিটিকে স্কেল করার জন্য কিছু প্রচেষ্টা করতে হবে।
যারা এখন পর্যন্ত এই লেখাটি পড়তে পেরেছেন বা পড়া ছাড়াই স্ক্রোল করার জন্য যথেষ্ট অলস ছিলেন তাদের ধন্যবাদ। এই নিবন্ধটির উদ্দেশ্য ছিল দেখানো যে অনেকগুলি কাজ যা লোকেরা কিছু দেশীয় যন্ত্র দিয়ে সমাধান করার কথা বিবেচনা করে না তা ন্যূনতম প্রচেষ্টায় সমাধান করা যেতে পারে। বিকল্প সমাধানগুলি সন্ধান করা উপভোগ্য, এবং এই জাতীয় কাজগুলি সমাধানের একমাত্র বিকল্প হিসাবে আপনার মনকে পাইথন লাইব্রেরি ইন্টিগ্রেশনে সীমাবদ্ধ করবেন না।