كيفية جعل الروبوت الذي يحول الصورة إلى فكاهي. الجزء الثالث. مجانا خادم + GPU نموذج استضافة

⇨ الجزء 1
⇨ الجزء 2


حسنا ، استراح وهذا يكفي. اهلا بعودتك


في السلسلة السابقة ، قمت أنت وأنا بجمع البيانات وتدريب نموذجنا الأول.
ثم ، مرعوبين بالنتائج ، دربوا أكثر من عشرة.
حان الوقت لاظهار خلقنا للعالم!


نموذج التصدير


بادئ ذي بدء ، سنقوم بإعادة حفظ طراز المولد بتنسيق مناسب حتى لا نضطر إلى سحب إعلانات الفئة إلى الاستضافة.


قم بإنشاء ملف صغير بملحق * .py وانسخ الكود من أسفل المفسد أدناه فيه.
فليكن jit.py:


يتم نسخ الكود بدون تفكير عن طريق استبدال المسار ، output_path بطريقتك الخاصة
#  path       #    *G_A.pth -   ->  # output_path -      #      *.jit,  -  ,     path= '/checkpoints/resnet9_nowd_nodo_128to400_c8/60_net_G_A.pth' output_path ='/checkpoints/resnet9_nowd_nodo_128to400_c8/resnet9_nowd_nodo_128to400_c8_160-50-60_1.jit' import torch from torch import nn class ResnetGenerator(nn.Module): """Resnet-based generator that consists of Resnet blocks between a few downsampling/upsampling operations. We adapt Torch code and idea from Justin Johnson's neural style transfer project(https://github.com/jcjohnson/fast-neural-style) """ def __init__(self, input_nc, output_nc, ngf=64, norm_layer=nn.BatchNorm2d, use_dropout=False, n_blocks=6, padding_type='reflect'): """Construct a Resnet-based generator Parameters: input_nc (int) -- the number of channels in input images output_nc (int) -- the number of channels in output images ngf (int) -- the number of filters in the last conv layer norm_layer -- normalization layer use_dropout (bool) -- if use dropout layers n_blocks (int) -- the number of ResNet blocks padding_type (str) -- the name of padding layer in conv layers: reflect | replicate | zero """ assert(n_blocks >= 0) super(ResnetGenerator, self).__init__() if type(norm_layer) == functools.partial: use_bias = norm_layer.func == nn.InstanceNorm2d else: use_bias = norm_layer == nn.InstanceNorm2d model = [nn.ReflectionPad2d(3), nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0, bias=use_bias), norm_layer(ngf), nn.ReLU(True)] n_downsampling = 2 for i in range(n_downsampling): # add downsampling layers mult = 2 ** i model += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3, stride=2, padding=1, bias=use_bias), norm_layer(ngf * mult * 2), nn.ReLU(True)] mult = 2 ** n_downsampling for i in range(n_blocks): # add ResNet blocks model += [ResnetBlock(ngf * mult, padding_type=padding_type, norm_layer=norm_layer, use_dropout=use_dropout, use_bias=use_bias)] for i in range(n_downsampling): # add upsampling layers mult = 2 ** (n_downsampling - i) model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2), kernel_size=3, stride=2, padding=1, output_padding=1, bias=use_bias), norm_layer(int(ngf * mult / 2)), nn.ReLU(True)] model += [nn.ReflectionPad2d(3)] model += [nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0)] model += [nn.Tanh()] self.model = nn.Sequential(*model) def forward(self, input): """Standard forward""" return self.model(input) class ResnetBlock(nn.Module): """Define a Resnet block""" def __init__(self, dim, padding_type, norm_layer, use_dropout, use_bias): """Initialize the Resnet block A resnet block is a conv block with skip connections We construct a conv block with build_conv_block function, and implement skip connections in <forward> function. Original Resnet paper: https://arxiv.org/pdf/1512.03385.pdf """ super(ResnetBlock, self).__init__() self.conv_block = self.build_conv_block(dim, padding_type, norm_layer, use_dropout, use_bias) def build_conv_block(self, dim, padding_type, norm_layer, use_dropout, use_bias): """Construct a convolutional block. Parameters: dim (int) -- the number of channels in the conv layer. padding_type (str) -- the name of padding layer: reflect | replicate | zero norm_layer -- normalization layer use_dropout (bool) -- if use dropout layers. use_bias (bool) -- if the conv layer uses bias or not Returns a conv block (with a conv layer, a normalization layer, and a non-linearity layer (ReLU)) """ conv_block = [] p = 0 if padding_type == 'reflect': conv_block += [nn.ReflectionPad2d(1)] elif padding_type == 'replicate': conv_block += [nn.ReplicationPad2d(1)] elif padding_type == 'zero': p = 1 else: raise NotImplementedError('padding [%s] is not implemented' % padding_type) conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p, bias=use_bias), norm_layer(dim), nn.ReLU(True)] if use_dropout: conv_block += [nn.Dropout(0.5)] p = 0 if padding_type == 'reflect': conv_block += [nn.ReflectionPad2d(1)] elif padding_type == 'replicate': conv_block += [nn.ReplicationPad2d(1)] elif padding_type == 'zero': p = 1 else: raise NotImplementedError('padding [%s] is not implemented' % padding_type) conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p, bias=use_bias), norm_layer(dim)] return nn.Sequential(*conv_block) def forward(self, x): """Forward function (with skip connections)""" out = x + self.conv_block(x) # add skip connections return out import functools norm_layer = functools.partial(nn.InstanceNorm2d, affine=False, track_running_stats=False) model = ResnetGenerator(3,3,64, norm_layer=norm_layer, use_dropout=False, n_blocks=9) model.load_state_dict(torch.load(path)) model.eval() model.cuda() model.half() trace_input = torch.ones(1,3,256,256).cuda() model = model.eval() jit_model = torch.jit.trace(model.float(), trace_input) torch.jit.save(jit_model, output_path) 

