Kemajuan di bidang jaringan saraf pada umumnya dan pengenalan pola pada khususnya telah mengarah pada fakta bahwa mungkin tampak seolah-olah membuat aplikasi jaringan saraf untuk bekerja dengan gambar adalah tugas rutin. Dalam arti tertentu, itu adalah - jika Anda menemukan ide yang berkaitan dengan pengenalan pola, jangan ragu bahwa seseorang sudah menulis sesuatu seperti itu. Yang Anda butuhkan hanyalah menemukan bagian kode yang sesuai di Google dan "kompilasi" dari penulis.
Namun, masih ada banyak detail yang membuat tugas ini tidak begitu sulit dipecahkan seperti ... membosankan, menurut saya. Butuh terlalu banyak waktu, terutama jika Anda seorang pemula yang membutuhkan kepemimpinan, selangkah demi selangkah, proyek yang dilakukan tepat di depan mata Anda, dan selesai dari awal hingga selesai. Tanpa biasa dalam kasus seperti itu, "lewati bagian yang jelas ini" alasan.
Dalam artikel ini, kami akan mempertimbangkan tugas membuat Dog Breed Identifier: kami akan membuat dan melatih jaringan saraf, dan kemudian port ke Java untuk Android dan mempublikasikannya di Google Play.
Jika Anda ingin melihat hasil akhirnya, ini dia:
Aplikasi NeuroDog di Google Play.
Situs web dengan robotika saya (sedang berlangsung):
robotics.snowcron.com .
Situs web dengan program itu sendiri, termasuk panduan:
Panduan Pengguna NeuroDog .
Dan di sini adalah tangkapan layar program:

