mobile + new models
Gitea Actions Demo / build_and_push (push) Successful in 23s
Details
Gitea Actions Demo / build_and_push (push) Successful in 23s
Details
This commit is contained in:
parent
1ac9bc2ecb
commit
60e194b2c9
|
|
@ -0,0 +1 @@
|
||||||
|
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
@ -24,7 +24,7 @@ jobs:
|
||||||
tags: gitea.webart-tech.ru/webart/beerds/backend:${{ gitea.sha }}
|
tags: gitea.webart-tech.ru/webart/beerds/backend:${{ gitea.sha }}
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
run: |
|
run: |
|
||||||
git clone https://gitea.webart-tech.ru/webart/kuber-deploy.git deploy
|
git clone https://${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}@gitea.webart-tech.ru/webart/kuber-deploy.git deploy
|
||||||
cd ./deploy/ai
|
cd ./deploy/ai
|
||||||
sed -i -E 's/backend:.+/backend:${{ gitea.sha }}/g' dogs.yml
|
sed -i -E 's/backend:.+/backend:${{ gitea.sha }}/g' dogs.yml
|
||||||
git config --global user.email "deploy@deploy.deploy"
|
git config --global user.email "deploy@deploy.deploy"
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ from train import get_labels, load_model, get_loaders, train, show, DEVICE # ty
|
||||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
|
|
||||||
print(f"Using device: {DEVICE}")
|
print(f"Using device: {DEVICE}")
|
||||||
IMG_SIZE = (180, 180)
|
IMG_SIZE = (224, 224)
|
||||||
INPUT_DIR = "assets/cat"
|
INPUT_DIR = "assets/cat"
|
||||||
NUM_EPOCHS = 10
|
NUM_EPOCHS = 50
|
||||||
MODEL_NAME = "cats_model.pth"
|
MODEL_NAME = "cats_model.pth"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ from train import get_labels, load_model, get_loaders, train, show, DEVICE # ty
|
||||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
|
|
||||||
print(f"Using device: {DEVICE}")
|
print(f"Using device: {DEVICE}")
|
||||||
IMG_SIZE = (180, 180)
|
IMG_SIZE = (224, 224)
|
||||||
INPUT_DIR = "assets/dog"
|
INPUT_DIR = "assets/dog"
|
||||||
NUM_EPOCHS = 100
|
NUM_EPOCHS = 50
|
||||||
MODEL_NAME = "dogs_model.pth"
|
MODEL_NAME = "dogs_model.pth"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
10
ml/train.py
10
ml/train.py
|
|
@ -17,8 +17,9 @@ def get_labels(input_dir, img_size):
|
||||||
transform = transforms.Compose(
|
transform = transforms.Compose(
|
||||||
[
|
[
|
||||||
transforms.Resize(img_size),
|
transforms.Resize(img_size),
|
||||||
|
transforms.RandomHorizontalFlip(),
|
||||||
transforms.ToTensor(),
|
transforms.ToTensor(),
|
||||||
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
|
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
dataset = ImageFolder(root=input_dir, transform=transform)
|
dataset = ImageFolder(root=input_dir, transform=transform)
|
||||||
|
|
@ -44,7 +45,10 @@ def load_model(model_path: str, labels_dict: dict, device: str = "cuda") -> nn.M
|
||||||
if not os.path.isfile(model_path):
|
if not os.path.isfile(model_path):
|
||||||
print("Start new model")
|
print("Start new model")
|
||||||
model = torchvision.models.resnet50(weights=ResNet50_Weights.DEFAULT)
|
model = torchvision.models.resnet50(weights=ResNet50_Weights.DEFAULT)
|
||||||
model.fc = torch.nn.Linear(model.fc.in_features, len(labels_dict))
|
model.fc = nn.Sequential(
|
||||||
|
nn.Dropout(0.5), # Регуляризация
|
||||||
|
torch.nn.Linear(model.fc.in_features, len(labels_dict))
|
||||||
|
)
|
||||||
return model
|
return model
|
||||||
model = torch.load(model_path, map_location=device, weights_only=False)
|
model = torch.load(model_path, map_location=device, weights_only=False)
|
||||||
model.eval()
|
model.eval()
|
||||||
|
|
@ -59,7 +63,7 @@ def train(
|
||||||
val_loader: DataLoader,
|
val_loader: DataLoader,
|
||||||
) -> Tuple[list[float], list[float], list[float], list[float]]:
|
) -> Tuple[list[float], list[float], list[float], list[float]]:
|
||||||
criterion = torch.nn.CrossEntropyLoss()
|
criterion = torch.nn.CrossEntropyLoss()
|
||||||
optimizer = torch.optim.Adam(model.fc.parameters(), lr=0.001, weight_decay=0.001) # type: ignore[union-attr]
|
optimizer = torch.optim.Adam(model.fc.parameters(), lr=1e-4) # type: ignore[union-attr]
|
||||||
# История метрик
|
# История метрик
|
||||||
train_loss_history = []
|
train_loss_history = []
|
||||||
train_acc_history = []
|
train_acc_history = []
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ with open("server/meta/labels_cats.json", "r") as f:
|
||||||
|
|
||||||
|
|
||||||
def predict_image(image, model, device="cuda") -> list[tuple]:
|
def predict_image(image, model, device="cuda") -> list[tuple]:
|
||||||
img_size = (180, 180)
|
img_size = (224, 224)
|
||||||
preprocess = transforms.Compose(
|
preprocess = transforms.Compose(
|
||||||
[
|
[
|
||||||
transforms.Resize(img_size),
|
transforms.Resize(img_size),
|
||||||
|
|
@ -119,12 +119,16 @@ class BaseController(Controller):
|
||||||
path = "/"
|
path = "/"
|
||||||
|
|
||||||
@get("/")
|
@get("/")
|
||||||
async def main(self) -> Template:
|
async def dogs(self) -> Template:
|
||||||
return Template(name="index.html")
|
return Template(name="dogs.html")
|
||||||
|
|
||||||
@get("/cats")
|
@get("/cats")
|
||||||
async def cats(self) -> Template:
|
async def cats(self) -> Template:
|
||||||
return Template(name="cats.html")
|
return Template(name="cats.html")
|
||||||
|
|
||||||
|
@get("/contacts")
|
||||||
|
async def contacts(self) -> Template:
|
||||||
|
return Template(name="contacts.html")
|
||||||
|
|
||||||
@get("/sitemap.xml", media_type=MediaType.XML)
|
@get("/sitemap.xml", media_type=MediaType.XML)
|
||||||
async def sitemaps(self) -> bytes:
|
async def sitemaps(self) -> bytes:
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -25,7 +25,9 @@ h1 {
|
||||||
|
|
||||||
form {
|
form {
|
||||||
border: 1px solid #696969;
|
border: 1px solid #696969;
|
||||||
padding: 0 10px 0 10px;
|
padding: 2px 10px 2px 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main {
|
#main {
|
||||||
|
|
@ -54,4 +56,66 @@ form {
|
||||||
|
|
||||||
.image-results {
|
.image-results {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#menu {
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
border-bottom: 1px solid #dee2e6; /* Серая разделительная линия */
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu li {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #696969; /* Темно-серый цвет */
|
||||||
|
font-size: 1.1rem;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu a:hover {
|
||||||
|
color: #212529; /* Чёрный при наведении */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Стиль для активной ссылки */
|
||||||
|
#menu a.active {
|
||||||
|
color: #212529;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu a.active::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #696969; /* Чёрная линия для активной ссылки */
|
||||||
|
bottom: -4px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
padding: 10px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #696969;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"]:hover {
|
||||||
|
background-color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:hover {
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="yandex-verification" content="2d4efced567f0f7f" />
|
||||||
|
<meta name="google-site-verification" content="gKPSnPZ1ULUF9amD0vw_JQqkS5GLqc937UxayaN_s-I" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
{% block meta %}{% endblock %}
|
||||||
|
<link rel="icon" type="image/x-icon" href="static/favicon.ico">
|
||||||
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
<link rel="stylesheet" href="static/styles.css">
|
||||||
|
<!-- Yandex.Metrika counter -->
|
||||||
|
<script type="text/javascript" >
|
||||||
|
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
||||||
|
m[i].l=1*new Date();
|
||||||
|
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
||||||
|
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
||||||
|
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
|
||||||
|
|
||||||
|
ym(93420354, "init", {
|
||||||
|
clickmap:true,
|
||||||
|
trackLinks:true,
|
||||||
|
accurateTrackBounce:true
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<noscript><div><img src="https://mc.yandex.ru/watch/93420354" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
||||||
|
<!-- /Yandex.Metrika counter -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section id="main">
|
||||||
|
<div id="menu">
|
||||||
|
<ul>
|
||||||
|
<li><a href = "/">Собаки</a></li>
|
||||||
|
<li><a href = "/cats">Кошки</a></li>
|
||||||
|
<li><a href = "/contacts">Контакты</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
{% block form %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</section>
|
||||||
|
<script src="static/scripts.js"></script>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -1,50 +1,25 @@
|
||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="ru">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="yandex-verification" content="2d4efced567f0f7f" />
|
|
||||||
<meta name="google-site-verification" content="gKPSnPZ1ULUF9amD0vw_JQqkS5GLqc937UxayaN_s-I" />
|
|
||||||
<meta name="description" content="Опередление породы кошки по фото. Определение породы происходит при помощи нейронной сети - точность опеределения составляет 70%." />
|
|
||||||
<link rel="icon" type="image/x-icon" href="static/favicon.ico">
|
|
||||||
<title>Определение породы кошки по фото</title>
|
|
||||||
<link rel="stylesheet" href="static/styles.css">
|
|
||||||
<!-- Yandex.Metrika counter -->
|
|
||||||
<script type="text/javascript" >
|
|
||||||
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
|
||||||
m[i].l=1*new Date();
|
|
||||||
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
|
||||||
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
|
||||||
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
|
|
||||||
|
|
||||||
ym(93420354, "init", {
|
{% block meta %}
|
||||||
clickmap:true,
|
<meta name="description" content="Опередление породы кошки по фото. Определение породы происходит при помощи нейронной сети - точность опеределения составляет 70%." />
|
||||||
trackLinks:true,
|
{% endblock %}
|
||||||
accurateTrackBounce:true
|
{% block title %}Определение породы кошки по фото{% endblock %}
|
||||||
});
|
{% block content %}
|
||||||
</script>
|
<h1>Определить породу кошки по фото</h1>
|
||||||
<noscript><div><img src="https://mc.yandex.ru/watch/93420354" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
<p>Загрузите фото, чтобы опеределить породу собаки или щенка. Если порода смешанная (или порода определена неточно), после загрузки будет показана вероятность породы животного.</p>
|
||||||
<!-- /Yandex.Metrika counter -->
|
<p>Определение породы происходит при помощи нейронной сети - точность опеределения составляет 60%, сеть обучена на 65 породах. Если на фото будет неизвестная порода или не кошка - сеть не сможет правильно опеределить, что это.</p>
|
||||||
</head>
|
<p>Для распознования все фото отправляются на сервер, но там не сохраняются</p>
|
||||||
<body>
|
{% endblock %}
|
||||||
<section id="main">
|
{% block form %}
|
||||||
<h1>Определить породу кошки по фото</h1>
|
<form enctype="multipart/form-data" method="post" action="/beerds/cats" onsubmit="SavePhoto(this);return false">
|
||||||
<p>Узнать породу <a href = "/">Собаки</a></p>
|
<input type="file" name="f" id="file-input">
|
||||||
<p>Загрузите фото, чтобы опеределить породу собаки или щенка. Если порода смешанная (или порода определена неточно), после загрузки будет показана вероятность породы животного.</p>
|
<input type="submit" value="Определить">
|
||||||
<p>Определение породы происходит при помощи нейронной сети - точность опеределения составляет 60%, сеть обучена на 65 породах. Если на фото будет неизвестная порода или не кошка - сеть не сможет правильно опеределить, что это.</p>
|
</form>
|
||||||
<p>Для распознования все фото отправляются на сервер, но там не сохраняются</p>
|
<div>
|
||||||
<form enctype="multipart/form-data" method="post" action="/beerds/cats" onsubmit="SavePhoto(this);return false">
|
<div id="upload-image">
|
||||||
<p><input type="file" name="f" id="file-input">
|
<div id="upload-image-text"></div>
|
||||||
<input type="submit" value="Определить"></p>
|
<img id="image" style="max-width: 200px;"/>
|
||||||
</form>
|
</div>
|
||||||
<div>
|
<div id="result"></div>
|
||||||
<div id="upload-image">
|
</div>
|
||||||
<div id="upload-image-text"></div>
|
{% endblock %}
|
||||||
<img id="image" style="max-width: 200px;"/>
|
|
||||||
</div>
|
|
||||||
<div id="result"></div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</section>
|
|
||||||
<script src="static/scripts.js"></script>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block meta %}
|
||||||
|
<meta name="description" content="Опередление породы собаки по фото. Определение породы происходит при помощи нейронной сети - точность опеределения составляет 80%." />
|
||||||
|
{% endblock %}
|
||||||
|
{% block title %}Контакты. Определение породы собаки или кошки по фото{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>Как можно связаться</h1>
|
||||||
|
<ul>
|
||||||
|
<li>Email: <i>artem@webart-tech.ru</i></li>
|
||||||
|
<li>VK: <a href="https://vk.com/dogs_beers?from=groups" target="_blank">Группа VK</a></li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block meta %}
|
||||||
|
<meta name="description" content="Опередление породы собаки по фото. Определение породы происходит при помощи нейронной сети - точность опеределения составляет 80%." />
|
||||||
|
{% endblock %}
|
||||||
|
{% block title %}Определение породы собаки по фото{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>Определить породу собаки по фото</h1>
|
||||||
|
<p>Загрузите фото, чтобы опеределить породу собаки или щенка. Если порода смешанная (или порода определена неточно), после загрузки будет показана вероятность породы животного.</p>
|
||||||
|
<p>Определение породы происходит при помощи нейронной сети - точность опеределения составляет 80%, сеть обучена на <a href="https://vk.com/albums-220240483" target="_blank">125 породах</a>. Если на фото будет неизвестная порода или не собака - сеть не сможет правильно опеределить, что это.</p>
|
||||||
|
<p>Для распознования все фото отправляются на сервер, но там не сохраняются</p>
|
||||||
|
{% endblock %}
|
||||||
|
{% block form %}
|
||||||
|
<form enctype="multipart/form-data" method="post" action="/beerds/dogs" onsubmit="SavePhoto(this);return false">
|
||||||
|
<input type="file" name="f" id="file-input">
|
||||||
|
<input type="submit" value="Определить">
|
||||||
|
</form>
|
||||||
|
<div>
|
||||||
|
<div id="upload-image">
|
||||||
|
<div id="upload-image-text"></div>
|
||||||
|
<img id="image" style="max-width: 200px;"/>
|
||||||
|
</div>
|
||||||
|
<div id="result"></div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ru">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="yandex-verification" content="2d4efced567f0f7f" />
|
|
||||||
<meta name="google-site-verification" content="gKPSnPZ1ULUF9amD0vw_JQqkS5GLqc937UxayaN_s-I" />
|
|
||||||
<meta name="description" content="Опередление породы собаки по фото. Определение породы происходит при помощи нейронной сети - точность опеределения составляет 80%." />
|
|
||||||
<link rel="icon" type="image/x-icon" href="static/favicon.ico">
|
|
||||||
<title>Определение породы собаки по фото</title>
|
|
||||||
<link rel="stylesheet" href="static/styles.css">
|
|
||||||
<!-- Yandex.Metrika counter -->
|
|
||||||
<script type="text/javascript" >
|
|
||||||
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
|
||||||
m[i].l=1*new Date();
|
|
||||||
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
|
||||||
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
|
||||||
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
|
|
||||||
|
|
||||||
ym(93420354, "init", {
|
|
||||||
clickmap:true,
|
|
||||||
trackLinks:true,
|
|
||||||
accurateTrackBounce:true
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<noscript><div><img src="https://mc.yandex.ru/watch/93420354" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
|
||||||
<!-- /Yandex.Metrika counter -->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<section id="main">
|
|
||||||
<h1>Определить породу собаки по фото</h1>
|
|
||||||
<p>Узнать породу <a href = "/cats">Кошки</a></p>
|
|
||||||
<p>Загрузите фото, чтобы опеределить породу собаки или щенка. Если порода смешанная (или порода определена неточно), после загрузки будет показана вероятность породы животного.</p>
|
|
||||||
<p>Определение породы происходит при помощи нейронной сети - точность опеределения составляет 60%, сеть обучена на <a href="https://vk.com/albums-220240483" target="_blank">125 породах</a>. Если на фото будет неизвестная порода или не собака - сеть не сможет правильно опеределить, что это.</p>
|
|
||||||
<p>Для распознования все фото отправляются на сервер, но там не сохраняются</p>
|
|
||||||
<form enctype="multipart/form-data" method="post" action="/beerds/dogs" onsubmit="SavePhoto(this);return false">
|
|
||||||
<p><input type="file" name="f" id="file-input">
|
|
||||||
<input type="submit" value="Определить"></p>
|
|
||||||
</form>
|
|
||||||
<div>
|
|
||||||
<div id="upload-image">
|
|
||||||
<div id="upload-image-text"></div>
|
|
||||||
<img id="image" style="max-width: 200px;"/>
|
|
||||||
</div>
|
|
||||||
<div id="result"></div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</section>
|
|
||||||
<script src="static/scripts.js"></script>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
Loading…
Reference in New Issue