{"id":395944,"date":"2024-06-29T12:32:21","date_gmt":"2024-06-29T12:32:21","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=395944"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=395944","title":{"rendered":"<span>\u041a\u0430\u043a \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0418\u0418 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435 \u0432\u0432\u043e\u0434\u0438\u043c\u044b\u0445 \u0432\u0430\u043c\u0438 \u0440\u0443\u043a\u043e\u043f\u0438\u0441\u043d\u044b\u0445 \u0446\u0438\u0444\u0440 \u043f\u0440\u044f\u043c\u043e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/080\/258\/d09\/080258d0965f03f0bf923064ec5e544e.jpeg\" width=\"1097\" height=\"613\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/080\/258\/d09\/080258d0965f03f0bf923064ec5e544e.jpeg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u043b\u044f \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432 \u0438 \u043d\u0435 \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442 \u043d\u0430 \u0432\u044b\u0441\u043e\u043a\u0438\u0439 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u0430 \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 <a href=\"https:\/\/habr.com\/ru\/company\/skillfactory\/blog\/564896\/\">\u0441\u0442\u0430\u0442\u044c\u044e \u043e GIRAFFE<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0435\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0441\u0430\u043c\u044b\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0432 \u0418\u0418.<\/p>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u044b \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0441 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0443\u043a\u043e\u043f\u0438\u0441\u043d\u043e\u0433\u043e \u0432\u0432\u043e\u0434\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0418\u0418, \u0430 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0432 \u044d\u0442\u043e \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e, \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u043e\u043c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0434\u0435\u043b\u0438\u043c\u0441\u044f \u043a \u0441\u0442\u0430\u0440\u0442\u0443 \u043a\u0443\u0440\u0441\u0430 \u043e <a href=\"https:\/\/skillfactory.ru\/ml-and-dl?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_MLDL&amp;utm_term=regular&amp;utm_content=280721\">\u043c\u0430\u0448\u0438\u043d\u043d\u043e\u043c \u0438 \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u043c \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0438<\/a>, \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u0432\u043e\u0439 \u0431\u043b\u043e\u043a\u043d\u043e\u0442 Colab \u0438\u043b\u0438 \u0431\u043b\u043e\u043a\u043d\u043e\u0442 \u0430\u0432\u0442\u043e\u0440\u0430 \u0441\u0442\u0430\u0442\u044c\u0438. \u0421\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u044b \u043c\u043e\u0434\u0435\u043b\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442 \u043c\u0435\u043d\u044c\u0448\u0435 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u0430.<\/p>\n<hr\/>\n<h2>\u041e\u0431\u0443\u0447\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0446\u0438\u0444\u0440 \u043d\u0430 \u043d\u0430\u0431\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 MNIST<\/h2>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u0431\u043b\u043e\u043a\u043d\u043e\u0442 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0432\u0441\u0451 \u0441 \u043d\u0443\u043b\u044f, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443 \u0412\u0430\u0448\u0435\u0433\u043e \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">import tensorflow as tf  # import digit dataset mnist = tf.keras.datasets.mnist (tx, ty), (vx, vy) = mnist.load_data()  # preprocess input types tx = tx[:,:,:,None].astype('float32') vx = vx[:,:,:,None].astype('float32') ty = ty.astype(int) vy = vy.astype(int)  # display relevant info print(\"\"\"tx:%s, ty:%s vx:%s, vy:%s\"\"\" % (tx.shape, ty.shape, vx.shape, vy.shape))<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0440\u043d\u043e\u0441\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 <code>tx<\/code> \u0438 \u0446\u0435\u043b\u0438 <code>ty<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 <code>vx<\/code> \u0438 \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 <code>vy<\/code>:<\/p>\n<pre><code class=\"python\">tx:(60000, 28, 28, 1), ty:(60000,)  vx:(10000, 28, 28, 1), vy:(10000,)<\/code><\/pre>\n<p>\u0412\u044b\u0432\u0435\u0434\u0435\u043c 10 \u043e\u0431\u0440\u0430\u0437\u0446\u043e\u0432 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043a\u0430\u0436\u0434\u043e\u0439 \u0446\u0438\u0444\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0434\u0430\u043d\u043d\u044b\u0435:<\/p>\n<pre><code class=\"python\">import matplotlib.pyplot as plt  # create a grid of plots f, axs = plt.subplots(10,10,figsize=(10,10))  # plot a sample number into each subplot for i in range(10):   for j in range(10):     # get a sample image for the 'i' number     img = tx[ty==i,:,:,0][j,:,:]      # plot image in axes     axs[i,j].imshow(img, cmap='gray')      # remove x and y axis     axs[i,j].axis('off')  # remove unecessary white space plt.tight_layout()  # display image plt.show()<\/code><\/pre>\n<p>\u00a0\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0447\u0451\u0440\u043d\u044b\u0439 \u0444\u043e\u043d \u0438 \u0431\u0435\u043b\u044b\u0435 \u0446\u0438\u0444\u0440\u044b. \u042d\u0442\u043e \u0432\u0430\u0436\u043d\u043e \u0432 \u0441\u043c\u044b\u0441\u043b\u0435 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0447\u0438\u0441\u0435\u043b \u0438 \u043a\u043e\u0434\u0430 canvas \u0432 HTML:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/240\/150\/d1f\/240150d1fe7a326986557149b332ce6e.png\" width=\"700\" height=\"700\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/240\/150\/d1f\/240150d1fe7a326986557149b332ce6e.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430 \u0441\u0432\u0451\u0440\u0442\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0440\u043e\u043c\u0435 \u0441\u0430\u043c\u043e\u0439 \u0441\u0432\u0451\u0440\u0442\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442\u043d\u0443\u044e \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 RELU, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u043e\u0442\u0441\u0435\u0438\u0432\u0430\u044e\u0449\u0438\u0435 \u0441\u043b\u043e\u0438:<\/p>\n<pre><code class=\"python\"># defines a standard 2d convolution block with batch normalisation,  # relu activation, max pooling and dropout  def normConvBlock(filters, return_model=True, name=None):   lays = [     tf.keras.layers.Conv2D(filters, 3, padding='valid', name=name+'_conv'),     tf.keras.layers.BatchNormalization(name=name+'_bn'),     tf.keras.layers.Activation('relu', name=name+'_act'),     tf.keras.layers.MaxPooling2D(2, strides=2, name=name+'_mpool'),     tf.keras.layers.Dropout(0.1, name=name+'_drop'),   ]    if return_model:     return tf.keras.models.Sequential(lays, name=name)   else:     return lays<\/code><\/pre>\n<p>\u041d\u0430\u0448\u0430 \u043f\u043e\u043b\u043d\u0430\u044f \u0441\u0435\u0442\u044c \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u0434\u0432\u0443\u0445 <code>normConvBlock<\/code>, \u0437\u0430\u0442\u0435\u043c \u043f\u043b\u043e\u0441\u043a\u043e\u0433\u043e \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u043b\u043e\u0442\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f \u0441 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0435\u0439 softmax. \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>Adam<\/code> . \u0412 \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0435\u0441\u0442\u044c \u043c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u043e\u0440\u044f\u0434\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0430\u043a\u0436\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0442\u0435\u0440\u0435\u0439 \u043f\u0435\u0440\u0435\u043a\u0440\u0451\u0441\u0442\u043d\u043e\u0439 \u044d\u043d\u0442\u0440\u043e\u043f\u0438\u0438:<\/p>\n<pre><code class=\"python\"># create NN model model = tf.keras.models.Sequential() model.add(normConvBlock(64, name='b1')) model.add(normConvBlock(128, name='b2')) model.add(tf.keras.layers.Flatten(name='flat')) model.add(tf.keras.layers.Dense(10, activation='softmax', name='logit'))  # compile model with adam optimizer and crossentropy loss # note that 'sparse_categorical_crossentropy' loss should be used as our target # is encoded as ordinal. if using one hot change this to 'categorical_crossentropy' model.compile('adam', 'sparse_categorical_crossentropy', metrics=['acc'])  # test model with a sample image _ = model(tx[:1,:,:,:])  # summary of model structure tf.keras.utils.plot_model(     model,      show_shapes=True,      show_layer_names=True,      show_dtype=True,     expand_nested=True,     dpi = 50 )<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0432\u044b\u0448\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043c\u043e\u0434\u0435\u043b\u0438:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f4d\/717\/7e2\/f4d7177e22deb2f73d78d3d97c410168.png\" alt=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0441\u043b\u043e\u0451\u0432 normConvBlock (b1 \u0438 b2), \u0437\u0430 \u043d\u0438\u043c\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0442 \u043f\u043b\u043e\u0441\u043a\u0438\u0439 \u0438 \u043f\u043b\u043e\u0442\u043d\u044b\u0439 \u0441\u043b\u043e\u0438\" title=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0441\u043b\u043e\u0451\u0432 normConvBlock (b1 \u0438 b2), \u0437\u0430 \u043d\u0438\u043c\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0442 \u043f\u043b\u043e\u0441\u043a\u0438\u0439 \u0438 \u043f\u043b\u043e\u0442\u043d\u044b\u0439 \u0441\u043b\u043e\u0438\" width=\"306\" height=\"855\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f4d\/717\/7e2\/f4d7177e22deb2f73d78d3d97c410168.png\"\/><figcaption>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0441\u043b\u043e\u0451\u0432 normConvBlock (b1 \u0438 b2), \u0437\u0430 \u043d\u0438\u043c\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0442 \u043f\u043b\u043e\u0441\u043a\u0438\u0439 \u0438 \u043f\u043b\u043e\u0442\u043d\u044b\u0439 \u0441\u043b\u043e\u0438<\/figcaption><\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u043e\u0431\u0443\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c, \u0432\u044b\u0437\u043e\u0432\u0435\u043c <code>model.fit<\/code> \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u043c\u0438 \u0432\u044b\u0448\u0435 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u0440\u0430\u043d\u043d\u0435\u0439 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"python\"># define an early stopping callback. This callback will load the iteration with # the best val loss at the end of training es_call = tf.keras.callbacks.EarlyStopping(     monitor='val_loss', min_delta=0, patience=2, verbose=0,     mode='auto', baseline=None, restore_best_weights=True )  # fit the model with the mnist dataset history = model.fit(tx, ty, validation_data=(vx, vy), epochs=20, batch_size=1024, callbacks=[es_call])<\/code><\/pre>\n<p>\u0422\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 (~99 % \u0432 \u043d\u0430\u0431\u043e\u0440\u0435 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438). \u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c \u0442\u043e\u0447\u043d\u0435\u0435, \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0435\u0451 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438\u043b\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043d\u0430\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u043c\u0438:<\/p>\n<pre><code>Epoch 11\/20 59\/59 [==============================] - 3s 50ms\/step - loss: 0.0317 - acc: 0.9906 - val_loss: 0.0338 - val_acc: 0.9899 Epoch 12\/20 59\/59 [==============================] - 3s 50ms\/step - loss: 0.0292 - acc: 0.9913 - val_loss: 0.0496 - val_acc: 0.9823 Epoch 13\/20 59\/59 [==============================] - 3s 50ms\/step - loss: 0.0275 - acc: 0.9918 - val_loss: 0.0422 - val_acc: 0.9866<\/code><\/pre>\n<h3>\u0412\u0435\u0441\u044c \u043a\u043e\u0434<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/andreRibeiro1989\/medium\/tree\/main\/tensorflowjs\/digit_recognition\">Github<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/colab.research.google.com\/github\/andreRibeiro1989\/medium\/blob\/main\/tensorflowjs\/digit_recognition\/tensorflow_js_training.ipynb\">Colab<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>TensorFlow.js<\/h2>\n<p>\u0414\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043c\u043e\u0434\u0435\u043b\u044c\u044e TensorFlow.js \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 HTML \u0438 JavaScript. TensorFlow.js \u2014 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u0434\u043b\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 ML \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 JavaScript \u0438 \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u0433\u043e API.<\/p>\n<h3>\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c TensorFlow \u0432 TensorFlow.js<\/h3>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0433 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438 TensorFlow \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u2014 \u0435\u0451 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043c\u043e\u0434\u0435\u043b\u044c TensorFlow.js, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>tensorflowjs.converters.save_keras_model<\/code> \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>tensorflowjs<\/code>.<\/p>\n<pre><code class=\"python\"># install \/ update the tensorflowjs package !pip install tensorflowjs > \/dev\/null 2>&amp;1  import tensorflowjs print(tensorflowjs.__version__)  # convert keras model to tensorflow js tensorflowjs.converters.save_keras_model(model, '.\/mnist_tf_keras_js_model\/')<\/code><\/pre>\n<blockquote>\n<p>\u041f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0432 Colab \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0444\u0430\u0439\u043b\u044b \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443, \u043e\u043d\u0438 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f.<\/p>\n<\/blockquote>\n<pre><code class=\"python\"># download generated files from colab to local  from google.colab import files  files.download(\"mnist_tf_keras_js_model\/group1-shard1of1.bin\") files.download(\"mnist_tf_keras_js_model\/model.json\")<\/code><\/pre>\n<h3>\u041f\u0438\u0448\u0435\u043c \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/h3>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u043f\u0430\u043f\u043a\u0435 <code>digit_recognition<\/code> \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 \u0441 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 <code>index.html<\/code> \u0438 <code>script.js<\/code>. \u0412\u043d\u0443\u0442\u0440\u0438 <code>digit_recognition<\/code> \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 <code>tensorflow<\/code>. \u0421\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 \u0438\u0437 \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u0430 Colab, <code>group1-shard1of1.bin<\/code> \u0438 <code>model.json<\/code> , \u0432 \u043d\u043e\u0432\u0443\u044e \u043f\u0430\u043f\u043a\u0443, \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code>- digit_recognition\/   - index.html   - script.js   - tensorflow\/     - group1-shard1of1.bin     - model.json<\/code><\/pre>\n<p>\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 <code>index.html<\/code> \u043b\u044e\u0431\u044b\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u043e\u043c \u043a\u043e\u0434\u0430 \u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0432 \u043d\u0435\u0433\u043e \u043a\u043e\u0434 \u043d\u0438\u0436\u0435. \u042d\u0442\u043e\u0442 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0446\u0438\u0444\u0440\u044b:<\/p>\n<pre><code>&lt;html>      &lt;head>          &lt;!-- Imports TensorFlow.js -->     &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@tensorflow\/tfjs@3.7.0\"> &lt;\/script>      &lt;!-- Imports tfjs-vis -->     &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@tensorflow\/tfjs-vis@1.5.1\/dist\/tfjs-vis.umd.min.js\">&lt;\/script>        &lt;\/head>      &lt;body>          &lt;!-- Defines the container with the predictand erase buttons, and the canvas to draw a digit -->     &lt;div id=\"container\">              &lt;h1>Draw a number&lt;\/h1>       &lt;p id=\"result\">Prediction &lt;\/p>              &lt;div>         &lt;!-- This button tells the model to return a prediction for the current canvas -->         &lt;button type=\"button\" onclick=\"predictModel()\">Predict&lt;\/button>                  &lt;!-- This button clears the canvas so that we can draw a new digit -->         &lt;button type=\"button\" onclick=\"erase()\">Clear&lt;\/button>       &lt;\/div>              &lt;!-- This defines the canvas on which we can draw a digit.             If the canvas is too small increase the width and height -->       &lt;canvas id=\"canvas\" width=\"386px\" height=\"386px\" style=\"border:1px solid #b9bfc9;margin-top:25px;\">&lt;\/canvas>     &lt;\/div>      &lt;!-- Imports the main script file -->     &lt;script src=\"script.js\">&lt;\/script>        &lt;\/body>    &lt;\/html><\/code><\/pre>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043a\u043e\u0434:<\/p>\n<ul>\n<li>\n<p>\u0412 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <code>&lt;head><\/code> \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f TensorFlow.js \u0438 \u0435\u0451 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 23 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043a\u043d\u043e\u043f\u043a\u0443 \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u044b\u0432\u043e\u0434\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 <code>predictModel<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0432 \u0442\u0435\u0433\u0435 <code>&lt;p id=\"result\"><\/code> .<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 26 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0445\u043e\u043b\u0441\u0442\u0430 <code>erase<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 31 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>canvas<\/code>, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0446\u0438\u0444\u0440\u0443 \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0442\u0440\u043e\u043a\u0435 35 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0444\u0430\u0439\u043b script.js \u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 JavaScript, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442 \u0446\u0438\u0444\u0440\u0443 \u0441 \u0445\u043e\u043b\u0441\u0442\u0430 \u0432 \u0442\u0435\u043d\u0437\u043e\u0440 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u043c\u043e\u0434\u0435\u043b\u044c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>script.js<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u043d\u0438\u0436\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u0434\u0430.\u00a0<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430:<\/p>\n<pre><code class=\"javascript\">\/\/ define relevant variables var canvas = document.getElementById(\"canvas\"); var ctx = canvas.getContext('2d'); var dragging = false; var pos = { x: 0, y: 0 };<\/code><\/pre>\n<p>\u0422\u0440\u0438\u0433\u0433\u0435\u0440\u044b \u0445\u043e\u043b\u0441\u0442\u0430:<\/p>\n<ul>\n<li>\n<p>\u041f\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044e <code>mousedown<\/code> (\u043d\u0430\u0436\u0430\u0442\u0438\u044e \u0438 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u043a\u043d\u043e\u043f\u043a\u0438) \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u044b\u0448\u0438\/\u043f\u0440\u0438\u043a\u043e\u0441\u043d\u043e\u0432\u0435\u043d\u0438\u044f. <\/p>\n<\/li>\n<li>\n<p>\u041f\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044e <code>mousemove<\/code> \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0445\u043e\u043b\u0441\u0442\u0435. \u041f\u043e <code>mouseup<\/code> (\u043a\u043e\u0433\u0434\u0430 \u043e\u0442\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u043d\u043e\u043f\u043a\u0438 \u043c\u044b\u0448\u0438) \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0449\u0438\u0439 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"javascript\">\/\/ define event listeners for both desktop and mobile  \/\/ nontouch canvas.addEventListener('mousedown',  engage); canvas.addEventListener('mousedown',  setPosition); canvas.addEventListener('mousemove',  draw); canvas.addEventListener('mouseup', disengage);  \/\/ touch canvas.addEventListener('touchstart', engage); canvas.addEventListener('touchmove', setPosition); canvas.addEventListener('touchmove', draw); canvas.addEventListener('touchend', disengage);<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432 <code>setPosition<\/code>, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u0433\u043e, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c \u0441\u0435\u043d\u0441\u043e\u0440\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"javascript\">\/\/ detect if it is a touch device function isTouchDevice() {   return (     ('ontouchstart' in window) ||     (navigator.maxTouchPoints > 0) ||     (navigator.msMaxTouchPoints > 0)   ); }<\/code><\/pre>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0444\u043b\u0430\u0433\u0438 \u043d\u0430\u0447\u0430\u043b\u0430 \u0438 \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"javascript\">\/\/ define basic functions to detect click \/ release  function engage() {   dragging = true; };  function disengage() {   dragging = false; };<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u044b\u0448\u0438\/\u043f\u0440\u0438\u043a\u043e\u0441\u043d\u043e\u0432\u0435\u043d\u0438\u044f. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043b\u0438 \u0441\u0435\u043d\u0441\u043e\u0440\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"javascript\">\/\/ get the new position given a mouse \/ touch event function setPosition(e) {    if (isTouchDevice()) {   var touch = e.touches[0];   pos.x = touch.clientX - ctx.canvas.offsetLeft;   pos.y = touch.clientY - ctx.canvas.offsetTop;   } else {      pos.x = e.clientX - ctx.canvas.offsetLeft;   pos.y = e.clientY - ctx.canvas.offsetTop;   } }<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u0424\u043b\u0430\u0433 <code>draging<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u0440\u0438\u0441\u0443\u0435\u0442 \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441 (\u0441\u0442\u0440\u043e\u043a\u0430 8). \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u0442\u0430\u043a, \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u0438\u0437 <code>setPosition<\/code> \u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043b\u0438\u043d\u0438\u044f, \u044d\u0442\u043e \u0441\u0442\u0440\u043e\u043a\u0438 \u0441 18 \u043f\u043e 21:<\/p>\n<pre><code class=\"javascript\">\/\/ draws a line in a canvas if mouse is pressed function draw(e) {      e.preventDefault();   e.stopPropagation();    \/\/ to draw the user needs to be engaged (dragging = True)   if (dragging) {      \/\/ begin drawing     ctx.beginPath();        \/\/ attributes of the line     ctx.lineWidth = 40;     ctx.lineCap = 'round';     ctx.strokeStyle = 'red';      \/\/ get current position, move to new position, create line from current to new     ctx.moveTo(pos.x, pos.y);     setPosition(e);     ctx.lineTo(pos.x, pos.y);      \/\/ draw     ctx.stroke();   } }<\/code><\/pre>\n<p>\u041e\u0447\u0438\u0441\u0442\u043a\u0430 canvas:<\/p>\n<pre><code class=\"javascript\">\/\/ clear canvas function erase() {   ctx.clearRect(0, 0, canvas.width, canvas.height); }<\/code><\/pre>\n<p>\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c. \u041c\u0435\u0442\u043e\u0434 <code>tf.loadLayersModel<\/code> \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e URL \u0438\u043b\u0438 \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 (\u0441\u0442\u0440\u043e\u043a\u0430 5). \u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0438 \u043e\u043d\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0432\u0435\u0441\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u0447\u0442\u043e\u0431\u044b \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u043e\u0433\u0440\u0435\u0442\u044c \u0435\u0451 (\u0441\u0442\u0440\u043e\u043a\u0430 8):<\/p>\n<pre><code class=\"javascript\">\/\/ defines a TF model load function async function loadModel(){      \/\/ loads the model   model = await tf.loadLayersModel('tensorflow\/model.json');          \/\/ warm start the model. speeds up the first inference   model.predict(tf.zeros([1, 28, 28, 1]))      \/\/ return model   return model }<\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0446\u0438\u0444\u0440\u0435 \u0441 \u0445\u043e\u043b\u0441\u0442\u0430:<\/p>\n<pre><code class=\"javascript\">\/\/ gets an image tensor from a canvas function getData(){   return ctx.getImageData(0, 0, canvas.width, canvas.height); }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u044b\u0432\u043e\u0434\u043e\u0432 \u043c\u043e\u0434\u0435\u043b\u0438:<\/p>\n<ul>\n<li>\n<p><code>getData<\/code> \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0445\u043e\u043b\u0441\u0442\u0430 (\u0441\u0442\u0440\u043e\u043a\u0430 5). <\/p>\n<\/li>\n<li>\n<p><code>tf.browser.fromPixels<\/code> \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u0438\u0445 \u0432 \u0442\u0435\u043d\u0437\u043e\u0440 (\u0441\u0442\u0440\u043e\u043a\u0430 8).<\/p>\n<\/li>\n<li>\n<p><code>tf.image.resizeBilinear<\/code> \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0440 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438 (\u0441\u0442\u0440\u043e\u043a\u0430 11). <\/p>\n<\/li>\n<li>\n<p><code>model.predict<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 14, \u0430 \u0441\u0442\u0440\u043e\u043a\u0430 17 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0446\u0438\u0444\u0440\u0443 \u0438\u0437 \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430 <code>y.argMax(1)<\/code> \u0432 \u0442\u0435\u0433 <code>&lt;p id=\"result\"><\/code>.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"javascript\">\/\/ defines the model inference functino async function predictModel(){        \/\/ gets image data   imageData = getData();      \/\/ converts from a canvas data object to a tensor   image = tf.browser.fromPixels(imageData)      \/\/ pre-process image   image = tf.image.resizeBilinear(image, [28,28]).sum(2).expandDims(0).expandDims(-1)      \/\/ gets model prediction   y = model.predict(image);      \/\/ replaces the text in the result tag by the model prediction   document.getElementById('result').innerHTML = \"Prediction: \" + y.argMax(1).dataSync(); }<\/code><\/pre>\n<h3>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c<\/h3>\n<p>\u0420\u0430\u0434\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u044e\u0442 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u0442\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430, \u043e\u0442\u043a\u0443\u0434\u0430 \u043e\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u043e\u0441\u044c, \u0435\u0441\u043b\u0438 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 Cross-Origin Resource Sharing (<abbr title=\"\u0421\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c\u0438\">CORS<\/abbr>). \u0417\u0434\u0435\u0441\u044c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f Firefox.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c CORS \u0432 Firefox, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 <code>about:config<\/code> \u0432 \u043f\u043e\u0438\u0441\u043a\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 Firefox, \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432\u0432\u0435\u0434\u0438\u0442\u0435 <code>privacy.file_unique_origin<\/code> \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0430 <code>false<\/code>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0de\/664\/b96\/0de664b960cf535a2575d8c5ba26f924.png\" width=\"700\" height=\"100\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0de\/664\/b96\/0de664b960cf535a2575d8c5ba26f924.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 <code>index.html<\/code> \u0432 Firefox:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bfd\/a7d\/a3a\/bfda7da3af89889a13c96e9af6fffe8a.png\" width=\"584\" height=\"641\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bfd\/a7d\/a3a\/bfda7da3af89889a13c96e9af6fffe8a.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0440\u0438\u0441\u0443\u0435\u043c \u0446\u0438\u0444\u0440\u0443 \u0438 \u043d\u0430\u0436\u043c\u0451\u043c Predict:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/99c\/92f\/eec\/99c92feec16fe1862e2ac6511942c124.png\" width=\"586\" height=\"638\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/99c\/92f\/eec\/99c92feec16fe1862e2ac6511942c124.png\"\/><figcaption><\/figcaption><\/figure>\n<blockquote>\n<p>\u0414\u043b\u044f \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u0441\u0435\u0442\u0438 \u0430\u0432\u0442\u043e\u0440 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 Amazon S3, \u0430 \u0434\u043b\u044f \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Github Pages, \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0437\u0430\u0449\u0438\u0442\u0443 CORS \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432\u0441\u0451 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0435.<\/p>\n<\/blockquote>\n<h3>\u041c\u043e\u0434\u0435\u043b\u044c \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438<\/h3>\n<ul>\n<li>\n<p><a href=\"http:\/\/portfolio.dataisawesome.com\/projects\/digit_recognition\/index.html\">\u0414\u043b\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u0438 \u0434\u0435\u0441\u043a\u0442\u043e\u043f\u043e\u0432<\/a>.<\/p>\n<\/li>\n<li>\n<p><a href=\"http:\/\/portfolio.dataisawesome.com\/projects\/digit_recognition\/index_mobile.html\">\u0422\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445<\/a>.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/andreRibeiro1989\/medium\/tree\/main\/tensorflowjs\/digit_recognition\">Github<\/a>.<\/p>\n<\/li>\n<\/ul>\n<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043e\u0447\u0435\u043d\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0445, \u043d\u0435\u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0445 \u043d\u0435\u043f\u043e\u0441\u0432\u044f\u0449\u0451\u043d\u043d\u043e\u043c\u0443 \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445, \u043d\u043e \u0438 \u0432 \u0441\u0430\u043c\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u0430 \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043d\u043e\u0432\u044b\u043c \u044d\u043b\u0435\u043a\u0442\u0440\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c, \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0432\u0441\u0451 \u0431\u043e\u043b\u044c\u0448\u0435 \u043c\u0435\u0441\u0442\u0430 \u0432 \u0431\u044b\u0442\u0443. \u0415\u0441\u043b\u0438 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u0430\u0440\u044c\u0435\u0440\u0443 \u0438\u043b\u0438 \u043f\u0440\u043e\u043a\u0430\u0447\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043d\u0430\u0432\u044b\u043a\u0438 \u0432 ML, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u0438\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u043a\u0443\u0440\u0441\u0443 <a href=\"https:\/\/skillfactory.ru\/ml-and-dl?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_MLDL&amp;utm_term=regular&amp;utm_content=280721\">\u00abMachine Learning \u0438 Deep Learning\u00bb<\/a>, \u0430 \u0435\u0441\u043b\u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430, \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 <a href=\"https:\/\/skillfactory.ru\/frontend?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_FR&amp;utm_term=regular&amp;utm_content=280721\">\u043a\u0443\u0440\u0441 \u043f\u043e \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0443<\/a> \u0438\u043b\u0438 \u043f\u043e <a href=\"https:\/\/skillfactory.ru\/python-fullstack-web-developer?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_FPW&amp;utm_term=regular&amp;utm_content=280721\">Fullstack-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0430 Python<\/a>. \u0422\u0430\u043a\u0436\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 <a href=\"https:\/\/skillfactory.ru\/courses\/?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_ALLCOURSES&amp;utm_term=regular&amp;utm_content=280721\">\u0443\u0437\u043d\u0430\u0442\u044c<\/a>, \u043a\u0430\u043a \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043b\u0438 \u0432\u044b\u0439\u0442\u0438 \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/901\/335\/eff\/901335eff3df888dae395b63e28b6e95.png\" width=\"1000\" height=\"200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/901\/335\/eff\/901335eff3df888dae395b63e28b6e95.png\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>Machine Learning, Data Science \u0438 Python<\/strong><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/ml-and-dl?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_MLDL&amp;utm_term=regular&amp;utm_content=280721\">\u041a\u0443\u0440\u0441 \u00abMachine Learning \u0438 Deep Learning\u00bb<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/ml-programma-machine-learning-online?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_ML&amp;utm_term=regular&amp;utm_content=280721\">\u041a\u0443\u0440\u0441 \u043f\u043e Machine Learning<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/dstpro?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_DSPR&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f Data Scientist<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/dataanalystpro?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_DAPR&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f Data Analyst<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/python-fullstack-web-developer?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_FPW&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f Fullstack-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430 Python<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/math-stat-for-ds#syllabus?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_MAT&amp;utm_term=regular&amp;utm_content=280721\">\u041a\u0443\u0440\u0441 \u00ab\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0430 \u0434\u043b\u044f Data Science\u00bb<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/math_and_ml?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_MATML&amp;utm_term=regular&amp;utm_content=280721\">\u041a\u0443\u0440\u0441 \u00ab\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0430 \u0438 Machine Learning \u0434\u043b\u044f Data Science\u00bb<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/dataengineer?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_DEA&amp;utm_term=regular&amp;utm_content=280721\">\u041a\u0443\u0440\u0441 \u043f\u043e Data Engineering<\/a><\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0412\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/strong><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/python-for-web-developers?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_PWS&amp;utm_term=regular&amp;utm_content=280721\">\u041a\u0443\u0440\u0441 \u00abPython \u0434\u043b\u044f \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438\u00bb<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/frontend?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_FR&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f Frontend-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/webdev?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_WEBDEV&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f \u0412\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/a><\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041c\u043e\u0431\u0438\u043b\u044c\u043d\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/strong><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/iosdev?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_IOSDEV&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f iOS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/android?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_ANDR&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/a><\/p>\n<\/li>\n<\/ul>\n<p><strong>Java \u0438 C#<\/strong><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/java?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_JAVA&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f Java-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/java-qa-engineer?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_QAJA&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440 \u043d\u0430 JAVA<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/csharp?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_CDEV&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f C#-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/game-dev?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_GAMEDEV&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438\u0433\u0440 \u043d\u0430 Unity<\/a><\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041e\u0442 \u043e\u0441\u043d\u043e\u0432 \u2014 \u0432 \u0433\u043b\u0443\u0431\u0438\u043d\u0443<\/strong><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/algo?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_algo&amp;utm_term=regular&amp;utm_content=280721\">\u041a\u0443\u0440\u0441 \u00ab\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445\u00bb<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/cplus?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_CPLUS&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f C++ \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/cybersecurity?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_HACKER&amp;utm_term=regular&amp;utm_content=280721\">\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f \u042d\u0442\u0438\u0447\u043d\u044b\u0439 \u0445\u0430\u043a\u0435\u0440<\/a><\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0410 \u0442\u0430\u043a\u0436\u0435:<\/strong><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/skillfactory.ru\/devops?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_DEVOPS&amp;utm_term=regular&amp;utm_content=280721\">\u041a\u0443\u0440\u0441 \u043f\u043e DevOps<\/a><\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/570096\/\"> https:\/\/habr.com\/ru\/articles\/570096\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u043b\u044f \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432 \u0438 \u043d\u0435 \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442 \u043d\u0430 \u0432\u044b\u0441\u043e\u043a\u0438\u0439 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u0430 \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 <a href=\"https:\/\/habr.com\/ru\/company\/skillfactory\/blog\/564896\/\">\u0441\u0442\u0430\u0442\u044c\u044e \u043e GIRAFFE<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0435\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0441\u0430\u043c\u044b\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0432 \u0418\u0418.<\/p>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u044b \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0441 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0443\u043a\u043e\u043f\u0438\u0441\u043d\u043e\u0433\u043e \u0432\u0432\u043e\u0434\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0418\u0418, \u0430 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0432 \u044d\u0442\u043e \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e, \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u043e\u043c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0434\u0435\u043b\u0438\u043c\u0441\u044f \u043a \u0441\u0442\u0430\u0440\u0442\u0443 \u043a\u0443\u0440\u0441\u0430 \u043e <a href=\"https:\/\/skillfactory.ru\/ml-and-dl?utm_source=infopartners&amp;utm_medium=habr&amp;utm_campaign=habr_MLDL&amp;utm_term=regular&amp;utm_content=280721\">\u043c\u0430\u0448\u0438\u043d\u043d\u043e\u043c \u0438 \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u043c \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0438<\/a>, \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u0432\u043e\u0439 \u0431\u043b\u043e\u043a\u043d\u043e\u0442 Colab \u0438\u043b\u0438 \u0431\u043b\u043e\u043a\u043d\u043e\u0442 \u0430\u0432\u0442\u043e\u0440\u0430 \u0441\u0442\u0430\u0442\u044c\u0438. \u0421\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u044b \u043c\u043e\u0434\u0435\u043b\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442 \u043c\u0435\u043d\u044c\u0448\u0435 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u0430.<\/p>\n<hr\/>\n<h2>\u041e\u0431\u0443\u0447\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0446\u0438\u0444\u0440 \u043d\u0430 \u043d\u0430\u0431\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 MNIST<\/h2>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u0431\u043b\u043e\u043a\u043d\u043e\u0442 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0432\u0441\u0451 \u0441 \u043d\u0443\u043b\u044f, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443 \u0412\u0430\u0448\u0435\u0433\u043e \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"python\">import tensorflow as tf  # import digit dataset mnist = tf.keras.datasets.mnist (tx, ty), (vx, vy) = mnist.load_data()  # preprocess input types tx = tx[:,:,:,None].astype('float32') vx = vx[:,:,:,None].astype('float32') ty = ty.astype(int) vy = vy.astype(int)  # display relevant info print(\"\"\"tx:%s, ty:%s vx:%s, vy:%s\"\"\" % (tx.shape, ty.shape, vx.shape, vy.shape))<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0440\u043d\u043e\u0441\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 <code>tx<\/code> \u0438 \u0446\u0435\u043b\u0438 <code>ty<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 <code>vx<\/code> \u0438 \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 <code>vy<\/code>:<\/p>\n<pre><code class=\"python\">tx:(60000, 28, 28, 1), ty:(60000,)  vx:(10000, 28, 28, 1), vy:(10000,)<\/code><\/pre>\n<p>\u0412\u044b\u0432\u0435\u0434\u0435\u043c 10 \u043e\u0431\u0440\u0430\u0437\u0446\u043e\u0432 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043a\u0430\u0436\u0434\u043e\u0439 \u0446\u0438\u0444\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0434\u0430\u043d\u043d\u044b\u0435:<\/p>\n<pre><code class=\"python\">import matplotlib.pyplot as plt  # create a grid of plots f, axs = plt.subplots(10,10,figsize=(10,10))  # plot a sample number into each subplot for i in range(10):   for j in range(10):     # get a sample image for the 'i' number     img = tx[ty==i,:,:,0][j,:,:]      # plot image in axes     axs[i,j].imshow(img, cmap='gray')      # remove x and y axis     axs[i,j].axis('off')  # remove unecessary white space plt.tight_layout()  # display image plt.show()<\/code><\/pre>\n<p>\u00a0\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0447\u0451\u0440\u043d\u044b\u0439 \u0444\u043e\u043d \u0438 \u0431\u0435\u043b\u044b\u0435 \u0446\u0438\u0444\u0440\u044b. \u042d\u0442\u043e \u0432\u0430\u0436\u043d\u043e \u0432 \u0441\u043c\u044b\u0441\u043b\u0435 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0447\u0438\u0441\u0435\u043b \u0438 \u043a\u043e\u0434\u0430 canvas \u0432 HTML:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430 \u0441\u0432\u0451\u0440\u0442\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0440\u043e\u043c\u0435 \u0441\u0430\u043c\u043e\u0439 \u0441\u0432\u0451\u0440\u0442\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442\u043d\u0443\u044e \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 RELU, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u043e\u0442\u0441\u0435\u0438\u0432\u0430\u044e\u0449\u0438\u0435 \u0441\u043b\u043e\u0438:<\/p>\n<pre><code class=\"python\"># defines a standard 2d convolution block with batch normalisation,  # relu activation, max pooling and dropout  def normConvBlock(filters, return_model=True, name=None):   lays = [     tf.keras.layers.Conv2D(filters, 3, padding='valid', name=name+'_conv'),     tf.keras.layers.BatchNormalization(name=name+'_bn'),     tf.keras.layers.Activation('relu', name=name+'_act'),     tf.keras.layers.MaxPooling2D(2, strides=2, name=name+'_mpool'),     tf.keras.layers.Dropout(0.1, name=name+'_drop'),   ]    if return_model:     return tf.keras.models.Sequential(lays, name=name)   else:     return lays<\/code><\/pre>\n<p>\u041d\u0430\u0448\u0430 \u043f\u043e\u043b\u043d\u0430\u044f \u0441\u0435\u0442\u044c \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u0434\u0432\u0443\u0445 <code>normConvBlock<\/code>, \u0437\u0430\u0442\u0435\u043c \u043f\u043b\u043e\u0441\u043a\u043e\u0433\u043e \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u043b\u043e\u0442\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f \u0441 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0435\u0439 softmax. \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>Adam<\/code> . \u0412 \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0435\u0441\u0442\u044c \u043c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u043e\u0440\u044f\u0434\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0430\u043a\u0436\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0442\u0435\u0440\u0435\u0439 \u043f\u0435\u0440\u0435\u043a\u0440\u0451\u0441\u0442\u043d\u043e\u0439 \u044d\u043d\u0442\u0440\u043e\u043f\u0438\u0438:<\/p>\n<pre><code class=\"python\"># create NN model model = tf.keras.models.Sequential() model.add(normConvBlock(64, name='b1')) model.add(normConvBlock(128, name='b2')) model.add(tf.keras.layers.Flatten(name='flat')) model.add(tf.keras.layers.Dense(10, activation='softmax', name='logit'))  # compile model with adam optimizer and crossentropy loss # note that 'sparse_categorical_crossentropy' loss should be used as our target # is encoded as ordinal. if using one hot change this to 'categorical_crossentropy' model.compile('adam', 'sparse_categorical_crossentropy', metrics=['acc'])  # test model with a sample image _ = model(tx[:1,:,:,:])  # summary of model structure tf.keras.utils.plot_model(     model,      show_shapes=True,      show_layer_names=True,      show_dtype=True,     expand_nested=True,     dpi = 50 )<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0432\u044b\u0448\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043c\u043e\u0434\u0435\u043b\u0438:<\/p>\n<figure class=\"\"><figcaption>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0441\u043b\u043e\u0451\u0432 normConvBlock (b1 \u0438 b2), \u0437\u0430 \u043d\u0438\u043c\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0442 \u043f\u043b\u043e\u0441\u043a\u0438\u0439 \u0438 \u043f\u043b\u043e\u0442\u043d\u044b\u0439 \u0441\u043b\u043e\u0438<\/figcaption><\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u043e\u0431\u0443\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c, \u0432\u044b\u0437\u043e\u0432\u0435\u043c <code>model.fit<\/code> \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u043c\u0438 \u0432\u044b\u0448\u0435 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u0440\u0430\u043d\u043d\u0435\u0439 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"python\"># define an early stopping callback. This callback will load the iteration with # the best val loss at the end of training es_call = tf.keras.callbacks.EarlyStopping(     monitor='val_loss', min_delta=0, patience=2, verbose=0,     mode='auto', baseline=None, restore_best_weights=True )  # fit the model with the mnist dataset history = model.fit(tx, ty, validation_data=(vx, vy), epochs=20, batch_size=1024, callbacks=[es_call])<\/code><\/pre>\n<p>\u0422\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 (~99 % \u0432 \u043d\u0430\u0431\u043e\u0440\u0435 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438). \u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c \u0442\u043e\u0447\u043d\u0435\u0435, \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0435\u0451 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438\u043b\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043d\u0430\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u043c\u0438:<\/p>\n<pre><code>Epoch 11\/20 59\/59 [==============================] - 3s 50ms\/step - loss: 0.0317 - acc: 0.9906 - val_loss: 0.0338 - val_acc: 0.9899 Epoch 12\/20 59\/59 [==============================] - 3s 50ms\/step - loss: 0.0292 - acc: 0.9913 - val_loss: 0.0496 - val_acc: 0.9823 Epoch 13\/20 59\/59 [==============================] - 3s 50ms\/step - loss: 0.0275 - acc: 0.9918 - val_loss: 0.0422 - val_acc: 0.9866<\/code><\/pre>\n<h3>\u0412\u0435\u0441\u044c \u043a\u043e\u0434<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/andreRibeiro1989\/medium\/tree\/main\/tensorflowjs\/digit_recognition\">Github<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/colab.research.google.com\/github\/andreRibeiro1989\/medium\/blob\/main\/tensorflowjs\/digit_recognition\/tensorflow_js_training.ipynb\">Colab<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>TensorFlow.js<\/h2>\n<p>\u0414\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043c\u043e\u0434\u0435\u043b\u044c\u044e TensorFlow.js \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 HTML \u0438 JavaScript. TensorFlow.js \u2014 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u0434\u043b\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 ML \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 JavaScript \u0438 \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u0433\u043e API.<\/p>\n<h3>\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c TensorFlow \u0432 TensorFlow.js<\/h3>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0433 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438 TensorFlow \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u2014 \u0435\u0451 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043c\u043e\u0434\u0435\u043b\u044c TensorFlow.js, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>tensorflowjs.converters.save_keras_model<\/code> \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>tensorflowjs<\/code>.<\/p>\n<pre><code class=\"python\"># install \/ update the tensorflowjs package !pip install tensorflowjs > \/dev\/null 2>&amp;1  import tensorflowjs print(tensorflowjs.__version__)  # convert keras model to tensorflow js tensorflowjs.converters.save_keras_model(model, '.\/mnist_tf_keras_js_model\/')<\/code><\/pre>\n<blockquote>\n<p>\u041f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0432 Colab \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0444\u0430\u0439\u043b\u044b \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443, \u043e\u043d\u0438 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f.<\/p>\n<\/blockquote>\n<pre><code class=\"python\"># download generated files from colab to local  from google.colab import files  files.download(\"mnist_tf_keras_js_model\/group1-shard1of1.bin\") files.download(\"mnist_tf_keras_js_model\/model.json\")<\/code><\/pre>\n<h3>\u041f\u0438\u0448\u0435\u043c \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/h3>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u043f\u0430\u043f\u043a\u0435 <code>digit_recognition<\/code> \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 \u0441 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 <code>index.html<\/code> \u0438 <code>script.js<\/code>. \u0412\u043d\u0443\u0442\u0440\u0438 <code>digit_recognition<\/code> \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 <code>tensorflow<\/code>. \u0421\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 \u0438\u0437 \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u0430 Colab, <code>group1-shard1of1.bin<\/code> \u0438 <code>model.json<\/code> , \u0432 \u043d\u043e\u0432\u0443\u044e \u043f\u0430\u043f\u043a\u0443, \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code>- digit_recognition\/   - index.html   - script.js   - tensorflow\/     - group1-shard1of1.bin     - model.json<\/code><\/pre>\n<p>\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 <code>index.html<\/code> \u043b\u044e\u0431\u044b\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u043e\u043c \u043a\u043e\u0434\u0430 \u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0432 \u043d\u0435\u0433\u043e \u043a\u043e\u0434 \u043d\u0438\u0436\u0435. \u042d\u0442\u043e\u0442 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0446\u0438\u0444\u0440\u044b:<\/p>\n<pre><code>&lt;html>      &lt;head>          &lt;!-- Imports TensorFlow.js -->     &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@tensorflow\/tfjs@3.7.0\"> &lt;\/script>      &lt;!-- Imports tfjs-vis -->     &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@tensorflow\/tfjs-vis@1.5.1\/dist\/tfjs-vis.umd.min.js\">&lt;\/script>        &lt;\/head>      &lt;body>          &lt;!-- Defines the container with the predictand erase buttons, and the canvas to draw a digit -->     &lt;div id=\"container\">              &lt;h1>Draw a number&lt;\/h1>       &lt;p id=\"result\">Prediction &lt;\/p>              &lt;div>         &lt;!-- This button tells the model to return a prediction for the current canvas -->         &lt;button type=\"button\" onclick=\"predictModel()\">Predict&lt;\/button>                  &lt;!-- This button clears the canvas so that we can draw a new digit -->         &lt;button type=\"button\" onclick=\"erase()\">Clear&lt;\/button>       &lt;\/div>              &lt;!-- This defines the canvas on which we can draw a digit.             If the canvas is too small increase the width and height -->       &lt;canvas id=\"canvas\" width=\"386px\" height=\"386px\" style=\"border:1px solid #b9bfc9;margin-top:25px;\">&lt;\/canvas>     &lt;\/div>      &lt;!-- Imports the main script file -->     &lt;script src=\"script.js\">&lt;\/script>        &lt;\/body>    &lt;\/html><\/code><\/pre>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043a\u043e\u0434:<\/p>\n<ul>\n<li>\n<p>\u0412 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <code>&lt;head><\/code> \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f TensorFlow.js \u0438 \u0435\u0451 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 23 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043a\u043d\u043e\u043f\u043a\u0443 \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u044b\u0432\u043e\u0434\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 <code>predictModel<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0432 \u0442\u0435\u0433\u0435 <code>&lt;p id=\"result\"><\/code> .<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 26 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0445\u043e\u043b\u0441\u0442\u0430 <code>erase<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 31 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>canvas<\/code>, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0446\u0438\u0444\u0440\u0443 \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0442\u0440\u043e\u043a\u0435 35 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0444\u0430\u0439\u043b script.js \u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 JavaScript, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442 \u0446\u0438\u0444\u0440\u0443 \u0441 \u0445\u043e\u043b\u0441\u0442\u0430 \u0432 \u0442\u0435\u043d\u0437\u043e\u0440 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u043c\u043e\u0434\u0435\u043b\u044c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>script.js<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u043d\u0438\u0436\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u0434\u0430.\u00a0<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430:<\/p>\n<pre><code class=\"javascript\">\/\/ define relevant variables var canvas = document.getElementById(\"canvas\"); var ctx = canvas.getContext('2d'); var dragging = false; var pos = { x: 0, y: 0 };<\/code><\/pre>\n<p>\u0422\u0440\u0438\u0433\u0433\u0435\u0440\u044b \u0445\u043e\u043b\u0441\u0442\u0430:<\/p>\n<ul>\n<li>\n<p>\u041f\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044e <code>mousedown<\/code> (\u043d\u0430\u0436\u0430\u0442\u0438\u044e \u0438 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u043a\u043d\u043e\u043f\u043a\u0438) \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u044b\u0448\u0438\/\u043f\u0440\u0438\u043a\u043e\u0441\u043d\u043e\u0432\u0435\u043d\u0438\u044f. <\/p>\n<\/li>\n<li>\n<p>\u041f\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044e <code>mousemove<\/code> \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0445\u043e\u043b\u0441\u0442\u0435. \u041f\u043e <code>mouseup<\/code> (\u043a\u043e\u0433\u0434\u0430 \u043e\u0442\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u043d\u043e\u043f\u043a\u0438 \u043c\u044b\u0448\u0438) \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0449\u0438\u0439 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"javascript\">\/\/ define event listeners for both desktop and mobile  \/\/ nontouch canvas.addEventListener('mousedown',  engage); canvas.addEventListener('mousedown',  setPosition); canvas.addEventListener('mousemove',  draw); canvas.addEventListener('mouseup', disengage);  \/\/ touch canvas.addEventListener('touchstart', engage); canvas.addEventListener('touchmove', setPosition); canvas.addEventListener('touchmove', draw); canvas.addEventListener('touchend', disengage);<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432 <code>setPosition<\/code>, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u0433\u043e, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c \u0441\u0435\u043d\u0441\u043e\u0440\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"javascript\">\/\/ detect if it is a touch device function isTouchDevice() {   return (     ('ontouchstart' in window) ||     (navigator.maxTouchPoints > 0) ||     (navigator.msMaxTouchPoints > 0)   ); }<\/code><\/pre>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0444\u043b\u0430\u0433\u0438 \u043d\u0430\u0447\u0430\u043b\u0430 \u0438 \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"javascript\">\/\/ define basic functions to detect click \/ release  function engage() {   dragging = true; };  function disengage() {   dragging = false; };<\/code><\/pre>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-395944","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/395944","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=395944"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/395944\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=395944"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=395944"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=395944"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}