Pernyataan masalah
Kami akan menggunakan Keras: perpustakaan Google untuk bekerja dengan jaringan saraf. Ini adalah perpustakaan tingkat tinggi, yang berarti lebih mudah digunakan dibandingkan dengan alternatif yang saya tahu. Jika ada - ada banyak buku teks tentang Keras di jaringan, berkualitas tinggi.
Kami akan menggunakan CNN - Convolutional Neural Networks. CNN (dan lebih banyak konfigurasi lanjutan berdasarkan pada mereka) adalah standar de facto dalam pengenalan gambar. Pada saat yang sama, melatih jaringan seperti itu tidak selalu mudah: Anda harus memilih struktur jaringan yang tepat, parameter pelatihan (semua tingkat pembelajaran, momentum, L1 dan L2, dll.). Tugas ini membutuhkan sumber daya komputasi yang signifikan, dan karenanya, untuk menyelesaikannya hanya dengan melalui SEMUA parameter akan gagal.
Ini adalah salah satu dari beberapa alasan mengapa dalam kebanyakan kasus mereka menggunakan apa yang disebut “pengetahuan transfer”, alih-alih apa yang disebut pendekatan “vanila”. Transfer Knowlege menggunakan jaringan saraf yang dilatih oleh seseorang sebelum kita (misalnya, Google) dan biasanya untuk tugas yang serupa, tetapi masih berbeda. Kami mengambil layer awal darinya, mengganti layer terakhir dengan classifier kita sendiri - dan itu berfungsi, dan itu berfungsi dengan baik.
Pada awalnya, hasil seperti itu mungkin mengejutkan: bagaimana kita mengambil jaringan Google yang terlatih untuk membedakan kucing dari kursi, dan ia mengenali jenis anjing untuk kita? Untuk memahami bagaimana ini terjadi, Anda perlu memahami prinsip-prinsip dasar karya Deep Neural Networks, termasuk yang digunakan untuk pengenalan pola.
Kami “memberi makan” jaringan gambar (array angka, yaitu) sebagai input. Lapisan pertama menganalisis gambar untuk pola-pola sederhana, seperti "garis horizontal", "busur", dll. Lapisan berikutnya menerima pola-pola ini sebagai input, dan menghasilkan pola orde kedua, seperti "bulu", "sudut mata" ... Pada akhirnya, kita mendapatkan teka-teki dari mana kita dapat merekonstruksi anjing: wol, dua mata, dan tangan manusia bergigi.
Semua hal di atas dilakukan dengan bantuan lapisan pra-terlatih yang kami peroleh (misalnya, dari Google). Selanjutnya, kami menambahkan layer kami, dan mengajar mereka untuk mengekstrak informasi breed dari pola ini. Kedengarannya logis.
Sebagai rangkuman, dalam artikel ini kita akan membuat "vanilla" CNN dan beberapa varian "transfer learning" dari berbagai jenis jaringan. Adapun "vanilla": Saya akan membuatnya, tetapi saya tidak berencana untuk mengkonfigurasinya dengan memilih parameter, karena jauh lebih mudah untuk melatih dan mengonfigurasi jaringan "pra-terlatih".
Karena kami berencana untuk mengajarkan jaringan saraf kami untuk mengenali ras anjing, kami harus “menunjukkan” sampel dari berbagai ras. Untungnya, ada satu set foto yang dibuat di
sini untuk tugas yang sama (
aslinya ada di sini ).
Kemudian saya berencana untuk port yang terbaik dari jaringan yang diterima untuk android. Porting jaringan Kerasov ke android relatif sederhana, diformalkan dengan baik dan kami akan melakukan semua langkah yang diperlukan, sehingga tidak akan sulit untuk mereproduksi bagian ini.
Kemudian kami akan menerbitkan semua ini di Google Play. Secara alami, Google akan menolak, jadi trik tambahan akan digunakan. Misalnya, ukuran aplikasi kita (karena jaringan saraf besar) akan lebih besar daripada ukuran yang diizinkan dari APK Android yang diterima oleh Google Play: kita harus menggunakan bundel. Selain itu, Google tidak akan menampilkan aplikasi kami di hasil pencarian, ini dapat diperbaiki dengan mendaftarkan tag pencarian di aplikasi, atau hanya menunggu ... satu atau dua minggu.
Sebagai hasilnya, kami mendapatkan aplikasi "komersial" yang berfungsi penuh (dalam tanda kutip, sebagaimana dinyatakan gratis) untuk android dan menggunakan jaringan saraf.
Lingkungan pengembangan
Anda dapat memprogram untuk Keras secara berbeda, tergantung pada OS yang Anda gunakan (disarankan Ubuntu), ada atau tidak adanya kartu video, dan sebagainya. Tidak ada yang buruk dalam pengembangan di komputer lokal (dan, karenanya, konfigurasinya), kecuali bahwa ini bukan cara termudah.
Pertama, menginstal dan mengonfigurasi sejumlah besar alat dan pustaka membutuhkan waktu, dan kemudian ketika versi baru dirilis, Anda harus menghabiskan waktu lagi. Kedua, jaringan saraf membutuhkan daya komputasi yang besar untuk pelatihan. Anda dapat mempercepat (10 kali atau lebih) proses ini jika Anda menggunakan GPU ... pada saat menulis artikel ini, GPU teratas yang paling cocok untuk pekerjaan ini adalah $ 2.000 - $ 7.000. Dan ya, mereka juga perlu dikonfigurasi.
Jadi kita akan pergi ke arah lain. Faktanya adalah bahwa Google memungkinkan landak miskin seperti kita untuk menggunakan GPU dari cluster mereka - gratis, untuk perhitungan yang berkaitan dengan jaringan saraf, itu juga menyediakan lingkungan yang sepenuhnya dikonfigurasi, bersama-sama, ini disebut Google Colab. Layanan ini memberi Anda akses ke Jupiter Notebook dengan python, Keras dan sejumlah besar perpustakaan lain sudah dikonfigurasi. Yang harus Anda lakukan adalah mendapatkan akun Google (dapatkan akun Gmail dan ini akan memberi Anda akses ke yang lainnya).
Saat ini, Colab dapat disewa di
sini , tetapi mengetahui Google, ini dapat berubah setiap saat. Hanya google Google Colab.
Masalah yang jelas dengan menggunakan Colab adalah itu adalah layanan WEB. Bagaimana kita mengakses data kita? Simpan jaringan saraf setelah pelatihan, misalnya, mengunduh data khusus untuk tugas kita dan seterusnya?
Ada beberapa (pada saat penulisan artikel ini - tiga) cara yang berbeda, kami menggunakan yang menurut saya paling nyaman - kami menggunakan Google Drive.
Google Drive adalah penyimpanan data berbasis cloud yang berfungsi seperti hard drive biasa, dan dapat dipetakan di Google Colab (lihat kode di bawah). Setelah itu, Anda dapat bekerja dengannya seperti halnya Anda bekerja dengan file pada disk lokal. Misalnya, untuk mengakses foto-foto anjing untuk melatih jaringan saraf kita, kita perlu mengunggahnya ke Google Drive, itu saja.
Membuat dan melatih jaringan saraf
Di bawah ini saya berikan kode dengan Python, blok demi blok (dari Notebook Jupiter). Anda dapat menyalin kode ini ke dalam Notebook Jupiter Anda dan menjalankannya, blok demi blok, juga, karena blok dapat dieksekusi secara independen (tentu saja, variabel yang ditentukan dalam blok awal mungkin diperlukan di bagian akhir, tetapi ini adalah ketergantungan yang jelas).
Inisialisasi
Pertama-tama, mari kita pasang Google Drive. Hanya dua baris. Kode ini harus dieksekusi hanya sekali dalam sesi Colab (katakanlah, setiap 6 jam sekali). Jika Anda menyebutnya kedua kalinya saat sesi masih "hidup", itu akan dilewati karena drive sudah terpasang.
from google.colab import drive drive.mount('/content/drive/')
Pada awal pertama, Anda akan diminta untuk mengkonfirmasi niat Anda, tidak ada yang rumit. Begini tampilannya:
>>> Go to this URL in a browser: ... >>> Enter your authorization code: >>> ·········· >>> Mounted at /content/drive/
Bagian
termasuk sepenuhnya standar; mungkin beberapa file yang disertakan tidak diperlukan, well ... maaf. Juga, karena saya akan menguji jaringan saraf yang berbeda, Anda harus berkomentar / menghapus komentar beberapa modul yang disertakan untuk jenis jaringan saraf tertentu: misalnya, untuk menggunakan InceptionV3 NN, batalkan komentar pada inklusi InceptionV3, dan komentar, misalnya, ResNet50. Atau tidak: semua yang berubah dari ini adalah ukuran memori yang digunakan, dan itu tidak terlalu kuat.
import datetime as dt import pandas as pd import seaborn as sns import matplotlib.pyplot as plt from tqdm import tqdm import cv2 import numpy as np import os import sys import random import warnings from sklearn.model_selection import train_test_split import keras from keras import backend as K from keras import regularizers from keras.models import Sequential from keras.models import Model from keras.layers import Dense, Dropout, Activation from keras.layers import Flatten, Conv2D from keras.layers import MaxPooling2D from keras.layers import BatchNormalization, Input from keras.layers import Dropout, GlobalAveragePooling2D from keras.callbacks import Callback, EarlyStopping from keras.callbacks import ReduceLROnPlateau from keras.callbacks import ModelCheckpoint import shutil from keras.applications.vgg16 import preprocess_input from keras.preprocessing import image from keras.preprocessing.image import ImageDataGenerator from keras.models import load_model from keras.applications.resnet50 import ResNet50 from keras.applications.resnet50 import preprocess_input from keras.applications.resnet50 import decode_predictions from keras.applications import inception_v3 from keras.applications.inception_v3 import InceptionV3 from keras.applications.inception_v3 import preprocess_input as inception_v3_preprocessor from keras.applications.mobilenetv2 import MobileNetV2 from keras.applications.nasnet import NASNetMobile
Di Google Drive, kami membuat folder untuk file kami. Baris kedua menampilkan isinya:
working_path = "/content/drive/My Drive/DeepDogBreed/data/" !ls "/content/drive/My Drive/DeepDogBreed/data" >>> all_images labels.csv models test train valid
Seperti yang Anda lihat, foto-foto anjing (disalin dari dataset Stanford (lihat di atas) di Google Drive) pertama kali disimpan di folder
all_images . Nantinya, kami akan menyalinnya ke direktori
kereta, valid, dan
uji . Kami akan menyimpan model yang terlatih dalam folder
model . Adapun file labels.csv, ini adalah bagian dari dataset dengan foto, ini berisi daftar korespondensi nama gambar dan trah anjing.
Ada banyak tes yang dapat Anda jalankan untuk memahami apa sebenarnya yang kami dapatkan untuk penggunaan sementara dari Google. Sebagai contoh:
Seperti yang Anda lihat, GPU benar-benar terhubung, dan jika tidak, Anda perlu menemukan dan mengaktifkan opsi ini di pengaturan Notebook Jupiter.
Selanjutnya, kita perlu mendeklarasikan beberapa konstanta, seperti ukuran gambar, dll. Kami akan menggunakan gambar dengan ukuran 256x256 piksel, ini adalah gambar yang cukup besar agar tidak kehilangan detail, dan cukup kecil sehingga semuanya pas di memori. Namun, perlu diketahui bahwa beberapa jenis jaringan saraf yang akan kita gunakan mengharapkan gambar 224x224 piksel. Dalam kasus seperti itu, kami berkomentar 256 dan menghapus komentar 224.
Pendekatan yang sama (komentar satu - batalkan komentar) akan diterapkan pada nama model yang kita simpan, hanya karena kita tidak ingin menimpa file yang mungkin masih berguna.
warnings.filterwarnings("ignore") os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' np.random.seed(7) start = dt.datetime.now() BATCH_SIZE = 16 EPOCHS = 15 TESTING_SPLIT=0.3
Pemuatan data
Pertama-tama, mari kita
unggah file
labels.csv dan
pisahkan ke bagian pelatihan dan validasi. Perhatikan bahwa belum ada bagian pengujian, karena saya akan menipu untuk mendapatkan lebih banyak data pelatihan.
labels = pd.read_csv(working_path + 'labels.csv') print(labels.head()) train_ids, valid_ids = train_test_split(labels, test_size = TESTING_SPLIT) print(len(train_ids), 'train ids', len(valid_ids), 'validation ids') print('Total', len(labels), 'testing images') >>> id breed >>> 0 000bec180eb18c7604dcecc8fe0dba07 boston_bull >>> 1 001513dfcb2ffafc82cccf4d8bbaba97 dingo >>> 2 001cdf01b096e06d78e9e5112d419397 pekinese >>> 3 00214f311d5d2247d5dfe4fe24b2303d bluetick >>> 4 0021f9ceb3235effd7fcde7f7538ed62 golden_retriever >>> 7155 train ids 3067 validation ids >>> Total 10222 testing images
Selanjutnya, salin file gambar ke folder pelatihan / validasi / pengujian, sesuai dengan nama file. Fungsi berikut menyalin file yang namanya kami transfer ke folder yang ditentukan.
def copyFileSet(strDirFrom, strDirTo, arrFileNames): arrBreeds = np.asarray(arrFileNames['breed']) arrFileNames = np.asarray(arrFileNames['id']) if not os.path.exists(strDirTo): os.makedirs(strDirTo) for i in tqdm(range(len(arrFileNames))): strFileNameFrom = strDirFrom + arrFileNames[i] + ".jpg" strFileNameTo = strDirTo + arrBreeds[i] + "/" + arrFileNames[i] + ".jpg" if not os.path.exists(strDirTo + arrBreeds[i] + "/"): os.makedirs(strDirTo + arrBreeds[i] + "/")
Seperti yang Anda lihat, kami hanya menyalin satu file untuk setiap trah anjing sebagai
tes . Juga, saat menyalin, kami membuat subfolder, satu untuk setiap trah. Oleh karena itu, foto-foto disalin ke subfolder oleh breed.
Ini dilakukan karena Keras dapat bekerja dengan direktori dengan struktur yang sama, memuat file gambar sesuai kebutuhan, dan tidak sekaligus, yang menghemat memori. Mengunggah semua 15.000 gambar sekaligus adalah ide yang buruk.
Kami harus memanggil fungsi ini hanya sekali, karena ini menyalin gambar - dan tidak lagi diperlukan. Karenanya, untuk penggunaan di masa mendatang, kita harus mengomentarinya:
Dapatkan daftar trah anjing:
breeds = np.unique(labels['breed']) map_characters = {}
Pemrosesan gambar
Kita akan menggunakan fitur pustaka Keras yang disebut ImageDataGenerators. ImageDataGenerator dapat memproses gambar, skala, memutar, dan sebagainya. Itu juga dapat menerima fungsi
pemrosesan yang dapat memproses gambar tambahan.
def preprocess(img): img = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE), interpolation = cv2.INTER_AREA)
Perhatikan kode berikut:
Kita dapat menormalkan (sub-data di bawah rentang 0-1 alih-alih yang asli 0-255) di ImageDataGenerator itu sendiri. Lalu mengapa kita membutuhkan preprosesor? Sebagai contoh, pertimbangkan panggilan kabur (dikomentari, saya tidak menggunakannya): ini adalah manipulasi gambar khusus yang sama yang dapat arbitrer. Apa pun yang kontras dengan HDR.
Kami akan menggunakan dua ImageDataGenerators yang berbeda, satu untuk pelatihan dan satu untuk validasi. Perbedaannya adalah bahwa untuk pelatihan kita perlu belokan dan penskalaan untuk meningkatkan "variasi" data, tetapi untuk validasi, kita tidak membutuhkannya, setidaknya tidak dalam tugas ini.
train_datagen = ImageDataGenerator( preprocessing_function=preprocess,
Menciptakan jaringan saraf
Seperti yang telah disebutkan, kita akan membuat beberapa jenis jaringan saraf. Setiap kali kita memanggil fungsi lain untuk dibuat, sertakan file lain dan kadang-kadang menentukan ukuran gambar yang berbeda. Jadi, untuk beralih di antara berbagai jenis jaringan saraf, kita harus mengomentari / menghapus komentar kode yang sesuai.
Pertama-tama, buat CNN "vanilla". Itu tidak berfungsi dengan baik, karena saya memutuskan untuk tidak membuang waktu men-debug-nya, tetapi setidaknya itu memberikan dasar yang dapat dikembangkan jika ada keinginan (biasanya ini adalah ide yang buruk, karena jaringan pra-terlatih memberikan hasil terbaik).
def createModelVanilla(): model = Sequential()
Saat kami membuat jaringan menggunakan
pembelajaran transfer , prosedurnya berubah:
def createModelMobileNetV2():
Membuat jenis jaringan lain mengikuti pola yang sama:
def createModelResNet50(): base_model = ResNet50(weights='imagenet', include_top=False, pooling='avg', input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3)) x = base_model.output x = Dense(512)(x) x = Activation('relu')(x) x = Dropout(0.5)(x) predictions = Dense(NUM_CLASSES, activation='softmax')(x) model = Model(inputs=base_model.input, outputs=predictions)
Peringatan: pemenang! NN ini menunjukkan hasil terbaik:
def createModelInceptionV3():
Satu lagi:
def createModelNASNetMobile():
Berbagai jenis jaringan saraf dapat digunakan untuk tugas yang berbeda. Jadi, selain persyaratan untuk akurasi prediksi, ukuran juga penting (NN seluler 5 kali lebih kecil dari Inception) dan kecepatan (jika kita membutuhkan pemrosesan streaming video secara real-time, maka akurasi harus dikorbankan).
Pelatihan jaringan saraf
Pertama-tama, kami
bereksperimen , jadi kami harus dapat menghapus jaringan saraf yang telah kami simpan, tetapi tidak lagi digunakan. Fungsi berikut menghapus NN jika ada:
Cara kita membuat dan menghapus jaringan saraf cukup sederhana dan mudah. Pertama, hapus. Saat memanggil
delete (hanya), harus diingat bahwa Jupiter Notebook memiliki fungsi "run selection", pilih hanya apa yang ingin Anda gunakan, dan jalankan.
Kemudian kita membuat jaringan saraf jika file-nya tidak ada, atau memanggil
beban jika ada: tentu saja, kita tidak bisa memanggil "delete" dan kemudian mengharapkan NN ada, jadi untuk menggunakan jaringan saraf yang disimpan, jangan panggil
delete .
Dengan kata lain, kita dapat membuat NN baru, atau menggunakan NN yang sudah ada, tergantung pada situasinya dan pada apa yang sedang kita eksperimenkan. Skenario sederhana: kami melatih jaringan saraf, lalu pergi berlibur. Mereka kembali, dan Google memakukan sesi, jadi kita perlu memuat yang disimpan sebelumnya: komentar "hapus" dan hapus komentar "muat".
deleteSavedNet(working_path + strModelFileName)
Pos pemeriksaan adalah elemen yang sangat penting dari program kami. Kita dapat membuat berbagai fungsi yang harus dipanggil di akhir setiap era pelatihan, dan meneruskannya ke pos pemeriksaan. Misalnya, Anda dapat menyimpan jaringan saraf
jika itu menunjukkan hasil yang lebih baik daripada yang sudah disimpan.
checkpoint = ModelCheckpoint(working_path + strModelFileName, monitor='val_acc', verbose=1, save_best_only=True, mode='auto', save_weights_only=False) callbacks_list = [ checkpoint ]
Akhirnya, kami mengajarkan jaringan saraf pada set pelatihan:
Grafik untuk akurasi dan kehilangan untuk yang terbaik dari konfigurasi adalah sebagai berikut:


