Skip to content

Commit

Permalink
Merge pull request #44 from aimakerspace/asgcn
Browse files Browse the repository at this point in the history
Add Sentic-GCN to SGNlp
  • Loading branch information
jonheng authored Jan 18, 2022
2 parents b6d0aa7 + b123236 commit c4c5a94
Show file tree
Hide file tree
Showing 45 changed files with 5,144 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ cache:

run_non_slow_unit_tests:
stage: unit_test_non_slow
tags:
- dind
before_script:
- python -m venv .venv
- source .venv/bin/activate
Expand All @@ -29,6 +31,8 @@ run_non_slow_unit_tests:

run_slow_unit_tests:
stage: unit_test_slow
tags:
- dind
when: manual
before_script:
- python -m venv .venv
Expand All @@ -45,6 +49,8 @@ run_slow_unit_tests:

generate_demo_api_yaml:
stage: pre
tags:
- dind
image: alpine:latest
script:
- apk add -U jsonnet
Expand All @@ -55,6 +61,8 @@ generate_demo_api_yaml:

generate_dev_demo_api_yaml:
stage: pre
tags:
- dind
image: alpine:latest
script:
- apk add -U jsonnet
Expand Down
10 changes: 10 additions & 0 deletions demo_api/sentic_gcn/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3.8-buster

COPY . /demo_api

WORKDIR /demo_api/sentic_gcn

RUN pip install -r requirements.txt
RUN python -m download_pretrained

CMD PYTHONPATH=../../ gunicorn -c ../gunicorn.conf.py
46 changes: 46 additions & 0 deletions demo_api/sentic_gcn/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from flask import request, jsonify

from demo_api.common import create_api
from sgnlp.models.sentic_gcn import (
SenticGCNBertModel,
SenticGCNBertConfig,
SenticGCNBertPreprocessor,
SenticGCNBertPostprocessor,
)

app = create_api(app_name=__name__, model_card_path="model_card/sentic_gcn.json")

preprocessor = SenticGCNBertPreprocessor(
senticnet="https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticnet.pickle", device="cpu"
)

postprocessor = SenticGCNBertPostprocessor()

# Load model
config = SenticGCNBertConfig.from_pretrained(
"https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/config.json"
)

model = SenticGCNBertModel.from_pretrained(
"https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/pytorch_model.bin", config=config
)

app.logger.info("Preprocessing pipeline and model initialization complete.")


@app.route("/predict", methods=["POST"])
def predict():
req_body = request.get_json()

# Preprocessing
processed_inputs, processed_indices = preprocessor([req_body])
outputs = model(processed_indices)

# Postprocessing
post_outputs = postprocessor(processed_inputs=processed_inputs, model_outputs=outputs)

return jsonify(post_outputs[0])


if __name__ == "__main__":
app.run()
14 changes: 14 additions & 0 deletions demo_api/sentic_gcn/dev.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM python:3.8-buster

COPY ./demo_api /demo_api
COPY ./sgnlp /sgnlp
COPY ./setup.py /setup.py
COPY ./README.md /README.md

RUN pip install -r /demo_api/sentic_gcn/requirements_dev.txt

WORKDIR /demo_api/sentic_gcn

RUN python -m download_pretrained

CMD PYTHONPATH=../../ gunicorn -c ../gunicorn.conf.py
22 changes: 22 additions & 0 deletions demo_api/sentic_gcn/download_pretrained.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Run this script during build time to download the pretrained models and relevant files first"""

from sgnlp.models.sentic_gcn import (
SenticGCNConfig,
SenticGCNBertTokenizer,
SenticGCNBertModel,
SenticGCNBertPreprocessor
)

# Downloads preprocessor, pretrained config, tokenizer, model
preprocessor = SenticGCNBertPreprocessor(
senticnet='https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticnet.pickle',
device='cpu'
)
tokenizer = SenticGCNBertTokenizer.from_pretrained("bert-base-uncased")
config = SenticGCNConfig.from_pretrained(
"https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/config.json"
)
model = SenticGCNBertModel.from_pretrained(
"https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/pytorch_model.bin",
config=config
)
44 changes: 44 additions & 0 deletions demo_api/sentic_gcn/model_card/sentic_gcn.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "Sentic GCN",
"languages": "English",
"description": "This is a neural network that utilises LSTM and GCN to detect the sentiment polarities of different aspects in the same sentence. The models used corresponds to the associated models described in the paper.",
"paper": {
"text": "Bin Liang, Hang Su, Lin Gui, Erik Cambria, Ruifeng Xu. (2021). Aspect-based sentiment analysis via affective knowledge enhanced graph convolutional networks, 2021: 107643.",
"url": "https://github.com/BinLiang-NLP/Sentic-GCN"
},
"trainingDataset": {
"text": "acl-14-short-data, semeval14, semeval15, semeval16",
"url": "https://github.com/BinLiang-NLP/Sentic-GCN/tree/main/datasets"
},
"evaluationDataset": {
"text": "acl-14-short-data, semeval14, semeval15, semeval16",
"url": "https://github.com/BinLiang-NLP/Sentic-GCN/tree/main/datasets"
},
"evaluationScores": "Sentic-GCN: 94.36% Acc, 94.43% F1 (SemEval14-Laptop), 94.55% Acc, 91.99% F1 (SemEval14-Restaurant), 95.02% Acc, 93.22% F1 (SemEval15-Restaurant), 96.75% Acc, 93.55% F1 (SemEval16-Restaurant). Sentic-GCN Bert: 99.22% Acc, 99.15% F1 (SemEval14-Laptop), 97.39% Acc, 96.53% F1 (SemEval14-Restaurant), 99.17% Acc, 98.78% F1 (SemEval15-Restaurant), 99.37% Acc, 98.79% F1 (SemEval16-Restaurant).",
"trainingConfig": {
"text": "Refer to documentation for details."
},
"trainingTime": "Sentic-GCN: ~10 mins for ~35 epochs (early stopped), Sentic-GCN Bert: ~1 hr for ~40 epochs (early stopped) for SemEval14-Laptop/SemEval14-Restaurant/SemEval15-Restaurant/SemEval16-Restaurant datasets.",
"modelWeights": {
"text": "https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/pytorch_model.bin",
"url": "https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/pytorch_model.bin"
},
"modelConfig": {
"text": "https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/config.json",
"url": "https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/config.json"
},
"modelInput": "Aspect (word), sentence containing the aspect",
"modelOutput": "Sentiment of aspect, -1 (negative), 0 (neutral), 1 (postive)",
"modelSize": "Sentic-GCN: ~8.7MB, Sentic-GCN Bert: ~7.1MB",
"inferenceInfo": "< 1 sec on Intel(R) i7 Quad-Core @ 1.7GHz.",
"usageScenarios": "Sentiment analysis of aspects in sentences",
"originalCode": {
"text": "https://github.com/BinLiang-NLP/Sentic-GCN",
"url": "https://github.com/BinLiang-NLP/Sentic-GCN"
},
"license": {
"text": "MIT License",
"url": "https://choosealicense.com/licenses/mit"
},
"contact": "[email protected]"
}
6 changes: 6 additions & 0 deletions demo_api/sentic_gcn/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
torch==1.10.1
spacy==3.2.1
numpy==1.22.0
flask
gunicorn
sgnlp
6 changes: 6 additions & 0 deletions demo_api/sentic_gcn/requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-e .
torch==1.10.1
spacy==3.2.1
numpy==1.22.0
flask
gunicorn
43 changes: 43 additions & 0 deletions demo_api/sentic_gcn/usage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from sgnlp.models.sentic_gcn import (
SenticGCNBertModel,
SenticGCNBertPreprocessor,
SenticGCNBertConfig,
SenticGCNBertPostprocessor,
)

preprocessor = SenticGCNBertPreprocessor(
senticnet="https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticnet.pickle", device="cpu"
)

postprocessor = SenticGCNBertPostprocessor()

# Load model
config = SenticGCNBertConfig.from_pretrained(
"https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/config.json"
)

model = SenticGCNBertModel.from_pretrained(
"https://storage.googleapis.com/sgnlp/models/sentic_gcn/senticgcn_bert/pytorch_model.bin", config=config
)

# Inputs
inputs = [
{
"aspects": ["service", "decor"],
"sentence": "Everything is always cooked to perfection , the service is excellent, the decor cool and understated.",
},
{
"aspects": ["food", "portions"],
"sentence": "The food was lousy - too sweet or too salty and the portions tiny.",
},
{
"aspects": ["service"],
"sentence": "To sum it up : service varies from good to mediorce , depending on which waiter you get ; generally it is just average ok .",
},
]

processed_inputs, processed_indices = preprocessor(inputs)
outputs = model(processed_indices)

# Postprocessing
post_outputs = postprocessor(processed_inputs=processed_inputs, model_outputs=outputs)
Loading

0 comments on commit c4c5a94

Please sign in to comment.