mnemlaghi commited on
Commit
af18939
1 Parent(s): 888d6e3

add app files

Browse files
Files changed (6) hide show
  1. deploy/Dockerfile +21 -0
  2. src/__init__.py +0 -0
  3. src/app.py +59 -0
  4. src/meta.py +35 -0
  5. src/requirements.txt +3 -0
  6. src/sampler.py +71 -0
deploy/Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.7-slim-buster
2
+
3
+ ENV REMOTEPORT 1091
4
+ RUN pip install --upgrade pip
5
+
6
+ RUN useradd --create-home server
7
+
8
+ USER server
9
+
10
+ ENV PATH="/home/server/.local/bin:${PATH}"
11
+
12
+ COPY --chown=server:server src src
13
+
14
+ RUN pip install --user -r src/requirements.txt
15
+
16
+ ## Downloading Belgian GPT2 Model, in order to accelerate startup time
17
+ RUN python -c "from transformers import GPT2Tokenizer; _ = GPT2Tokenizer.from_pretrained('antoiloui/belgpt2')"
18
+ RUN python -c "from transformers import GPT2LMHeadModel; _ = GPT2LMHeadModel.from_pretrained('antoiloui/belgpt2')"
19
+
20
+ ## Running streamlit
21
+ CMD streamlit run src/app.py --server.port $REMOTEPORT
src/__init__.py ADDED
File without changes
src/app.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from sampler import GPT2SentencesGenerator, SamplingSentencesGenerator, GreedySentencesGenerator, BeamSentencesGenerator
3
+ import meta
4
+
5
+ st.set_page_config(layout="wide")
6
+
7
+ @st.cache(allow_output_mutation = True)
8
+ def get_sentences_generator(method):
9
+ model_dir = "antoiloui/belgpt2"
10
+ if method =='sampling':
11
+ return SamplingSentencesGenerator(model_dir)
12
+ elif method == 'greedy':
13
+ return GreedySentencesGenerator(model_dir)
14
+ elif method == 'beam':
15
+ return BeamSentencesGenerator(model_dir)
16
+ else:
17
+ return NotImplementedError
18
+
19
+
20
+ def display_parameters_from_generation_method(methode):
21
+ user_input = st.text_input('Texte de départ (peut être vide)', "les modèles génératifs sont cool !")
22
+ if methode == 'sampling':
23
+ user_nsamples = st.number_input("Nombre de phrases", min_value=1, max_value = 20)
24
+ user_temperature = st.slider("Choisissez une température : le degré de 'folie' du texte", min_value = 0.01, max_value = 1.5, value = 0.7)
25
+ user_top_k = st.slider(" TOP K : choisissez parmi les K mots les plus probables dans la génération", min_value = 0, max_value = 1000, value=0)
26
+ user_top_p = st.slider(" TOP P : choisissez parmi le pourcentage des mots les plus probables dans la génération", min_value = 0.5, max_value = 0.99, value = 0.9)
27
+ args_dict= {"contexte":user_input, "nsamples":user_nsamples, "temperature":user_temperature, "top_p":user_top_p, "top_k":user_top_k}
28
+ elif methode == 'greedy':
29
+ args_dict= {"contexte":user_input}
30
+ elif methode == 'beam':
31
+ user_num_beams = st.number_input("Nombre de faisceaux de probabilités", min_value = 2, max_value = 10)
32
+ user_nsamples = st.number_input("Nombre de phrases", min_value=1, max_value = 10)
33
+ args_dict= {"contexte":user_input, "num_beams":user_num_beams, "nsamples":user_nsamples}
34
+ else:
35
+ st.write("Les autres méthodes arrivent !!!")
36
+ return args_dict
37
+
38
+
39
+ def display_principles():
40
+ for k,sentences in meta.body.items():
41
+ st.header(k)
42
+ for s in sentences:
43
+ st.write(s)
44
+
45
+ def main():
46
+ st.title(meta.TITLE)
47
+ display_principles()
48
+ methode = st.selectbox("Choisissez votre méthode de génération", ['sampling', 'greedy', 'beam'])
49
+ generator = get_sentences_generator(methode)
50
+ st.header(f"Paramètres de la méthode __{methode}__")
51
+ args_dict = display_parameters_from_generation_method(methode)
52
+
53
+ if st.button('Parle, beau parleur !'):
54
+ res = generator.generate(**args_dict)
55
+ for texte in res:
56
+ st.write(texte)
57
+
58
+ if __name__=='__main__':
59
+ main()
src/meta.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import OrderedDict
2
+
3
+ TITLE = "Beau parleur 🥖🥖🥖 : plateforme d'expérimentation de modèle génératif en langue française"
4
+
5
+ HEADER1 = "Principes et objectifs"
6
+ HEADER2 = "Méthodes de génération"
7
+ HEADER3 = "Expérimentons ! "
8
+
9
+ body = OrderedDict()
10
+
11
+ body[HEADER1] = []
12
+ body[HEADER1].append("Les modèles génératifs sur base des [Transformers](https://fr.wikipedia.org/wiki/Transformeur) ont permis une avancée notable en ce qui concerne la compréhension automatisée du langage. Ceci a permis des innovations de rupture dans plusieurs domaines, notamment dans la qualification de texte. Mais _quid_ du domaine créatif ? C'est ici qu'interviennent les modèles génératifs tels que [GPT](https://openai.com/blog/language-unsupervised/),[GPT-2](https://openai.com/blog/better-language-models/) ou encore le récent - et révolutionnaire - [GPT3](https://arxiv.org/abs/2005.14165).")
13
+
14
+ body[HEADER1].append("Ces modèles sont pré-entraînés : ceci veut dire que les paramètres qui les déterminent ont déjà été appris par une grande volumétrie de données. Ainsi, libre à l'utilisateur de ce modèle de l'utiliser directement, ou bien de _spécialiser_ le modèle en ajoutant une couche d'apprentissage supplémentaire (on parle alors de _fine-tuning_)")
15
+
16
+ body[HEADER1].append("Ceci étant, les modèles génératifs sont biaisés en ce qui concerne les langues traitées. Ainsi, la donnée ayant servi à créer les modèles génératifs GPT est principalement de langue anglaise, ce qui peut avoir tendance à entraver l'adoption de l'intelligence artificielle dans le monde dans le monde.")
17
+
18
+
19
+ body[HEADER1].append("La langue française n'est pas épargnée par une telle prépondérance de la langue anglaise. Notons néanmoins la remarquable initiative [PiaF](https://aclanthology.org/2020.lrec-1.673/), initiative issue de l'[EtaLab](https://www.etalab.gouv.fr/politique-de-la-donnee), plateforme gouvernementale de partage de la donnée.")
20
+
21
+ body[HEADER1].append("Fort heureusement, la langue française ne se résume pas au territoire hexagonal ! Ainsi Antoine Louis a pré-entraîné un modèle GPT-2 sur près de 60Gb de donnée française et a mis à disposition ce modèle sur Hugging Face. Ce modèle se nomme [BelGPT-2](https://github.com/antoiloui/belgpt2), et c'est celui-ci que nous utiliserons.")
22
+
23
+
24
+ body[HEADER2] = []
25
+ body[HEADER2].append("Nous allons explorer 3 méthodes de génération. Les personnes intéressées pourront se référer au [post de blog de Hugging Face sur les modèles génératif](https://huggingface.co/blog/how-to-generate)")
26
+ body[HEADER2].append("En bref, un modèle de type GPT2 est __auto-régressif__: conditionnellement à un mot que l'on prononce au sein d'une phrase, le modèle apprend à déterminer le mot suivant le plus probable.")
27
+
28
+ body[HEADER2].append("Trois méthodes de générations sont possibles à partir de ce modèle")
29
+ body[HEADER2].append(" - Une génération _greedy_ : les mots générés sont les mots les plus probables. Cette méthode n'a pas l'avantage de la diversité, car il n'en découle qu'un seul scénario possible.")
30
+ body[HEADER2].append(" - Une génération par faisceaux, dite _beam search_ : les mots générés font partie d'une arborescence de mots les plus probables.")
31
+ body[HEADER2].append(" - Une génération par échantillonage, ou une génération _sampling_ : On échantillone suivant la loi de probabilité calibrée par le modèle.")
32
+
33
+ body[HEADER3] = []
34
+ body[HEADER3].append("Il est grand temps d'expérimenter la génération et de se laisser entraîner par les différentes propositions")
35
+ body[HEADER3].append("⚠️ Suivant les paramètres d'entrée, les textes générés peuvent être vulgaires, voire offensants. Ceux-ci peuvent être instructifs en ce qui concerne toxicité actuelle des discours sur Internet : en effet, la donnée sur laquelle ces modèles sont appris ⚠️ ")
src/requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ streamlit
2
+ torch
3
+ transformers
src/sampler.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ import argparse
3
+ from transformers import CamembertTokenizerFast
4
+ from transformers import GPT2Config, GPT2LMHeadModel, GPT2Tokenizer
5
+ from abc import abstractmethod
6
+ from typing import List
7
+
8
+ class GPT2SentencesGenerator():
9
+ """Abstract sentences GPT2 class, taking two inputs directly from Huffing Face directory: tokenizer and model"""
10
+ def __init__(self, model_dir):
11
+ self.tokenizer = GPT2Tokenizer.from_pretrained(model_dir)
12
+ self.model = GPT2LMHeadModel.from_pretrained(model_dir)
13
+
14
+ @abstractmethod
15
+ def generate(self):
16
+ """Abstract generative method"""
17
+ pass
18
+
19
+ def decode(self, generated: List[int])-> List[str]:
20
+ """ Decode model output """
21
+ res = []
22
+ for v in generated:
23
+ res.append(self.tokenizer.decode(v, skip_special_tokens = True))
24
+ return res
25
+
26
+ def encode_context(self, contexte:str)->List[int]:
27
+ """encodes prompt input with UTF8 handling"""
28
+ utf8_contexte = contexte.encode("utf8").decode("utf8")
29
+ input_ids = self.tokenizer.encode(utf8_contexte, return_tensors = "pt")
30
+ return input_ids
31
+
32
+ class GreedySentencesGenerator(GPT2SentencesGenerator):
33
+ def generate(self, contexte:str)->List[str]:
34
+ """ Greedy output generation method """
35
+ input_ids = self.encode_context(contexte)
36
+ generated = self.model.generate(input_ids, do_sample = False)
37
+ return self.decode(generated)
38
+
39
+ class BeamSentencesGenerator(GPT2SentencesGenerator):
40
+ def generate(self, contexte:str, nsamples:int, num_beams:int)->List[str]:
41
+ """ """
42
+ input_ids = self.encode_context(contexte)
43
+ generated = self.model.generate(input_ids, do_sample = False, num_beams= num_beams, num_return_sequences = nsamples, early_stopping=True)
44
+ return self.decode(generated)
45
+
46
+ class SamplingSentencesGenerator(GPT2SentencesGenerator):
47
+ def generate(self, contexte:str, nsamples : int =10, temperature : int = 0.7, top_p: float = 0.9, top_k : float =0)-> List[str]:
48
+ input_ids = self.encode_context(contexte)
49
+ generated = self.model.generate(
50
+ input_ids,
51
+ do_sample=True,
52
+ top_p = top_p,
53
+ top_k = top_k,
54
+ temperature =temperature,
55
+ num_return_sequences=nsamples,
56
+ repetition_penalty = 1.2,
57
+ early_stopping = True)
58
+ return self.decode(generated)
59
+
60
+ if __name__=='__main__':
61
+ parser = argparse.ArgumentParser()
62
+ parser.add_argument("--contexte")
63
+ parser.add_argument("--model_dir")
64
+ parser.add_argument("--temperature", type = float, default = 0.7)
65
+ parser.add_argument("--tensors_type", default = "pt")
66
+ parser.add_argument("--samples_output", default = "generated_sample.txt")
67
+ args = parser.parse_args()
68
+ g = SamplingSentencesGenerator(args.model_dir)
69
+ res = g.generate(args.contexte, nsamples = 5, temperature = args.temperature)
70
+ for v in res:
71
+ print(v)