Seperti yang Anda lihat, jaringan saraf sedang belajar, dan tidak buruk.
Pengujian jaringan saraf
Setelah pelatihan selesai, kita harus menguji hasilnya; untuk ini, NN menyajikan gambar-gambar yang belum pernah dilihatnya - foto-foto yang kami salin ke dalam folder pengujian - satu untuk setiap jenis anjing.
Ekspor jaringan saraf ke aplikasi Java
Pertama-tama, kita perlu mengatur pemuatan jaringan saraf dari disk. Alasannya jelas: ekspor terjadi di blok kode lain, jadi kemungkinan besar kita akan memulai ekspor secara terpisah - ketika jaringan saraf dibawa ke keadaan optimal. Artinya, segera sebelum ekspor, dalam menjalankan program yang sama, kami tidak akan melatih jaringan. Jika Anda menggunakan kode yang ditunjukkan di sini, maka tidak ada perbedaan, jaringan optimal telah dipilih untuk Anda. Tetapi jika Anda mempelajari sesuatu dari Anda sendiri, maka untuk melatih segala sesuatu yang baru sebelum menabung adalah buang-buang waktu, jika sebelumnya Anda menyimpan semuanya.
Untuk alasan yang sama - jangan melompati kode - saya menyertakan file yang diperlukan untuk ekspor di sini. Tidak ada yang mengganggu Anda untuk memindahkan mereka ke awal program jika selera kecantikan Anda mengharuskannya:
from keras.models import Model from keras.models import load_model from keras.layers import * import os import sys import tensorflow as tf
Pengujian kecil setelah memuat jaringan saraf, hanya untuk memastikan semuanya dimuat - berfungsi:
img = image.load_img(working_path + "test/affenpinscher.jpg")