استبدال المتغيرات الخاصة بك:


  • المسار - المسار إلى نموذج التكرار الذي تريده.
    نحن بحاجة إلى ملف * G_A.pth - مولد الصور -> الكتاب الهزلي.
  • output_path - اسم ملف النموذج الذي تم تصديره ، يمكن أن يكون أي شيء بالامتداد *. جيت ، الشيء الرئيسي هو عدم نسيان المكان الذي حفظناه فيه.

ليس من الضروري تصدير المولد من الحقبة الأخيرة من التدريب ، خذ الذي ترغب في تحقيق نتائج أكثر.

بعد ذلك ، انتقل إلى وحدة التحكم ، انتقل إلى المجلد مع ملفنا والكتابة:


 python jit.py 

فويلا! النموذج جاهز للتعرف على العالم الخارجي.


مزيد من المعلومات حول الشعلة جيت

الوثائق: https://pytorch.org/docs/stable/jit.html
باختصار ، يتيح لك التصدير إلى jit إجراء تسلسل للنموذج وعدم السحب على طول بيئة الثعبان ، وجميع التبعيات والوحدات الخارجية التي يمكنه استخدامها. باستثناء الشعلة ، بالطبع.
على الرغم من أننا سنستضيفها في بيئة بيثون ، إلا أنه يمكن استخدام نماذج jit في التطبيقات المستقلة.


اختيار استضافة


سأكون صريحا للغاية وأعترف على الفور: لقد توفي عشاق التعلم الداخلي العميق في مكان ما في الساعة الثانية من استكشاف إمكانيات الاستضافة بدعم GPU. فإذا أخبرني شخص ما باستضافة خادم GPU غير مكلفة ، فسأكون أكثر من ممتن.

لم أخطط للدفع مقابل خادم متكامل لتجاربي ، لذلك كنت أبحث فقط عن حلول بدون خادم.


بعد اقتحام الزحف على خطط التعريفة المتعددة الصفحات الخاصة بـ Google و Amazon ، وقع اختياري على algorithmia.com


