philschmid HF staff commited on
Commit
562df22
1 Parent(s): e247d26
Files changed (7) hide show
  1. README.md +116 -1
  2. example1.jpg +0 -0
  3. handler.py +52 -0
  4. requirements.txt +4 -0
  5. sac+logos+ava1-l14-linearMSE.pth +3 -0
  6. test.ipynb +76 -0
  7. utils.py +35 -0
README.md CHANGED
@@ -1,3 +1,118 @@
1
  ---
2
- license: apache-2.0
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ tags:
3
+ - clip
4
+ - image-classification
5
+ - endpoints-template
6
+ library_name: generic
7
  ---
8
+
9
+ # Fork of [Geonmo/laion-aesthetic-predictor](https://huggingface.co/spaces/Geonmo/laion-aesthetic-predictor) for an Image Aesthetic Predictor).
10
+
11
+ This repository implements a `custom` task for `Geonmo/laion-aesthetic-predictor` for 🤗 Inference Endpoints. The code for the customized handler is in the [handler.py](https://huggingface.co/philschmid/laion-asthetic-endpoint/tree/main/handler.py).
12
+
13
+ ## Test Handler locally.
14
+
15
+ This model & handker can be tested locally using the [
16
+ hf-endpoints-emulator](https://github.com/huggingface/hf-endpoints-emulator).
17
+
18
+
19
+ 1. Clone the repository and install the requirements.
20
+
21
+ ```bash
22
+ git lfs install
23
+ git clone https://huggingface.co/philschmid/laion-asthetic-endpoint
24
+
25
+ cd laion-asthetic-endpoint
26
+ pip install -r requirements.txt
27
+ ```
28
+ 2. Install `hf-endpoints-emulator`
29
+
30
+ ```bash
31
+ pip install hf-endpoints-emulator
32
+ ```
33
+
34
+ 3. Run the emulator
35
+
36
+ ```bash
37
+ hf-endpoints-emulator --handler handler.py
38
+ ```
39
+
40
+ 4. Test the endpoint and send request
41
+
42
+ ```bash
43
+ curl --request POST \
44
+ --url http://localhost \
45
+ --header 'Content-Type: image/jpg' \
46
+ --data-binary '@example1.jpg'
47
+ ```
48
+
49
+
50
+ ## Run Request
51
+
52
+ The endpoint expects the image to be served as `binary`. Below is an curl and python example
53
+
54
+ #### cURL
55
+
56
+ 1. get image
57
+
58
+ ```bash
59
+ wget https://fki.tic.heia-fr.ch/static/img/a01-122-02-00.jpg -O test.jpg
60
+ ```
61
+
62
+ 2. send cURL request
63
+
64
+ ```bash
65
+ curl --request POST \
66
+ --url https://{ENDPOINT}/ \
67
+ --header 'Content-Type: image/jpg' \
68
+ --header 'Authorization: Bearer {HF_TOKEN}' \
69
+ --data-binary '@test.jpg'
70
+ ```
71
+
72
+ 3. the expected output
73
+
74
+ ```json
75
+ {"text": "INDLUS THE"}
76
+ ```
77
+
78
+ #### Python
79
+
80
+
81
+ 1. get image
82
+
83
+ ```bash
84
+ wget https://fki.tic.heia-fr.ch/static/img/a01-122-02-00.jpg -O test.jpg
85
+ ```
86
+
87
+ 2. run request
88
+
89
+ ```python
90
+ import json
91
+ from typing import List
92
+ import requests as r
93
+ import base64
94
+
95
+ ENDPOINT_URL=""
96
+ HF_TOKEN=""
97
+
98
+ def predict(path_to_image:str=None):
99
+ with open(path_to_image, "rb") as i:
100
+ b = i.read()
101
+ headers= {
102
+ "Authorization": f"Bearer {HF_TOKEN}",
103
+ "Content-Type": "image/jpeg" # content type of image
104
+ }
105
+ response = r.post(ENDPOINT_URL, headers=headers, data=b)
106
+ return response.json()
107
+
108
+ prediction = predict(path_to_image="test.jpg")
109
+
110
+ prediction
111
+ ```
112
+
113
+ expected output
114
+
115
+ ```python
116
+ {"text": "INDLUS THE"}
117
+ ```
118
+
example1.jpg ADDED
handler.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import clip
4
+ from utils import MLP, normalized
5
+
6
+ # set device
7
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
8
+
9
+
10
+ class EndpointHandler:
11
+ def __init__(self, path=""):
12
+ model = MLP(768)
13
+
14
+ s = torch.load(os.path.join(path, "sac+logos+ava1-l14-linearMSE.pth"), map_location=device)
15
+
16
+ model.load_state_dict(s)
17
+ model.to(device)
18
+ model.eval()
19
+
20
+ model2, preprocess = clip.load("ViT-L/14", device=device)
21
+
22
+ self.model_dict = {}
23
+ self.model_dict["classifier"] = model
24
+ self.model_dict["clip_model"] = model2
25
+ self.model_dict["clip_preprocess"] = preprocess
26
+ self.model_dict["device"] = device
27
+
28
+ def __call__(self, data):
29
+ """
30
+ data args:
31
+ images (:obj:`PIL.Image`)
32
+ candiates (:obj:`list`)
33
+ Return:
34
+ A :obj:`list`:. The list contains items that are dicts should be liked {"label": "XXX", "score": 0.82}
35
+ """
36
+ # extract converted PIL image from serialized request
37
+ image = data.pop("inputs", data)
38
+
39
+ image_input = self.model_dict["clip_preprocess"](image).unsqueeze(0).to(self.model_dict["device"])
40
+ with torch.no_grad():
41
+ image_features = self.model_dict["clip_model"].encode_image(image_input)
42
+ if self.model_dict["device"].type == "cuda":
43
+ im_emb_arr = normalized(image_features.detach().cpu().numpy())
44
+ im_emb = torch.from_numpy(im_emb_arr).to(self.model_dict["device"]).type(torch.cuda.FloatTensor)
45
+ else:
46
+ im_emb_arr = normalized(image_features.detach().numpy())
47
+ im_emb = torch.from_numpy(im_emb_arr).to(self.model_dict["device"]).type(torch.FloatTensor)
48
+
49
+ prediction = self.model_dict["classifier"](im_emb)
50
+ score = prediction.item()
51
+
52
+ return {"aesthetic score": score}
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ ftfy
2
+ regex
3
+ git+https://github.com/openai/CLIP.git
4
+ pytorch-lightning
sac+logos+ava1-l14-linearMSE.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:21dd590f3ccdc646f0d53120778b296013b096a035a2718c9cb0d511bff0f1e0
3
+ size 3714759
test.ipynb ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "from handler import EndpointHandler\n",
10
+ "\n",
11
+ "# init handler\n",
12
+ "my_handler = EndpointHandler(path=\".\")\n"
13
+ ]
14
+ },
15
+ {
16
+ "cell_type": "code",
17
+ "execution_count": 2,
18
+ "metadata": {},
19
+ "outputs": [
20
+ {
21
+ "data": {
22
+ "text/plain": [
23
+ "{'aesthetic score': 6.764713287353516}"
24
+ ]
25
+ },
26
+ "execution_count": 2,
27
+ "metadata": {},
28
+ "output_type": "execute_result"
29
+ }
30
+ ],
31
+ "source": [
32
+ "from PIL import Image\n",
33
+ "\n",
34
+ "# read PIL image\n",
35
+ "image = Image.open(\"example1.jpg\")\n",
36
+ "payload = {\"inputs\": image}\n",
37
+ "\n",
38
+ "my_handler(payload)"
39
+ ]
40
+ },
41
+ {
42
+ "cell_type": "code",
43
+ "execution_count": null,
44
+ "metadata": {},
45
+ "outputs": [],
46
+ "source": []
47
+ }
48
+ ],
49
+ "metadata": {
50
+ "kernelspec": {
51
+ "display_name": "dev",
52
+ "language": "python",
53
+ "name": "python3"
54
+ },
55
+ "language_info": {
56
+ "codemirror_mode": {
57
+ "name": "ipython",
58
+ "version": 3
59
+ },
60
+ "file_extension": ".py",
61
+ "mimetype": "text/x-python",
62
+ "name": "python",
63
+ "nbconvert_exporter": "python",
64
+ "pygments_lexer": "ipython3",
65
+ "version": "3.9.13"
66
+ },
67
+ "orig_nbformat": 4,
68
+ "vscode": {
69
+ "interpreter": {
70
+ "hash": "f6dd96c16031089903d5a31ec148b80aeb0d39c32affb1a1080393235fbfa2fc"
71
+ }
72
+ }
73
+ },
74
+ "nbformat": 4,
75
+ "nbformat_minor": 2
76
+ }
utils.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import numpy as np
4
+
5
+
6
+ # if you changed the MLP architecture during training, change it also here:
7
+ class MLP(torch.nn.Module):
8
+ def __init__(self, input_size, xcol="emb", ycol="avg_rating"):
9
+ super().__init__()
10
+ self.input_size = input_size
11
+ self.xcol = xcol
12
+ self.ycol = ycol
13
+ self.layers = nn.Sequential(
14
+ nn.Linear(self.input_size, 1024),
15
+ # nn.ReLU(),
16
+ nn.Dropout(0.2),
17
+ nn.Linear(1024, 128),
18
+ # nn.ReLU(),
19
+ nn.Dropout(0.2),
20
+ nn.Linear(128, 64),
21
+ # nn.ReLU(),
22
+ nn.Dropout(0.1),
23
+ nn.Linear(64, 16),
24
+ # nn.ReLU(),
25
+ nn.Linear(16, 1),
26
+ )
27
+
28
+ def forward(self, x):
29
+ return self.layers(x)
30
+
31
+
32
+ def normalized(a, axis=-1, order=2):
33
+ l2 = np.atleast_1d(np.linalg.norm(a, order, axis))
34
+ l2[l2 == 0] = 1
35
+ return a / np.expand_dims(l2, axis)