Selanjutnya, kita perlu mendapatkan nama-nama lapisan input dan output dari jaringan (baik ini atau fungsi pembuatan, kita harus secara eksplisit "memberi nama" lapisan, yang tidak kita lakukan).
model.summary() >>> Layer (type) >>> ====================== >>> input_7 (InputLayer) >>> ______________________ >>> conv2d_283 (Conv2D) >>> ______________________ >>> ... >>> dense_14 (Dense) >>> ====================== >>> Total params: 22,913,432 >>> Trainable params: 1,110,648 >>> Non-trainable params: 21,802,784
Kami akan menggunakan nama-nama lapisan input dan output nanti ketika kami mengimpor jaringan saraf ke aplikasi Java.
Kode lain berkeliaran di jaringan untuk mendapatkan data ini:
def print_graph_nodes(filename): g = tf.GraphDef() g.ParseFromString(open(filename, 'rb').read()) print() print(filename) print("=======================INPUT===================") print([n for n in g.node if n.name.find('input') != -1]) print("=======================OUTPUT==================") print([n for n in g.node if n.name.find('output') != -1]) print("===================KERAS_LEARNING==============") print([n for n in g.node if n.name.find('keras_learning_phase') != -1]) print("===============================================") print()
Tetapi saya tidak menyukainya dan saya tidak merekomendasikannya.Kode berikut akan mengekspor Keras Neural Network ke format pb , yang akan kami tangkap dari Android. def keras_to_tensorflow(keras_model, output_dir, model_name,out_prefix="output_", log_tensorboard=True): if os.path.exists(output_dir) == False: os.mkdir(output_dir) out_nodes = [] for i in range(len(keras_model.outputs)): out_nodes.append(out_prefix + str(i + 1)) tf.identity(keras_model.output[i], out_prefix + str(i + 1)) sess = K.get_session() from tensorflow.python.framework import graph_util from tensorflow.python.framework graph_io init_graph = sess.graph.as_graph_def() main_graph = graph_util.convert_variables_to_constants( sess, init_graph, out_nodes) graph_io.write_graph(main_graph, output_dir, name=model_name, as_text=False) if log_tensorboard: from tensorflow.python.tools import import_pb_to_tensorboard import_pb_to_tensorboard.import_to_tensorboard( os.path.join(output_dir, model_name), output_dir)
Memanggil fungsi-fungsi ini untuk mengekspor jaringan saraf:
model = load_model(working_path + strModelFileName) keras_to_tensorflow(model, output_dir=working_path + strModelFileName, model_name=working_path + "models/dogs.pb") print_graph_nodes(working_path + "models/dogs.pb")
Baris terakhir mencetak struktur jaringan saraf yang dihasilkan.Membuat aplikasi Android menggunakan jaringan saraf
Ekspor jaringan saraf di Android diformalkan dengan baik dan seharusnya tidak menyebabkan kesulitan. Ada, seperti biasa, beberapa cara, kami menggunakan yang paling (pada saat penulisan) populer.Pertama-tama, kami menggunakan Android Studio untuk membuat proyek baru. Kami akan “berhemat” karena tugas kami bukan tutorial android. Jadi aplikasi hanya akan berisi satu aktivitas.
Seperti yang Anda lihat, kami menambahkan folder "aset" dan menyalin jaringan saraf kami ke dalamnya (yang sebelumnya kami ekspor).File Gradle
Dalam file ini, Anda perlu membuat beberapa perubahan. Pertama-tama, kita perlu mengimpor perpustakaan tensorflow-android . Ini digunakan untuk bekerja dengan Tensorflow (dan, karenanya, Keras) dari Jawa:
Satu lagi penghalang yang tidak terlihat: versionCode dan versionName . Saat aplikasi berubah, Anda harus mengunggah versi baru di Google Play. Tanpa mengubah versi di gdadle (misalnya, 1 -> 2 -> 3 ...) Anda tidak dapat melakukan ini, Google akan memberikan kesalahan "versi ini sudah ada."Terwujud
Pertama-tama, aplikasi kita akan “berat” - 100 Mb Neural Network akan dengan mudah masuk ke dalam memori ponsel modern, tetapi membuka contoh terpisah untuk setiap foto yang “dibagikan” dari Facebook jelas merupakan ide yang buruk.Jadi kami melarang untuk membuat lebih dari satu contoh aplikasi kami: <activity android:name=".MainActivity" android:launchMode="singleTask">
Dengan menambahkan android: launchMode = "singleTask" ke MainActivity, kami memberi tahu Android untuk membuka (mengaktifkan) salinan aplikasi yang ada, alih-alih membuat instance lain.Maka kita perlu memasukkan aplikasi kita dalam daftar, yang ditampilkan oleh sistem ketika seseorang “membagikan” gambar: <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> </intent-filter>
Terakhir, kita perlu meminta fitur dan izin yang akan digunakan aplikasi kita: <uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />
Jika Anda terbiasa dengan pemrograman untuk Android, bagian ini seharusnya tidak menimbulkan pertanyaan.Aplikasi tata letak.
Kami akan membuat dua tata letak, satu untuk potret dan satu untuk lanskap. Seperti inilah tampilan Portrait .Apa yang akan kami tambahkan: bidang besar (tampilan) untuk menampilkan gambar, daftar iklan yang mengganggu (ditampilkan ketika tombol dengan tulang ditekan), tombol Bantuan, tombol untuk mengunduh gambar dari File / Galeri dan mengambil dari kamera, dan akhirnya (awalnya tersembunyi) tombol "Proses" untuk pemrosesan gambar.
Aktivitas itu sendiri berisi semua logika menampilkan dan menyembunyikan, serta mengaktifkan / menonaktifkan tombol, tergantung pada keadaan aplikasi.Mainaktivitas
Aktivitas ini mewarisi (meluas) Aktivitas Android standar: public class MainActivity extends Activity
Pertimbangkan kode yang bertanggung jawab untuk pengoperasian jaringan saraf.Pertama-tama, jaringan saraf menerima Bitmap. Awalnya, ini adalah Bitmap besar (ukuran sewenang-wenang) dari kamera atau dari file (m_bitmap), kemudian kami mengubahnya, mengarah ke 256x256 piksel standar (m_bitmapForNn). Kami juga menyimpan ukuran bitmap (256) dalam sebuah konstanta: static Bitmap m_bitmap = null; static Bitmap m_bitmapForNn = null; private int m_nImageSize = 256;
Kita harus memberi tahu jaringan saraf nama dari lapisan input dan output; kami menerimanya lebih awal (lihat daftar), tetapi perlu diingat bahwa dalam kasus Anda mereka mungkin berbeda: private String INPUT_NAME = "input_7_1"; private String OUTPUT_NAME = "output_1";
Kemudian kami mendeklarasikan variabel untuk memegang objek TensofFlow. Juga, kami menyimpan path ke file jaringan saraf (yang terletak pada aset):private TensorFlowInferenceInterface tf;
private String MODEL_PATH =
"file: ///android_asset/dogs.pb";
Kami menyimpan trah anjing dalam daftar, sehingga nanti akan ditampilkan kepada pengguna, bukan indeks array: private String[] m_arrBreedsArray;
Awalnya, kami mengunduh Bitmap. Namun, jaringan saraf mengharapkan array nilai RGB, dan outputnya adalah array probabilitas yang berkembang biak ini adalah apa yang ditunjukkan pada gambar. Oleh karena itu, kita perlu menambahkan dua array lagi (perhatikan bahwa 120 adalah jumlah ras anjing yang ada dalam data pelatihan kami): private float[] m_arrPrediction = new float[120]; private float[] m_arrInput = null;
Unduh perpustakaan inferensi tensorflow: static { System.loadLibrary("tensorflow_inference"); }
Karena operasi jaringan saraf membutuhkan waktu, kita perlu menjalankannya di utas terpisah, jika tidak ada kemungkinan bahwa kita akan menerima pesan sistem "aplikasi tidak merespons", belum lagi pengguna yang tidak puas. class PredictionTask extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); }
Di onCreate () dari MainActivity, kita perlu menambahkan onClickListener untuk tombol "Proses": m_btn_process.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { processImage(); } });
Di sini processImage () hanya memanggil utas yang kami jelaskan di atas: private void processImage() { try { enableControls(false);
Catatan tambahan
Kami tidak berencana untuk membahas rincian pemrograman UI untuk Android, karena ini tentu saja tidak berlaku untuk tugas porting jaringan saraf. Namun, satu hal masih layak disebut.Ketika kami mencegah pembuatan instance tambahan dari aplikasi kami, kami juga melanggar urutan normal pembuatan dan penghapusan aktivitas (aliran kontrol): jika Anda "berbagi" gambar dari Facebook, dan kemudian membagikan yang lain, maka aplikasi tidak akan memulai ulang. Ini berarti bahwa cara "tradisional" untuk menangkap data yang ditransfer di onCreate tidak akan cukup, karena onCreate tidak akan dipanggil.Berikut cara mengatasi masalah ini:1. Di onCreate di MainActivity, panggil fungsi onSharedIntent: protected void onCreate( Bundle savedInstanceState) { super.onCreate(savedInstanceState); .... onSharedIntent(); ....
Kami juga menambahkan handler untuk onNewIntent: @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); onSharedIntent(); }
Ini adalah fungsi onSharedIntent itu sendiri: private void onSharedIntent() { Intent receivedIntent = getIntent(); String receivedAction = receivedIntent.getAction(); String receivedType = receivedIntent.getType(); if (receivedAction.equals(Intent.ACTION_SEND)) {
Sekarang kami memproses data yang ditransfer di onCreate (jika aplikasi tidak ada dalam memori) atau di onNewIntent (jika diluncurkan sebelumnya).Semoga beruntung
Jika Anda menyukai artikel ini, silakan “suka” dengan semua cara yang mungkin, ada juga tombol “sosial” di situs .