هناك عدة أسباب:


  • يعد IDE Web مثاليًا للدمى ، وإن كان بطيئًا للغاية ، لأنه يتعين عليك الانتظار حتى يكتمل الإنشاء للتحقق. خارج هذا البرنامج التعليمي ، أوصي باختبار كل شيء محليًا ، حيث تحدث معظم الأخطاء في مرحلة تنزيل الملفات وحفظها.


  • الحد الأدنى لعدد الخيارات - من الصعب أن تموت من الشيخوخة المبكرة ، دون قراءة قائمة الخيارات حتى النهاية.


  • حسنًا ، الحجة الأخيرة - لنحو نصف عام من التجارب ، ما زلت لم أنفق رصيدًا مجانيًا.



رغم أنه الآن عند تسجيل حساب شخصي يقدمونه أقل من الصيف الماضي ، إلا أن هذا يجب أن يكون كافياً لفترة من الوقت ، وبالتأكيد لجميع تجاربنا. في نهاية الشهر ، يتم سكب المزيد من القروض ، مما أنقذني أكثر من مرة من الخراب المحتمل.


من السلبيات ، تجدر الإشارة إلى أن بطاقات الفيديو هناك فقط تسلا K80 القديمة مع 12 جيجابايت من ذاكرة الوصول العشوائي ، والذي يفرض قيود المقابلة. في أي حال ، حتى نصل إلى الإنتاج ، سوف نفهم بالفعل ما نحتاجه من الخادم.


نشر النماذج


حسنا ، إلى المعركة!


تسجيل


نذهب إلى https://algorithmia.com/signup والتسجيل. لست متأكدًا من وجود اختلاف في نوع المهنة \ نوع الحساب الذي يجب اختياره ، ولكن إذا وجدت مجموعة ذهبية توفر الحد الأقصى للائتمانات ، فتأكد من إخباري في التعليقات!


تحميل نموذج


بعد التسجيل ، سنكون في ملفك الشخصي.
نحتاج إلى إنشاء مجلدات للنموذج والصور التي سيقوم بإنشائها.
للقيام بذلك ، حدد Data Sources في القائمة على اليسار.


انقر فوق مصدر بيانات جديد -> مجموعة البيانات المستضافة
دعنا اسم المجلد "بلدي النماذج".
نتيجة لذلك ، يجب نقلنا إلى صفحة تحتوي على قائمة المجلدات الخاصة بنا.


إنشاء مجلد آخر: مجموعة جديدة -> "photo2comics_out"


حان الوقت لتنزيل نموذجنا المُصدر حديثًا!
انتقل إلى مجلد My Models واسحب ملف الطراز إلى المستعرض ، أو حدد تحميل الملفات من القائمة.


الآن قم بنسخ الرابط إلى نموذجنا ، وسيكون من المفيد لنا أدناه. للقيام بذلك ، انقر فوق علامة القطع الموجودة على يمين اسم الملف.


انتهت البيانات ، انتقل إلى الخوارزمية نفسها.


خوارزمية


نعود إلى الملف الشخصي من خلال النقر على الصفحة الرئيسية في القائمة على اليسار.


بعد ذلك ، انقر فوق إنشاء جديد -> خوارزمية وحدد اسم الخوارزمية الخاصة بنا. نملأ الخيارات المتبقية كما في الصورة أدناه.


الصورة أدناه


انقر فوق إنشاء خوارزمية جديدة وحدد WebIDE في النافذة التي تظهر.
إذا قمت بإغلاق الإطار المنبثق عن طريق الخطأ ، فيمكنك فتح التعليمات البرمجية المصدر بالنقر فوق "شفرة المصدر" في قائمة الخوارزمية الخاصة بنا.


نزيل شفرة القالب ونضيف رمزنا:


بعض التعليمات البرمجية لنسخ أكثر طائش
 import Algorithmia import torch import torchvision import torchvision.transforms as transforms import cv2 from torch import * import uuid import gc import requests import numpy as np client = Algorithmia.client() #     file_path,      #   model_file   . def load_model(): file_path = "{      }" model_file = client.file(file_path).getFile().name model = torch.jit.load(model_file).half().cuda() return model model = load_model().eval() torch.cuda.empty_cache() torch.cuda.ipc_collect() torch.backends.cudnn.benchmark = True #    ,    , #     , # ..      def preprocessing(image_path, max_size): response = requests.get(image_path) response = response.content nparr = np.frombuffer(response, np.uint8) img_res = cv2.imdecode(nparr, cv2.IMREAD_COLOR) img_res = cv2.cvtColor(img_res, cv2.COLOR_BGR2RGB) x = img_res.shape[0] y = img_res.shape[1] #if image is bigger than the target max_size, downscale it if x>max_size and x<=y: y = y*(max_size/x) x = max_size if y>max_size and y<x: x = x*(max_size/y) y = max_size size = (int(y),int(x)) img_res = cv2.resize(img_res,size) t = Tensor(img_res/255.)[None,:] t = t.permute(0,3,1,2).half().cuda() # standartize t = (t-0.5)/0.5 return(t) def predict(input): gc.collect() with torch.no_grad(): res = model(input).detach() return res #   ,     #      def save_file(res, file_uri): #de-standartize res = (res*0.5)+0.5 tempfile = "/tmp/"+str(uuid.uuid4())+".jpg" torchvision.utils.save_image(res,tempfile) client.file(file_uri).putFile(tempfile) # API calls will begin at the apply() method, with the request body passed as 'input' # For more details, see algorithmia.com/developers/algorithm-development/languages def apply(input): processed_data= preprocessing(input["in"], input["size"]) res = predict(processed_data) save_file(res, input["out"]) input = None res = None processed_data = None gc.collect() return "Success" 

لا تنسَ إدراج رابط للطراز الذي تم تنزيله. قمنا بنسخه في القسم السابق عند تحميل النموذج.


أثناء وجودك في WebIDE ، انقر فوق DEPENDENCIES في الجزء العلوي الأيمن واستبدل النص بقائمة من تبعياتنا:


 algorithmia>=1.0.0,<2.0 opencv-python six torch==1.3.0 torchvision numpy 

يجب أن تكون نسخة المشعل هي نفسها أو الأحدث من النسخة التي حفظنا بها النموذج. خلاف ذلك ، قد تكون هناك أخطاء عند استيراد نموذج jit.


انقر فوق "حفظ" و "إنشاء" وانتظر حتى يكتمل الإنشاء. بمجرد ظهور رسالة حول إنشاء ناجح في وحدة التحكم أدناه ، يمكننا التحقق من أداء الطراز عن طريق إرسال طلب اختبار إلى وحدة التحكم:


 {"in":"https://cdn3.sportngin.com/attachments/photo/9226/3971/JABC-9u_medium.JPG", "out":"data://username/photo2comics_out/test.jpg", "size":512} 

حيث {اسم المستخدم} هو اسم المستخدم الخاص بك. إذا سارت الأمور على ما يرام ، فسيظهر "Success" في وحدة التحكم ، وستظهر الصورة التي تم إنشاؤها في المجلد الذي حددناه (في هذه الحالة photo2comics_out).


النتائج


مبروك ، نحن بتأجيل وبثمن غاضب نموذجنا المتواضع!


في العدد التالي ، سنكون صداقات مع نموذج telegram bot ، وفي النهاية ، سنصدر كل هذه الأشياء.
إذا كنت لا تستطيع الانتظار لتجربة النموذج ، يمكنك دائمًا قراءة الوثائق الرسمية: https://algorithmia.com/developers/api/


حسنًا ، من أجل قضاء الوقت حتى المقالة التالية ، يمكنك وضع بعض الروبوتات ، النماذج التي نشرتها على الخوارزمية:


@ selfie2animebot - يتحول selfie إلى أنيمي
pimpmyresbot - زيادة دقة x2 (بحد أقصى 1400 × 1400)
photozoombot - يقوم بإنشاء فيديو تكبير ثلاثي الأبعاد من صورة واحدة
@ photo2comicsbot - في الواقع ، بطل هذه المناسبة


لا تنسى مشاركة النتائج والأفكار والمشاكل التي صودفت في التعليقات.
هذا كل شيء لهذا اليوم. اراك قريبا!

Source: https://habr.com/ru/post/ar485824/


All Articles