Spaces:
Build error
Build error
Upload 5 files
Browse files- app.py +47 -0
- best_model_bert.pth +3 -0
- best_model_heads.pth +3 -0
- model.py +153 -0
- requirements.txt +5 -0
app.py
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
from model import inference
|
4 |
+
|
5 |
+
|
6 |
+
def predict(sentence: str):
|
7 |
+
model_response = inference({"sentence": sentence})
|
8 |
+
prob = model_response["answer"]
|
9 |
+
df = {
|
10 |
+
"1": float(prob[1][0][2]),
|
11 |
+
"0": float(prob[1][0][1]),
|
12 |
+
"-1": float(prob[1][0][0]),
|
13 |
+
"Communication": float(prob[0][0][0]),
|
14 |
+
"Quality": float(prob[0][0][1]),
|
15 |
+
"Price": float(prob[0][0][2]),
|
16 |
+
"Safety": float(prob[0][0][3]),
|
17 |
+
}
|
18 |
+
return (
|
19 |
+
df["1"],
|
20 |
+
df["0"],
|
21 |
+
df["-1"],
|
22 |
+
df["Communication"],
|
23 |
+
df["Quality"],
|
24 |
+
df["Price"],
|
25 |
+
df["Safety"],
|
26 |
+
)
|
27 |
+
|
28 |
+
|
29 |
+
if __name__ == "__main__":
|
30 |
+
print("App started")
|
31 |
+
|
32 |
+
demo = gr.Interface(
|
33 |
+
fn=predict,
|
34 |
+
title="Try it yourself!",
|
35 |
+
inputs=gr.Textbox(lines=3, placeholder="Sentence here..."),
|
36 |
+
outputs=[
|
37 |
+
gr.Number(0.0, label="1"),
|
38 |
+
gr.Number(0.0, label="0"),
|
39 |
+
gr.Number(0.0, label="-1"),
|
40 |
+
gr.Number(0.0, label="Communication"),
|
41 |
+
gr.Number(0.0, label="Quality"),
|
42 |
+
gr.Number(0.0, label="Price"),
|
43 |
+
gr.Number(0.0, label="Safety"),
|
44 |
+
],
|
45 |
+
)
|
46 |
+
|
47 |
+
demo.launch(server_name="0.0.0.0", server_port=8080)
|
best_model_bert.pth
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:2183c10359aa1a55a8510ed1d8c3a02678b0f0aa585f8a931e9db5493db7cc21
|
3 |
+
size 709923201
|
best_model_heads.pth
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:5796bc27244f82089e1950d4d308b2ca8c06b7e649fd2acf0ec859cef121465e
|
3 |
+
size 136297
|
model.py
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!g1.1
|
2 |
+
|
3 |
+
import torch
|
4 |
+
import torch.nn as nn
|
5 |
+
from transformers import AutoTokenizer, AutoModel
|
6 |
+
|
7 |
+
import copy
|
8 |
+
|
9 |
+
|
10 |
+
class DL_category(nn.Module):
|
11 |
+
def __init__(self):
|
12 |
+
super(DL_category, self).__init__()
|
13 |
+
self.lin1 = nn.Linear(256, 64)
|
14 |
+
nn.init.xavier_uniform_(self.lin1.weight)
|
15 |
+
self.lin2 = nn.Linear(64, 5)
|
16 |
+
nn.init.xavier_uniform_(self.lin2.weight)
|
17 |
+
|
18 |
+
def forward(self, x):
|
19 |
+
x = torch.relu(self.lin1(x))
|
20 |
+
x = self.lin2(x)
|
21 |
+
return x
|
22 |
+
|
23 |
+
|
24 |
+
class DL_sentiment(nn.Module):
|
25 |
+
def __init__(self):
|
26 |
+
super(DL_sentiment, self).__init__()
|
27 |
+
self.lin1 = nn.Linear(256, 64)
|
28 |
+
nn.init.xavier_uniform_(self.lin1.weight)
|
29 |
+
self.lin2 = nn.Linear(64, 1, bias=False)
|
30 |
+
nn.init.xavier_uniform_(self.lin2.weight)
|
31 |
+
|
32 |
+
def forward(self, x):
|
33 |
+
x = torch.relu(self.lin1(x))
|
34 |
+
x = self.lin2(x)
|
35 |
+
return x
|
36 |
+
|
37 |
+
|
38 |
+
def mean_pooling(model_output, attention_mask):
|
39 |
+
input_mask_expanded = attention_mask.unsqueeze(-1).expand(model_output.size()).float()
|
40 |
+
sum_embeddings = torch.sum(model_output * input_mask_expanded, 1)
|
41 |
+
sum_mask = torch.clamp(input_mask_expanded.sum(1), min=1e-9)
|
42 |
+
return sum_embeddings / sum_mask
|
43 |
+
|
44 |
+
|
45 |
+
class Union_model(nn.Module):
|
46 |
+
def __init__(self, bert_model):
|
47 |
+
super(Union_model, self).__init__()
|
48 |
+
|
49 |
+
bert_model = bert_model
|
50 |
+
for name, param in bert_model.named_parameters():
|
51 |
+
param.requires_grad = False
|
52 |
+
bert_model.pooler = nn.Sequential(
|
53 |
+
nn.Linear(in_features=768, out_features=256)
|
54 |
+
)
|
55 |
+
bert_model = bert_model.to('cpu')
|
56 |
+
# print(bert_model.parameters)
|
57 |
+
|
58 |
+
self.DL_cat = DL_category()
|
59 |
+
self.DL_sent = DL_sentiment()
|
60 |
+
|
61 |
+
def forward(self, input):
|
62 |
+
output = bert_model(**input)
|
63 |
+
output = output.pooler_output
|
64 |
+
output = mean_pooling(output, input['attention_mask'])
|
65 |
+
|
66 |
+
return self.DL_cat(output), self.DL_sent(output)
|
67 |
+
|
68 |
+
|
69 |
+
class LogisticCumulativeLink(nn.Module):
|
70 |
+
"""
|
71 |
+
Converts a single number to the proportional odds of belonging to a class.
|
72 |
+
Parameters
|
73 |
+
----------
|
74 |
+
num_classes : int
|
75 |
+
Number of ordered classes to partition the odds into.
|
76 |
+
init_cutpoints : str (default='ordered')
|
77 |
+
How to initialize the cutpoints of the model. Valid values are
|
78 |
+
- ordered : cutpoints are initialized to halfway between each class.
|
79 |
+
- random : cutpoints are initialized with random values.
|
80 |
+
"""
|
81 |
+
|
82 |
+
def __init__(self, num_classes: int,
|
83 |
+
init_cutpoints: str = 'ordered') -> None:
|
84 |
+
assert num_classes > 2, (
|
85 |
+
'Only use this model if you have 3 or more classes'
|
86 |
+
)
|
87 |
+
super().__init__()
|
88 |
+
self.num_classes = num_classes
|
89 |
+
self.init_cutpoints = init_cutpoints
|
90 |
+
if init_cutpoints == 'ordered':
|
91 |
+
num_cutpoints = self.num_classes - 1
|
92 |
+
cutpoints = torch.arange(num_cutpoints).float() - num_cutpoints / 2
|
93 |
+
self.cutpoints = nn.Parameter(cutpoints)
|
94 |
+
elif init_cutpoints == 'random':
|
95 |
+
cutpoints = torch.rand(self.num_classes - 1).sort()[0]
|
96 |
+
self.cutpoints = nn.Parameter(cutpoints)
|
97 |
+
else:
|
98 |
+
raise ValueError(f'{init_cutpoints} is not a valid init_cutpoints '
|
99 |
+
f'type')
|
100 |
+
|
101 |
+
def forward(self, X: torch.Tensor) -> torch.Tensor:
|
102 |
+
"""
|
103 |
+
Equation (11) from
|
104 |
+
"On the consistency of ordinal regression methods", Pedregosa et. al.
|
105 |
+
"""
|
106 |
+
sigmoids = torch.sigmoid(self.cutpoints - X)
|
107 |
+
link_mat = sigmoids[:, 1:] - sigmoids[:, :-1]
|
108 |
+
link_mat = torch.cat((
|
109 |
+
sigmoids[:, [0]],
|
110 |
+
link_mat,
|
111 |
+
(1 - sigmoids[:, [-1]])
|
112 |
+
),
|
113 |
+
dim=1
|
114 |
+
)
|
115 |
+
return link_mat
|
116 |
+
|
117 |
+
|
118 |
+
class CustomOrdinalLogisticModel(nn.Module):
|
119 |
+
def __init__(self, predictor: nn.Module, num_classes: int,
|
120 |
+
init_cutpoints: str = 'ordered') -> None:
|
121 |
+
super().__init__()
|
122 |
+
self.num_classes = num_classes
|
123 |
+
self.predictor = copy.deepcopy(predictor)
|
124 |
+
self.link = LogisticCumulativeLink(self.num_classes,
|
125 |
+
init_cutpoints=init_cutpoints)
|
126 |
+
|
127 |
+
def forward(self, *args, **kwargs) -> torch.Tensor:
|
128 |
+
cat, sent = self.predictor(*args, **kwargs)
|
129 |
+
return cat, self.link(sent)
|
130 |
+
|
131 |
+
|
132 |
+
tokenizer = AutoTokenizer.from_pretrained('blanchefort/rubert-base-cased-sentiment-rusentiment')
|
133 |
+
|
134 |
+
bert_model = AutoModel.from_pretrained('blanchefort/rubert-base-cased-sentiment-rusentiment',
|
135 |
+
output_hidden_states=True).to('cpu')
|
136 |
+
bert_model.pooler = nn.Sequential(
|
137 |
+
nn.Linear(in_features=768, out_features=256)
|
138 |
+
)
|
139 |
+
|
140 |
+
model = CustomOrdinalLogisticModel(Union_model(bert_model), 3).to('cpu')
|
141 |
+
model.load_state_dict(torch.load('best_model_heads.pth', map_location='cpu'), strict=False)
|
142 |
+
|
143 |
+
bert_model.load_state_dict(torch.load('best_model_bert.pth', map_location='cpu'))
|
144 |
+
|
145 |
+
|
146 |
+
def inference(input_data):
|
147 |
+
tokenized = tokenizer(input_data['sentence'])
|
148 |
+
input_ids = torch.LongTensor(tokenized['input_ids']).unsqueeze(0).to('cpu')
|
149 |
+
attention_mask = torch.IntTensor(tokenized['attention_mask']).unsqueeze(0).to('cpu')
|
150 |
+
|
151 |
+
model.eval()
|
152 |
+
|
153 |
+
return dict(answer=model({'input_ids': input_ids, 'attention_mask': attention_mask}))
|
requirements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio~=3.27.0
|
2 |
+
requests~=2.28.2
|
3 |
+
PyYAML~=6.0
|
4 |
+
torch~=2.0.0
|
5 |
+
transformers~=4.28.1
|