commit 9be1dab6f3f99c5f68a13e7d791775076ac968af Author: artem Date: Thu Apr 27 12:53:21 2023 +0300 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf2cb32 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +assets/* +*.jpg +beerds.json \ No newline at end of file diff --git a/beerd_25_04_2023.keras b/beerd_25_04_2023.keras new file mode 100644 index 0000000..4f08ca5 Binary files /dev/null and b/beerd_25_04_2023.keras differ diff --git a/beerd_imagenet_25_04_2023.keras b/beerd_imagenet_25_04_2023.keras new file mode 100644 index 0000000..c1d98e6 Binary files /dev/null and b/beerd_imagenet_25_04_2023.keras differ diff --git a/beerds.py b/beerds.py new file mode 100644 index 0000000..e4b93b8 --- /dev/null +++ b/beerds.py @@ -0,0 +1,107 @@ + +import os +import random + +import matplotlib.pyplot as plt +import numpy as np +import tensorflow as tf +from tensorflow import keras +from tensorflow.keras import layers +from tensorflow.keras.utils import image_dataset_from_directory, split_dataset + + +img_size = (200, 200) + + +# обогащение выборки +data_augmentation = keras.Sequential( +[ + layers.RandomFlip("horizontal"), + layers.RandomRotation(0.1), + layers.RandomZoom(0.2), +] +) + + + +input_dir = "assets/dog" + +labels_dict = {} +for fname in os.listdir(input_dir): + if fname in labels_dict: + continue + labels_dict[fname] = len(labels_dict) + +model_name = "beerd_25_04_2023.keras" +train_dataset, val_ds = image_dataset_from_directory( + input_dir, + labels="inferred", + label_mode="categorical", + class_names=None, + color_mode="rgb", + batch_size=32, + seed=12, + image_size=img_size, + shuffle=True, + validation_split=0.1, + subset="both", + interpolation="bilinear", + follow_links=False, + crop_to_aspect_ratio=False +) + +validation_dataset, test_dataset = split_dataset(val_ds, left_size=0.8) + +inputs = keras.Input(shape=img_size + (3,)) +x = data_augmentation(inputs) +x = layers.Rescaling(1./255)(x) +x = layers.Conv2D(filters=32, kernel_size=5, use_bias=False)(x) +for size in [32, 64, 128, 256, 512, 1024]: + residual = x + x = layers.BatchNormalization()(x) + x = layers.Activation("relu")(x) + x = layers.SeparableConv2D(size, 3, padding="same", use_bias=False)(x) + x = layers.BatchNormalization()(x) + x = layers.Activation("relu")(x) + x = layers.SeparableConv2D(size, 3, padding="same", use_bias=False)(x) + x = layers.MaxPooling2D(3, strides=2, padding="same")(x) + residual = layers.Conv2D( + size, 1, strides=2, padding="same", use_bias=False)(residual) + x = layers.add([x, residual]) + +x = layers.GlobalAveragePooling2D()(x) +x = layers.Dropout(0.5)(x) +outputs = layers.Dense(len(labels_dict), activation="softmax")(x) +model = keras.Model(inputs, outputs) + +model.compile(optimizer="rmsprop", + loss="categorical_crossentropy", metrics=['accuracy']) +callbacks = [ + keras.callbacks.ModelCheckpoint(model_name, + save_best_only=True) +] +history = model.fit(train_dataset, + epochs=200, + callbacks=callbacks, + validation_data=validation_dataset,) + +epochs = range(1, len(history.history["loss"]) + 1) +loss = history.history["loss"] +val_loss = history.history["val_loss"] +acc = history.history["accuracy"] +val_acc = history.history["val_accuracy"] +plt.plot(epochs, acc, "bo", label="Точность на этапе обучения") +plt.plot(epochs, val_acc, "b", label="Точность на этапе проверки") +plt.title("Точность на этапах обучения и проверки") +plt.legend() +plt.figure() +plt.plot(epochs, loss, "bo", label="Потери на этапе обучения") +plt.plot(epochs, val_loss, "b", label="Потери на этапе проверки") +plt.title("Потери на этапах обучения и проверки") +plt.legend() +plt.show() + + +test_model = keras.models.load_model(model_name) +test_loss, test_acc = test_model.evaluate(test_dataset) +print(f"Test accuracy: {test_acc:.3f}") \ No newline at end of file diff --git a/beerds_imagenet.py b/beerds_imagenet.py new file mode 100644 index 0000000..4286df9 --- /dev/null +++ b/beerds_imagenet.py @@ -0,0 +1,100 @@ + +import os +import random + +import matplotlib.pyplot as plt +import numpy as np +import tensorflow as tf +from tensorflow import keras +from tensorflow.keras import layers +from tensorflow.keras.utils import image_dataset_from_directory, split_dataset + + +img_size = (180, 180) + +conv_base = keras.applications.vgg16.VGG16( + weights="imagenet", + include_top=False, + input_shape=(180, 180, 3)) +conv_base.trainable = False + + +# обогащение выборки +data_augmentation = keras.Sequential( +[ + layers.RandomFlip("horizontal"), + layers.RandomRotation(0.1), + layers.RandomZoom(0.2), +]) + + + +input_dir = "assets/dog" + +labels_dict = {} +for fname in os.listdir(input_dir): + if fname in labels_dict: + continue + labels_dict[fname] = len(labels_dict) + +model_name = "beerd_imagenet_25_04_2023.keras" +train_dataset, val_ds = image_dataset_from_directory( + input_dir, + labels="inferred", + label_mode="categorical", + class_names=None, + color_mode="rgb", + batch_size=32, + seed=12, + image_size=img_size, + shuffle=True, + validation_split=0.1, + subset="both", + interpolation="bilinear", + follow_links=False, + crop_to_aspect_ratio=False +) + +validation_dataset, test_dataset = split_dataset(val_ds, left_size=0.8) + +inputs = keras.Input(shape=(180, 180, 3)) +x = data_augmentation(inputs) +x = keras.applications.vgg16.preprocess_input(x) +x = conv_base(x) +x = layers.Flatten()(x) +x = layers.Dense(512)(x) +x = layers.Dropout(0.5)(x) +outputs = layers.Dense(len(labels_dict), activation="softmax")(x) +model = keras.Model(inputs, outputs) + +model.compile(optimizer="rmsprop", + loss="categorical_crossentropy", metrics=['accuracy']) +callbacks = [ + keras.callbacks.ModelCheckpoint(model_name, + save_best_only=True) +] +history = model.fit(train_dataset, + epochs=100, + callbacks=callbacks, + validation_data=validation_dataset,) + +epochs = range(1, len(history.history["loss"]) + 1) +loss = history.history["loss"] +val_loss = history.history["val_loss"] +acc = history.history["accuracy"] +val_acc = history.history["val_accuracy"] +plt.plot(epochs, acc, "bo", label="Точность на этапе обучения") +plt.plot(epochs, val_acc, "b", label="Точность на этапе проверки") +plt.title("Точность на этапах обучения и проверки") +plt.legend() +plt.figure() +plt.plot(epochs, loss, "bo", label="Потери на этапе обучения") +plt.plot(epochs, val_loss, "b", label="Потери на этапе проверки") +plt.title("Потери на этапах обучения и проверки") +plt.legend() +plt.show() + + +test_model = keras.models.load_model(model_name) +test_loss, test_acc = test_model.evaluate(test_dataset) +print(f"Test accuracy: {test_acc:.3f}") \ No newline at end of file diff --git a/beerds_val.py b/beerds_val.py new file mode 100644 index 0000000..5910e38 --- /dev/null +++ b/beerds_val.py @@ -0,0 +1,44 @@ + +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '-1' +import json +import matplotlib.pyplot as plt +import numpy as np +import tensorflow as tf +from tensorflow import keras +from tensorflow.keras import layers +from tensorflow.keras.utils import load_img, img_to_array +from tensorflow.keras.utils import image_dataset_from_directory + + +# model_name = "beerd_25_04_2023.keras" +model_name = "beerd_imagenet_25_04_2023.keras" +img = load_img("photo_2023-04-25_10-02-25.jpg", color_mode="rgb") +img = tf.image.resize(img, (180, 180, ), "bilinear") +img_array = img_to_array(img) + +test_model = keras.models.load_model(model_name) +test_loss = test_model.predict(np.expand_dims(img_array, 0)) + + +list_labels = [fname for fname in os.listdir("assets/dog")] +list_labels.sort() +dict_names = {} +for i, label in enumerate(list_labels): + dict_names[i] = label + +with open("beerds.json", "w") as f: + f.write(json.dumps(dict_names)) + +max_val = 0 +max_num = 0 +for i, val in enumerate(test_loss[0]): + if val < max_val: + continue + max_val = val + max_num = i + +print("-----------------------") +print(list_labels) +print(test_loss) +print(max_num, max_val, dict_names[max_num]) \ No newline at end of file diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000..5e6cc9e --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.10 + +COPY requirements.txt /app/requirements.txt +WORKDIR /app + +RUN pip3 install --upgrade pip +RUN pip3 install -r requirements.txt + +COPY . /app/ +EXPOSE 4150 +WORKDIR /app/external_api + +ENTRYPOINT ["python", "main.py"] + diff --git a/server/index.html b/server/index.html new file mode 100644 index 0000000..4a52d7c --- /dev/null +++ b/server/index.html @@ -0,0 +1,17 @@ + + + + + Определение породы собаки по фото + + +
+

+

+
+
+ + + + + diff --git a/server/main.py b/server/main.py new file mode 100644 index 0000000..51276b0 --- /dev/null +++ b/server/main.py @@ -0,0 +1,65 @@ + + +from PIL import Image +from sanic import Sanic +from sanic.response import json as json_answer +import numpy as np +from tensorflow import keras +from tensorflow.keras.utils import img_to_array +import io +import os +import json +os.environ['CUDA_VISIBLE_DEVICES'] = '-1' + + +app = Sanic("Ai") +model_name = "../beerd_imagenet_25_04_2023.keras" +test_model_imagenet = keras.models.load_model(model_name) + +model_name = "../beerd_25_04_2023.keras" +test_model = keras.models.load_model(model_name) + +list_labels = [fname for fname in os.listdir("../assets/dog")] +list_labels.sort() +dict_names = {} +with open("beerds.json", "r") as f: + dict_names = json.loads(f.read()) +app.static("/", "index.html", name="main") +app.static("/static/", "static/", name="static") + + +@app.post("/beeds") +async def beeds(request): + body = request.files.get("f").body + + img = Image.open(io.BytesIO(body)) + img = img.convert('RGB') + + img_net = img.resize((180, 180, ), Image.BILINEAR) + img_array = img_to_array(img_net) + test_loss_image_net = test_model_imagenet.predict( + np.expand_dims(img_array, 0)) + + img = img.resize((200, 200, ), Image.BILINEAR) + img_array = img_to_array(img) + test_loss = test_model.predict(np.expand_dims(img_array, 0)) + + result = {} + for i, val in enumerate(test_loss[0]): + if val <= 0.09: + continue + result[val] = dict_names[str(i)] + + result_net = {} + for i, val in enumerate(test_loss_image_net[0]): + if val <= 0.09: + continue + result_net[val] = dict_names[str(i)] + + return json_answer({ + "results": dict(sorted(result.items(), reverse=True)), + "results_net": dict(sorted(result_net.items(), reverse=True)), + }) + +if __name__ == "__main__": + app.run(auto_reload=True) diff --git a/server/requirements.txt b/server/requirements.txt new file mode 100644 index 0000000..0a497be --- /dev/null +++ b/server/requirements.txt @@ -0,0 +1,10 @@ + +keras==2.12.0 +matplotlib==3.7.1 +numpy==1.23.5 +pandas==2.0.0 +Pillow==9.4.0 +sanic==23.3.0 +scipy==1.10.1 +tensorflow==2.12.0 +ujson==5.7.0 diff --git a/server/static/scripts.js b/server/static/scripts.js new file mode 100644 index 0000000..d631148 --- /dev/null +++ b/server/static/scripts.js @@ -0,0 +1,24 @@ +async function SavePhoto() +{ + let photo = document.getElementById("file-input").files[0]; + let formData = new FormData(); + + formData.append("f", photo); + let response = await fetch('/beeds', {method: "POST", body: formData}); + if (response.ok) { + let json = await response.json(); + var text = "" + for (let key in json.results_net) { + text += "
" + json.results_net[key] + ": " + key + "
" + } + for (let key in json.results) { + text += "
" + json.results[key] + ": " + key + "
" + } + document.getElementById("result").innerHTML = text; + let urlCreator = window.URL || window.webkitURL; + let imageUrl = urlCreator.createObjectURL(photo); + document.getElementById("image").src = imageUrl; + } else { + alert("Ошибка HTTP: " + response.status); + } +} \ No newline at end of file