nkigumnov commited on
Commit
a2887cd
1 Parent(s): 9ae54b8

Upload 5 files

Browse files
Files changed (5) hide show
  1. app.py +47 -0
  2. best_model_bert.pth +3 -0
  3. best_model_heads.pth +3 -0
  4. model.py +153 -0
  5. 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