برنامه نویسی

ساخت پلتفرم هوش مصنوعی بدون کد و الگوریتم BFS

در چند ماه گذشته، پلتفرم AI/ML با کد کم/بدون کد ایجاد کرده‌ام که به کاربران امکان می‌دهد مدل‌های ML خود را به عنوان یک API مستقر کنند. سناریوی زیر را تصور کنید: شما یک مدل یادگیری عمیق را آموزش داده اید و آن را به Huggingface منتقل کرده اید. در حالی که این مدل برای آنچه شما آن را آموزش داده اید عالی است، در داخل یک نوت بوک jupyter زندگی می کند، اما شما به یک API قابل استقرار نیاز دارید که کاربران بتوانند مستقیماً با مدل شما تعامل داشته باشند. یا حتی بهتر از آن، می‌خواهید مدل خود را به یکی از LLM‌های موجود متصل کنید، اما نمی‌خواهید زمانی را صرف کدنویسی API کنید، به کد یکپارچه‌سازی فکر کنید و غیره. اساساً این چیزی است که من سعی می‌کنم حلش کنم.

از نقطه نظر کاربر، شما یک ابزار مانند فلوچارت را می بینید، که در آن بلوک های خود را پیکربندی می کنید (در مورد Huggingface، در کارت مدل خود قرار می دهید)، آنها را به بلوک های ورودی خود متصل می کنید (آنها اساساً تعیین می کنند که آیا مدل شما بپذیرد یا خیر. یک ورودی متن یا تصویر یا هر دو)، و ایجاد را فشار دهید، که سپس یک محفظه docker در حال اجرا یک سرور FastAPI را برای شما مستقر می‌کند تا سپس پرس و جو کنید. در زیر هود، یک نمودار ایجاد می شود که هر گره در نمودار، منابع مورد نیاز برای اجرای بار کاری شما را بارگذاری می کند. و در این مقاله، می‌خواهم در مورد الگوریتم جستجوی وسعت اول و اینکه چگونه پروژه من را نیرو می‌دهد صحبت کنم.

اکنون گردش کار زیر را در نظر بگیرید که مدل مالی برت را برای تحلیل احساسات اجرا می کند. شما 3 بلوک دارید – بلوک ورودی که متن ورودی شما را می گیرد، بلوک ML و بلوک خروجی که نتیجه نهایی را نمایش می دهد.

توضیحات تصویر

اولین قدم، گرفتن این رابط کاربری و ترجمه آن به قالبی است که با backend صحبت کند. این می تواند چیزی شبیه به این باشد:

{
  "input": [
      "Input_Block": {
          "run_config": "All user based config",
          "connections": [ "process.Financial_BERT" ],
          "payload": "",
          "implementation": Input_Implementation_Class()
      }
  ],
  "process": [
      "Financial_BERT": {
          "run_config": "All user based config",
          "connections": [ "output.Output_Block" ],
          "payload": "",
          "implementation": HF_MODEL_Class()
      }
  ],
  "output": [
      "Output_Block": {
          "run_config": "All user based config",
          "connections": []
      }
  ]
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مرحله بعدی دریافت بار یک بلوک، انتقال آن به اجرای بلوک دیگر است و شما بلوک بعدی را از طریق لیست اتصالات می شناسید. اکنون، ساده لوحانه می‌توانید یک حلقه تکرار شونده را پیاده‌سازی کنید که از بلوک ورودی شروع می‌شود و با عبور دادن بار به اطراف، اتصال خود را طی می‌کند. چیزی شبیه به این خواهد بود:

start_node = workflow['input']['Input_Block']

for connection in start_node['connection']:
    # pass payload to process.Financial_BERT.implementation
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این رویکرد فقط در صورتی کار می‌کند که یک گردش کار خطی داشته باشیم، که در آن 1 بلوک فقط به یک بلوک متصل می‌شود. اما در دنیای واقعی، می‌توان N بلوک را به 1 بلوک متصل کرد، که در آن بلوک زیر قبل از اجرای خود انتظار ورودی‌ها را از همه N بلوک دارد.

توضیحات تصویر

بلوک نارنجی به ورودی های A، B و C به عنوان پارامتر نیاز دارد تا بتواند اجرا شود. پس چگونه می توانیم اطمینان حاصل کنیم که ورودی های بلوک A، B و C به طور کلی در بلوک نارنجی ارسال می شوند؟ در اینجا اولین جستجوی وسعت به نجات می رسد.

توضیحات تصویر

منبع: https://commons.wikimedia.org/wiki/File:Breadth-First-Search-Algorithm.gif

روشی که الگوریتم BFS کار می کند این است که از یک گره، منبع شروع می شود، ابتدا به همه همسایگان خود نگاه می کند و نمودار را به صورت لایه ای طی می کند. در اینجا گزیده ای از مقاله Hackerearth است که آن را به بهترین شکل خلاصه می کند:

توضیحات تصویر

منبع: https://www.hackerearth.com/practice/algorithms/graphs/breadth-first-search/tutorial/

بنابراین با بازگشت به مورد استفاده خود، می توانیم چیزی شبیه به این انجام دهیم:

توضیحات تصویر

می‌توانیم از یک گره ساختگی شروع کنیم، به همه همسایه‌های فوری آن (A، B و C) نگاه کنیم و آنها را پردازش کنیم، و تنها زمانی که هر 3 پردازش شوند، زمانی است که روی لایه بعدی که بلوک نارنجی است حرکت می‌کنیم و 3 را پاس می‌کنیم. خروجی بلوک به عنوان ورودی بلوک نارنجی. روشی که ما این را پیاده‌سازی می‌کنیم از طریق یک صف است که گره‌ها را به ترتیبی که وارد شده‌اند پردازش می‌کند. ما همچنین تمام گره‌هایی را که قبلاً بازدید و پردازش کرده‌ایم پیگیری می‌کنیم تا در نهایت به پردازش مجدد آنها نپردازیم. در زیر یک جریان گام به گام از نحوه اجرای آن آورده شده است.

توضیحات تصویر

جریان گام به گام نحوه استفاده از BFS برای پردازش گره ها

در اینجا بلوک کدی است که من برای گنجاندن BFS در پروژه خود استفاده کردم:

توضیحات تصویر

منبع: https://github.com/farhan0167/otto-m8

و اگر متوجه شده باشید، بسیار شبیه چیزی است که در ویکی‌پدیا در الگوریتم BFS پیدا می‌کنید:

توضیحات تصویر

منبع: https://en.wikipedia.org/wiki/Breadth-first_search

اکنون که راهی برای انتقال بارها از یک بلوک به بلوک دیگر داریم، دنیای کاملی از امکاناتی وجود دارد که می‌توان آن‌ها را پیاده‌سازی کرد. در حال حاضر otto-m8 (که به صورت خودکار ترجمه می‌شود)، قصد دارد تمام این بلوک‌ها را ارائه دهد که نوعی از مدل یادگیری عمیق را پیاده‌سازی می‌کنند. از مدل های LLM (OpenAI و Olama) و Hugging Face پشتیبانی می کند. هنگامی که یک گردش کار ایجاد می کنید، یک ظرف Docker قابل استقرار با یک نقطه پایانی REST در معرض دید دریافت می کنید. و در هسته خود (بدیهی است که یک ساده سازی بیش از حد) الگوریتم BFS راه را برای ورودی کاربر برای عبور از تمام مدل های زنجیره ای در گردش کار شما هموار می کند.
ممنون که خواندید، مخصوصاً اگر تمام مسیر را دنبال کرده باشید. لطفاً otto-m8 را امتحان کنید که می توانید در اینجا در Github پیدا کنید: https://github.com/farhan0167/otto-m8، همراه با مستندات اینجا در https://otto-m8.com

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا