Eine Frage haben? Verbinden Sie sich mit der Community im TensorFlow Forum Visit Forum

Text laden

Ansicht auf TensorFlow.org In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Dieses Tutorial zeigt zwei Möglichkeiten zum Laden und Vorverarbeiten von Text.

  • Zunächst verwenden Sie Keras-Dienstprogramme und -Ebenen. Wenn Sie TensorFlow noch nicht kennen, sollten Sie mit diesen beginnen.

  • Als Nächstes verwenden Sie untergeordnete Dienstprogramme wie tf.data.TextLineDataset , um Textdateien zu laden, und tf.text um die Daten für eine feinere Steuerung tf.text .

# Be sure you're using the stable versions of both tf and tf-text, for binary compatibility.
pip install -q -U tf-nightly
pip install -q -U tensorflow-text-nightly
import collections
import pathlib
import re
import string

import tensorflow as tf

from tensorflow.keras import layers
from tensorflow.keras import losses
from tensorflow.keras import preprocessing
from tensorflow.keras import utils
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization

import tensorflow_datasets as tfds
import tensorflow_text as tf_text

Beispiel 1: Sagen Sie das Tag für eine Stapelüberlauffrage voraus

Als erstes Beispiel laden Sie einen Datensatz mit Programmierfragen von Stack Overflow herunter. Jede Frage ("Wie sortiere ich ein Wörterbuch nach Wert?") CSharp mit genau einem Tag gekennzeichnet ( Python , CSharp , JavaScript oder Java ). Ihre Aufgabe ist es, ein Modell zu entwickeln, das das Tag für eine Frage vorhersagt. Dies ist ein Beispiel für die Klassifizierung mehrerer Klassen, ein wichtiges und weit verbreitetes Problem des maschinellen Lernens.

Laden Sie den Datensatz herunter und erkunden Sie ihn

Als Nächstes laden Sie den Datensatz herunter und untersuchen die Verzeichnisstruktur.

data_url = 'https://storage.googleapis.com/download.tensorflow.org/data/stack_overflow_16k.tar.gz'
dataset = utils.get_file(
    'stack_overflow_16k.tar.gz',
    data_url,
    untar=True,
    cache_dir='stack_overflow',
    cache_subdir='')
dataset_dir = pathlib.Path(dataset).parent
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/stack_overflow_16k.tar.gz
6053888/6053168 [==============================] - 0s 0us/step
list(dataset_dir.iterdir())
[PosixPath('/tmp/.keras/train'),
 PosixPath('/tmp/.keras/README.md'),
 PosixPath('/tmp/.keras/test'),
 PosixPath('/tmp/.keras/stack_overflow_16k.tar.gz.tar.gz')]
train_dir = dataset_dir/'train'
list(train_dir.iterdir())
[PosixPath('/tmp/.keras/train/java'),
 PosixPath('/tmp/.keras/train/csharp'),
 PosixPath('/tmp/.keras/train/javascript'),
 PosixPath('/tmp/.keras/train/python')]

Die train/csharp , train/java , train/python und train/javascript enthalten viele Textdateien, von denen jede eine Frage zum Stapelüberlauf ist. Drucken Sie eine Datei und überprüfen Sie die Daten.

sample_file = train_dir/'python/1755.txt'
with open(sample_file) as f:
  print(f.read())
why does this blank program print true x=true.def stupid():.    x=false.stupid().print x

Laden Sie den Datensatz

Als Nächstes laden Sie die Daten von der Festplatte und bereiten sie in einem für das Training geeigneten Format vor. Dazu verwenden Sie das Dienstprogramm text_dataset_from_directory , um ein beschriftetestf.data.Dataset zu erstellen. Wenn Sie mit tf.data noch nicht vertraut sind , handelt es sich um eine leistungsstarke Sammlung von Tools zum Erstellen von Eingabepipelines.

Das Verzeichnis preprocessing.text_dataset_from_directory erwartet eine Verzeichnisstruktur wie folgt.

train/
...csharp/
......1.txt
......2.txt
...java/
......1.txt
......2.txt
...javascript/
......1.txt
......2.txt
...python/
......1.txt
......2.txt

Wenn Sie ein Experiment zum maschinellen Lernen ausführen, empfiehlt es sich, Ihren Datensatz in drei Teile zu unterteilen: Trainieren , Validieren und Testen . Das Stack Overflow-Dataset wurde bereits in Zug und Test unterteilt, es fehlt jedoch ein Validierungssatz. Erstellen Sie einen Validierungssatz mit einer 80: 20-Aufteilung der Trainingsdaten, indem Sie das folgende Argument validation_split .

batch_size = 32
seed = 42

raw_train_ds = preprocessing.text_dataset_from_directory(
    train_dir,
    batch_size=batch_size,
    validation_split=0.2,
    subset='training',
    seed=seed)
Found 8000 files belonging to 4 classes.
Using 6400 files for training.

Wie Sie oben sehen können, enthält der Trainingsordner 8.000 Beispiele, von denen Sie 80% (oder 6.400) für das Training verwenden. Wie Sie gleich sehen werden, können Sie ein Modell trainieren, indem Sie eintf.data.Dataset direkt an model.fit . Durchlaufen Sie zunächst den Datensatz und drucken Sie einige Beispiele aus, um ein Gefühl für die Daten zu bekommen.

for text_batch, label_batch in raw_train_ds.take(1):
  for i in range(10):
    print("Question: ", text_batch.numpy()[i])
    print("Label:", label_batch.numpy()[i])
Question:  b'"my tester is going to the wrong constructor i am new to programming so if i ask a question that can be easily fixed, please forgive me. my program has a tester class with a main. when i send that to my regularpolygon class, it sends it to the wrong constructor. i have two constructors. 1 without perameters..public regularpolygon().    {.       mynumsides = 5;.       mysidelength = 30;.    }//end default constructor...and my second, with perameters. ..public regularpolygon(int numsides, double sidelength).    {.        mynumsides = numsides;.        mysidelength = sidelength;.    }// end constructor...in my tester class i have these two lines:..regularpolygon shape = new regularpolygon(numsides, sidelength);.        shape.menu();...numsides and sidelength were declared and initialized earlier in the testing class...so what i want to happen, is the tester class sends numsides and sidelength to the second constructor and use it in that class. but it only uses the default constructor, which therefor ruins the whole rest of the program. can somebody help me?..for those of you who want to see more of my code: here you go..public double vertexangle().    {.        system.out.println(""the vertex angle method: "" + mynumsides);// prints out 5.        system.out.println(""the vertex angle method: "" + mysidelength); // prints out 30..        double vertexangle;.        vertexangle = ((mynumsides - 2.0) / mynumsides) * 180.0;.        return vertexangle;.    }//end method vertexangle..public void menu().{.    system.out.println(mynumsides); // prints out what the user puts in.    system.out.println(mysidelength); // prints out what the user puts in.    gotographic();.    calcr(mynumsides, mysidelength);.    calcr(mynumsides, mysidelength);.    print(); .}// end menu...this is my entire tester class:..public static void main(string[] arg).{.    int numsides;.    double sidelength;.    scanner keyboard = new scanner(system.in);..    system.out.println(""welcome to the regular polygon program!"");.    system.out.println();..    system.out.print(""enter the number of sides of the polygon ==> "");.    numsides = keyboard.nextint();.    system.out.println();..    system.out.print(""enter the side length of each side ==> "");.    sidelength = keyboard.nextdouble();.    system.out.println();..    regularpolygon shape = new regularpolygon(numsides, sidelength);.    shape.menu();.}//end main...for testing it i sent it numsides 4 and sidelength 100."\n'
Label: 1
Question:  b'"blank code slow skin detection this code changes the color space to lab and using a threshold finds the skin area of an image. but it\'s ridiculously slow. i don\'t know how to make it faster ?    ..from colormath.color_objects import *..def skindetection(img, treshold=80, color=[255,20,147]):..    print img.shape.    res=img.copy().    for x in range(img.shape[0]):.        for y in range(img.shape[1]):.            rgbimg=rgbcolor(img[x,y,0],img[x,y,1],img[x,y,2]).            labimg=rgbimg.convert_to(\'lab\', debug=false).            if (labimg.lab_l > treshold):.                res[x,y,:]=color.            else: .                res[x,y,:]=img[x,y,:]..    return res"\n'
Label: 3
Question:  b'"option and validation in blank i want to add a new option on my system where i want to add two text files, both rental.txt and customer.txt. inside each text are id numbers of the customer, the videotape they need and the price...i want to place it as an option on my code. right now i have:...add customer.rent return.view list.search.exit...i want to add this as my sixth option. say for example i ordered a video, it would display the price and would let me confirm the price and if i am going to buy it or not...here is my current code:..  import blank.io.*;.    import blank.util.arraylist;.    import static blank.lang.system.out;..    public class rentalsystem{.    static bufferedreader input = new bufferedreader(new inputstreamreader(system.in));.    static file file = new file(""file.txt"");.    static arraylist<string> list = new arraylist<string>();.    static int rows;..    public static void main(string[] args) throws exception{.        introduction();.        system.out.print(""nn"");.        login();.        system.out.print(""nnnnnnnnnnnnnnnnnnnnnn"");.        introduction();.        string repeat;.        do{.            loadfile();.            system.out.print(""nwhat do you want to do?nn"");.            system.out.print(""n                    - - - - - - - - - - - - - - - - - - - - - - -"");.            system.out.print(""nn                    |     1. add customer    |   2. rent return |n"");.            system.out.print(""n                    - - - - - - - - - - - - - - - - - - - - - - -"");.            system.out.print(""nn                    |     3. view list       |   4. search      |n"");.            system.out.print(""n                    - - - - - - - - - - - - - - - - - - - - - - -"");.            system.out.print(""nn                                             |   5. exit        |n"");.            system.out.print(""n                                              - - - - - - - - - -"");.            system.out.print(""nnchoice:"");.            int choice = integer.parseint(input.readline());.            switch(choice){.                case 1:.                    writedata();.                    break;.                case 2:.                    rentdata();.                    break;.                case 3:.                    viewlist();.                    break;.                case 4:.                    search();.                    break;.                case 5:.                    system.out.println(""goodbye!"");.                    system.exit(0);.                default:.                    system.out.print(""invalid choice: "");.                    break;.            }.            system.out.print(""ndo another task? [y/n] "");.            repeat = input.readline();.        }while(repeat.equals(""y""));..        if(repeat!=""y"") system.out.println(""ngoodbye!"");..    }..    public static void writedata() throws exception{.        system.out.print(""nname: "");.        string cname = input.readline();.        system.out.print(""address: "");.        string add = input.readline();.        system.out.print(""phone no.: "");.        string pno = input.readline();.        system.out.print(""rental amount: "");.        string ramount = input.readline();.        system.out.print(""tapenumber: "");.        string tno = input.readline();.        system.out.print(""title: "");.        string title = input.readline();.        system.out.print(""date borrowed: "");.        string dborrowed = input.readline();.        system.out.print(""due date: "");.        string ddate = input.readline();.        createline(cname, add, pno, ramount,tno, title, dborrowed, ddate);.        rentdata();.    }..    public static void createline(string name, string address, string phone , string rental, string tapenumber, string title, string borrowed, string due) throws exception{.        filewriter fw = new filewriter(file, true);.        fw.write(""nname: ""+name + ""naddress: "" + address +""nphone no.: ""+ phone+""nrentalamount: ""+rental+""ntape no.: ""+ tapenumber+""ntitle: ""+ title+""ndate borrowed: ""+borrowed +""ndue date: ""+ due+"":rn"");.        fw.close();.    }..    public static void loadfile() throws exception{.        try{.            list.clear();.            fileinputstream fstream = new fileinputstream(file);.            bufferedreader br = new bufferedreader(new inputstreamreader(fstream));.            rows = 0;.            while( br.ready()).            {.                list.add(br.readline());.                rows++;.            }.            br.close();.        } catch(exception e){.            system.out.println(""list not yet loaded."");.        }.    }..    public static void viewlist(){.        system.out.print(""n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"");.        system.out.print("" |list of all costumers|"");.        system.out.print(""~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"");.        for(int i = 0; i <rows; i++){.            system.out.println(list.get(i));.        }.    }.        public static void rentdata()throws exception.    {   system.out.print(""n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"");.        system.out.print("" |rent data list|"");.        system.out.print(""~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"");.        system.out.print(""nenter customer name: "");.        string cname = input.readline();.        system.out.print(""date borrowed: "");.        string dborrowed = input.readline();.        system.out.print(""due date: "");.        string ddate = input.readline();.        system.out.print(""return date: "");.        string rdate = input.readline();.        system.out.print(""rent amount: "");.        string ramount = input.readline();..        system.out.print(""you pay:""+ramount);...    }.    public static void search()throws exception.    {   system.out.print(""n~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"");.        system.out.print("" |search costumers|"");.        system.out.print(""~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"");.        system.out.print(""nenter costumer name: "");.        string cname = input.readline();.        boolean found = false;..        for(int i=0; i < rows; i++){.            string temp[] = list.get(i).split("","");..            if(cname.equals(temp[0])){.            system.out.println(""search result:nyou are "" + temp[0] + "" from "" + temp[1] + "".""+ temp[2] + "".""+ temp[3] + "".""+ temp[4] + "".""+ temp[5] + "" is "" + temp[6] + "".""+ temp[7] + "" is "" + temp[8] + ""."");.                found = true;.            }.        }..        if(!found){.            system.out.print(""no results."");.        }..    }..        public static boolean evaluate(string uname, string pass){.        if (uname.equals(""admin"")&&pass.equals(""12345"")) return true;.        else return false;.    }..    public static string login()throws exception{.        bufferedreader input=new bufferedreader(new inputstreamreader(system.in));.        int counter=0;.        do{.            system.out.print(""username:"");.            string uname =input.readline();.            system.out.print(""password:"");.            string pass =input.readline();..            boolean accept= evaluate(uname,pass);..            if(accept){.                break;.                }else{.                    system.out.println(""incorrect username or password!"");.                    counter ++;.                    }.        }while(counter<3);..            if(counter !=3) return ""login successful"";.            else return ""login failed"";.            }.        public static void introduction() throws exception{..        system.out.println(""                  - - - - - - - - - - - - - - - - - - - - - - - - -"");.        system.out.println(""                  !                  r e n t a l                  !"");.        system.out.println(""                   ! ~ ~ ~ ~ ~ !  =================  ! ~ ~ ~ ~ ~ !"");.        system.out.println(""                  !                  s y s t e m                  !"");.        system.out.println(""                  - - - - - - - - - - - - - - - - - - - - - - - - -"");.        }..}"\n'
Label: 1
Question:  b'"exception: dynamic sql generation for the updatecommand is not supported against a selectcommand that does not return any key i dont know what is the problem this my code : ..string nomtable;..datatable listeetablissementtable = new datatable();.datatable listeinteretstable = new datatable();.dataset ds = new dataset();.sqldataadapter da;.sqlcommandbuilder cmdb;..private void listeinterets_click(object sender, eventargs e).{.    nomtable = ""listeinteretstable"";.    d.cnx.open();.    da = new sqldataadapter(""select nome from offices"", d.cnx);.    ds = new dataset();.    da.fill(ds, nomtable);.    datagridview1.datasource = ds.tables[nomtable];.}..private void sauvgarder_click(object sender, eventargs e).{.    d.cnx.open();.    cmdb = new sqlcommandbuilder(da);.    da.update(ds, nomtable);.    d.cnx.close();.}"\n'
Label: 0
Question:  b'"parameter with question mark and super in blank, i\'ve come across a method that is formatted like this:..public final subscription subscribe(final action1<? super t> onnext, final action1<throwable> onerror) {.}...in the first parameter, what does the question mark and super mean?"\n'
Label: 1
Question:  b'call two objects wsdl the first time i got a very strange wsdl. ..i would like to call the object (interface - invoicecheck_out) do you know how?....i would like to call the object (variable) do you know how?..try to call (it`s ok)....try to call (how call this?)\n'
Label: 0
Question:  b"how to correctly make the icon for systemtray in blank using icon sizes of any dimension for systemtray doesn't look good overall. .what is the correct way of making icons for windows system tray?..screenshots: http://imgur.com/zsibwn9..icon: http://imgur.com/vsh4zo8\n"
Label: 0
Question:  b'"is there a way to check a variable that exists in a different script than the original one? i\'m trying to check if a variable, which was previously set to true in 2.py in 1.py, as 1.py is only supposed to continue if the variable is true...2.py..import os..completed = false..#some stuff here..completed = true...1.py..import 2 ..if completed == true.   #do things...however i get a syntax error at ..if completed == true"\n'
Label: 3
Question:  b'"blank control flow i made a number which asks for 2 numbers with blank and responds with  the corresponding message for the case. how come it doesnt work  for the second number ? .regardless what i enter for the second number , i am getting the message ""your number is in the range 0-10""...using system;.using system.collections.generic;.using system.linq;.using system.text;..namespace consoleapplication1.{.    class program.    {.        static void main(string[] args).        {.            string myinput;  // declaring the type of the variables.            int myint;..            string number1;.            int number;...            console.writeline(""enter a number"");.            myinput = console.readline(); //muyinput is a string  which is entry input.            myint = int32.parse(myinput); // myint converts the string into an integer..            if (myint > 0).                console.writeline(""your number {0} is greater than zero."", myint);.            else if (myint < 0).                console.writeline(""your number {0} is  less  than zero."", myint);.            else.                console.writeline(""your number {0} is equal zero."", myint);..            console.writeline(""enter another number"");.            number1 = console.readline(); .            number = int32.parse(myinput); ..            if (number < 0 || number == 0).                console.writeline(""your number {0} is  less  than zero or equal zero."", number);.            else if (number > 0 && number <= 10).                console.writeline(""your number {0} is  in the range from 0 to 10."", number);.            else.                console.writeline(""your number {0} is greater than 10."", number);..            console.writeline(""enter another number"");..        }.    }    .}"\n'
Label: 0
Question:  b'"credentials cannot be used for ntlm authentication i am getting org.apache.commons.httpclient.auth.invalidcredentialsexception: credentials cannot be used for ntlm authentication: exception in eclipse..whether it is possible mention eclipse to take system proxy settings directly?..public class httpgetproxy {.    private static final string proxy_host = ""proxy.****.com"";.    private static final int proxy_port = 6050;..    public static void main(string[] args) {.        httpclient client = new httpclient();.        httpmethod method = new getmethod(""https://kodeblank.org"");..        hostconfiguration config = client.gethostconfiguration();.        config.setproxy(proxy_host, proxy_port);..        string username = ""*****"";.        string password = ""*****"";.        credentials credentials = new usernamepasswordcredentials(username, password);.        authscope authscope = new authscope(proxy_host, proxy_port);..        client.getstate().setproxycredentials(authscope, credentials);..        try {.            client.executemethod(method);..            if (method.getstatuscode() == httpstatus.sc_ok) {.                string response = method.getresponsebodyasstring();.                system.out.println(""response = "" + response);.            }.        } catch (ioexception e) {.            e.printstacktrace();.        } finally {.            method.releaseconnection();.        }.    }.}...exception:...  dec 08, 2017 1:41:39 pm .          org.apache.commons.httpclient.auth.authchallengeprocessor selectauthscheme.         info: ntlm authentication scheme selected.       dec 08, 2017 1:41:39 pm org.apache.commons.httpclient.httpmethoddirector executeconnect.         severe: credentials cannot be used for ntlm authentication: .           org.apache.commons.httpclient.usernamepasswordcredentials.           org.apache.commons.httpclient.auth.invalidcredentialsexception: credentials .         cannot be used for ntlm authentication: .        enter code here .          org.apache.commons.httpclient.usernamepasswordcredentials.      at org.apache.commons.httpclient.auth.ntlmscheme.authenticate(ntlmscheme.blank:332).        at org.apache.commons.httpclient.httpmethoddirector.authenticateproxy(httpmethoddirector.blank:320).      at org.apache.commons.httpclient.httpmethoddirector.executeconnect(httpmethoddirector.blank:491).      at org.apache.commons.httpclient.httpmethoddirector.executewithretry(httpmethoddirector.blank:391).      at org.apache.commons.httpclient.httpmethoddirector.executemethod(httpmethoddirector.blank:171).      at org.apache.commons.httpclient.httpclient.executemethod(httpclient.blank:397).      at org.apache.commons.httpclient.httpclient.executemethod(httpclient.blank:323).      at httpgetproxy.main(httpgetproxy.blank:31).  dec 08, 2017 1:41:39 pm org.apache.commons.httpclient.httpmethoddirector processproxyauthchallenge.  info: failure authenticating with ntlm @proxy.****.com:6050"\n'
Label: 1

Die Beschriftungen sind 0 , 1 , 2 oder 3 . Um class_names welche davon welcher Zeichenfolgenbezeichnung entsprechen, können Sie die Eigenschaft class_names im Dataset überprüfen.

for i, label in enumerate(raw_train_ds.class_names):
  print("Label", i, "corresponds to", label)
Label 0 corresponds to csharp
Label 1 corresponds to java
Label 2 corresponds to javascript
Label 3 corresponds to python

Als Nächstes erstellen Sie einen Validierungs- und Testdatensatz. Sie werden die verbleibenden 1.600 Bewertungen aus dem Trainingssatz zur Validierung verwenden.

raw_val_ds = preprocessing.text_dataset_from_directory(
    train_dir,
    batch_size=batch_size,
    validation_split=0.2,
    subset='validation',
    seed=seed)
Found 8000 files belonging to 4 classes.
Using 1600 files for validation.
test_dir = dataset_dir/'test'
raw_test_ds = preprocessing.text_dataset_from_directory(
    test_dir, batch_size=batch_size)
Found 8000 files belonging to 4 classes.

Bereiten Sie den Datensatz für das Training vor

Als Nächstes standardisieren, tokenisieren und vektorisieren Sie die Daten mithilfe der Ebene " preprocessing.TextVectorization .

  • Standardisierung bezieht sich auf die Vorverarbeitung des Textes, normalerweise um Interpunktion oder HTML-Elemente zu entfernen, um das Dataset zu vereinfachen.

  • Tokenisierung bezieht sich auf das Aufteilen von Zeichenfolgen in Token (z. B. Aufteilen eines Satzes in einzelne Wörter durch Aufteilen in Leerzeichen).

  • Vektorisierung bezieht sich auf die Umwandlung von Token in Zahlen, damit sie in ein neuronales Netzwerk eingespeist werden können.

Alle diese Aufgaben können mit dieser Ebene ausgeführt werden. Weitere Informationen hierzu finden Sie im API-Dokument .

  • Die Standardstandardisierung konvertiert Text in Kleinbuchstaben und entfernt Interpunktion.

  • Der Standard-Tokenizer wird auf Leerzeichen aufgeteilt.

  • Der Standardvektorisierungsmodus ist int . Dies gibt ganzzahlige Indizes aus (einen pro Token). In diesem Modus können Modelle erstellt werden, die die Wortreihenfolge berücksichtigen. Sie können auch andere Modi wie binary , um Bag-of-Word-Modelle zu erstellen.

Sie werden zwei Modi erstellen, um mehr darüber zu erfahren. Zunächst verwenden Sie das binary , um ein Bag-of- binary Modell zu erstellen. Als nächstes verwenden Sie den int Modus mit einem 1D ConvNet.

VOCAB_SIZE = 10000

binary_vectorize_layer = TextVectorization(
    max_tokens=VOCAB_SIZE,
    output_mode='binary')

Für den int Modus müssen Sie zusätzlich zur maximalen Vokabulargröße eine explizite maximale Sequenzlänge festlegen, wodurch die Ebene Sequenzen auf genau sequence_length-Werte auffüllt oder abschneidet.

MAX_SEQUENCE_LENGTH = 250

int_vectorize_layer = TextVectorization(
    max_tokens=VOCAB_SIZE,
    output_mode='int',
    output_sequence_length=MAX_SEQUENCE_LENGTH)

Als Nächstes rufen Sie adapt auf, um den Status der Vorverarbeitungsebene an das Dataset adapt . Dadurch erstellt das Modell einen Index von Zeichenfolgen zu Ganzzahlen.

# Make a text-only dataset (without labels), then call adapt
train_text = raw_train_ds.map(lambda text, labels: text)
binary_vectorize_layer.adapt(train_text)
int_vectorize_layer.adapt(train_text)

Sehen Sie sich das Ergebnis der Verwendung dieser Ebenen zur Vorverarbeitung von Daten an:

def binary_vectorize_text(text, label):
  text = tf.expand_dims(text, -1)
  return binary_vectorize_layer(text), label
def int_vectorize_text(text, label):
  text = tf.expand_dims(text, -1)
  return int_vectorize_layer(text), label
# Retrieve a batch (of 32 reviews and labels) from the dataset
text_batch, label_batch = next(iter(raw_train_ds))
first_question, first_label = text_batch[0], label_batch[0]
print("Question", first_question)
print("Label", first_label)
Question tf.Tensor(b'"what is the difference between these two ways to create an element? var a = document.createelement(\'div\');..a.id = ""mydiv"";...and..var a = document.createelement(\'div\').id = ""mydiv"";...what is the difference between them such that the first one works and the second one doesn\'t?"\n', shape=(), dtype=string)
Label tf.Tensor(2, shape=(), dtype=int32)
print("'binary' vectorized question:", 
      binary_vectorize_text(first_question, first_label)[0])
'binary' vectorized question: tf.Tensor([[1. 1. 0. ... 0. 0. 0.]], shape=(1, 10000), dtype=float32)
print("'int' vectorized question:",
      int_vectorize_text(first_question, first_label)[0])
'int' vectorized question: tf.Tensor(
[[ 55   6   2 410 211 229 121 895   4 124  32 245  43   5   1   1   5   1
    1   6   2 410 211 191 318  14   2  98  71 188   8   2 199  71 178   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]], shape=(1, 250), dtype=int64)

Wie Sie oben sehen können, gibt der binary ein Array zurück, das angibt, welche Token mindestens einmal in der Eingabe vorhanden sind, während der int Modus jedes Token durch eine Ganzzahl ersetzt und so ihre Reihenfolge beibehält. Sie können das Token (Zeichenfolge) .get_vocabulary() , dem jede Ganzzahl entspricht, indem Sie .get_vocabulary() auf der Ebene aufrufen.

print("1289 ---> ", int_vectorize_layer.get_vocabulary()[1289])
print("313 ---> ", int_vectorize_layer.get_vocabulary()[313])
print("Vocabulary size: {}".format(len(int_vectorize_layer.get_vocabulary())))
1289 --->  roman
313 --->  source
Vocabulary size: 10000

Sie sind fast bereit, Ihr Modell zu trainieren. Als letzten Vorverarbeitungsschritt wenden Sie die zuvor erstellten TextVectorization Ebenen auf den Zug-, Validierungs- und Testdatensatz an.

binary_train_ds = raw_train_ds.map(binary_vectorize_text)
binary_val_ds = raw_val_ds.map(binary_vectorize_text)
binary_test_ds = raw_test_ds.map(binary_vectorize_text)

int_train_ds = raw_train_ds.map(int_vectorize_text)
int_val_ds = raw_val_ds.map(int_vectorize_text)
int_test_ds = raw_test_ds.map(int_vectorize_text)

Konfigurieren Sie das Dataset für die Leistung

Dies sind zwei wichtige Methoden, die Sie beim Laden von Daten verwenden sollten, um sicherzustellen, dass E / A nicht blockiert werden.

.cache() speichert Daten im Speicher, nachdem sie von der Festplatte geladen wurden. Dadurch wird sichergestellt, dass der Datensatz beim Training Ihres Modells nicht zu einem Engpass wird. Wenn Ihr Dataset zu groß ist, um in den Speicher zu passen, können Sie mit dieser Methode auch einen performanten On-Disk-Cache erstellen, der effizienter zu lesen ist als viele kleine Dateien.

.prefetch() überlappt die Datenvorverarbeitung und die Modellausführung während des Trainings.

Weitere Informationen zu beiden Methoden sowie zum Zwischenspeichern von Daten auf der Festplatte finden Sie im Handbuch zur Datenleistung .

AUTOTUNE = tf.data.AUTOTUNE

def configure_dataset(dataset):
  return dataset.cache().prefetch(buffer_size=AUTOTUNE)
binary_train_ds = configure_dataset(binary_train_ds)
binary_val_ds = configure_dataset(binary_val_ds)
binary_test_ds = configure_dataset(binary_test_ds)

int_train_ds = configure_dataset(int_train_ds)
int_val_ds = configure_dataset(int_val_ds)
int_test_ds = configure_dataset(int_test_ds)

Trainiere das Modell

Es ist Zeit, unser neuronales Netzwerk aufzubauen. Trainieren Sie für die binary vektorisierten Daten ein einfaches lineares Modell mit vielen Wörtern:

binary_model = tf.keras.Sequential([layers.Dense(4)])
binary_model.compile(
    loss=losses.SparseCategoricalCrossentropy(from_logits=True),
    optimizer='adam',
    metrics=['accuracy'])
history = binary_model.fit(
    binary_train_ds, validation_data=binary_val_ds, epochs=10)
Epoch 1/10
200/200 [==============================] - 2s 5ms/step - loss: 1.1210 - accuracy: 0.6522 - val_loss: 0.9196 - val_accuracy: 0.7775
Epoch 2/10
200/200 [==============================] - 0s 2ms/step - loss: 0.7795 - accuracy: 0.8206 - val_loss: 0.7541 - val_accuracy: 0.8031
Epoch 3/10
200/200 [==============================] - 0s 2ms/step - loss: 0.6279 - accuracy: 0.8630 - val_loss: 0.6677 - val_accuracy: 0.8150
Epoch 4/10
200/200 [==============================] - 0s 2ms/step - loss: 0.5344 - accuracy: 0.8856 - val_loss: 0.6139 - val_accuracy: 0.8263
Epoch 5/10
200/200 [==============================] - 0s 2ms/step - loss: 0.4684 - accuracy: 0.9045 - val_loss: 0.5770 - val_accuracy: 0.8331
Epoch 6/10
200/200 [==============================] - 0s 2ms/step - loss: 0.4181 - accuracy: 0.9156 - val_loss: 0.5501 - val_accuracy: 0.8381
Epoch 7/10
200/200 [==============================] - 0s 2ms/step - loss: 0.3779 - accuracy: 0.9280 - val_loss: 0.5299 - val_accuracy: 0.8400
Epoch 8/10
200/200 [==============================] - 0s 2ms/step - loss: 0.3446 - accuracy: 0.9347 - val_loss: 0.5142 - val_accuracy: 0.8413
Epoch 9/10
200/200 [==============================] - 0s 2ms/step - loss: 0.3164 - accuracy: 0.9430 - val_loss: 0.5019 - val_accuracy: 0.8413
Epoch 10/10
200/200 [==============================] - 0s 2ms/step - loss: 0.2920 - accuracy: 0.9481 - val_loss: 0.4920 - val_accuracy: 0.8406

Als Nächstes verwenden Sie die int vektorisierte Ebene, um ein 1D-ConvNet zu erstellen.

def create_model(vocab_size, num_labels):
  model = tf.keras.Sequential([
      layers.Embedding(vocab_size, 64, mask_zero=True),
      layers.Conv1D(64, 5, padding="valid", activation="relu", strides=2),
      layers.GlobalMaxPooling1D(),
      layers.Dense(num_labels)
  ])
  return model
# vocab_size is VOCAB_SIZE + 1 since 0 is used additionally for padding.
int_model = create_model(vocab_size=VOCAB_SIZE + 1, num_labels=4)
int_model.compile(
    loss=losses.SparseCategoricalCrossentropy(from_logits=True),
    optimizer='adam',
    metrics=['accuracy'])
history = int_model.fit(int_train_ds, validation_data=int_val_ds, epochs=5)
Epoch 1/5
200/200 [==============================] - 2s 5ms/step - loss: 1.1340 - accuracy: 0.5209 - val_loss: 0.7503 - val_accuracy: 0.6975
Epoch 2/5
200/200 [==============================] - 1s 3ms/step - loss: 0.6207 - accuracy: 0.7595 - val_loss: 0.5546 - val_accuracy: 0.7881
Epoch 3/5
200/200 [==============================] - 1s 3ms/step - loss: 0.3775 - accuracy: 0.8770 - val_loss: 0.4846 - val_accuracy: 0.8131
Epoch 4/5
200/200 [==============================] - 1s 3ms/step - loss: 0.2106 - accuracy: 0.9514 - val_loss: 0.4777 - val_accuracy: 0.8194
Epoch 5/5
200/200 [==============================] - 1s 3ms/step - loss: 0.1063 - accuracy: 0.9819 - val_loss: 0.4989 - val_accuracy: 0.8181

Vergleichen Sie die beiden Modelle:

print("Linear model on binary vectorized data:")
print(binary_model.summary())
Linear model on binary vectorized data:
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 4)                 40004     
=================================================================
Total params: 40,004
Trainable params: 40,004
Non-trainable params: 0
_________________________________________________________________
None
print("ConvNet model on int vectorized data:")
print(int_model.summary())
ConvNet model on int vectorized data:
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 64)          640064    
_________________________________________________________________
conv1d (Conv1D)              (None, None, 64)          20544     
_________________________________________________________________
global_max_pooling1d (Global (None, 64)                0         
_________________________________________________________________
dense_1 (Dense)              (None, 4)                 260       
=================================================================
Total params: 660,868
Trainable params: 660,868
Non-trainable params: 0
_________________________________________________________________
None

Bewerten Sie beide Modelle anhand der Testdaten:

binary_loss, binary_accuracy = binary_model.evaluate(binary_test_ds)
int_loss, int_accuracy = int_model.evaluate(int_test_ds)

print("Binary model accuracy: {:2.2%}".format(binary_accuracy))
print("Int model accuracy: {:2.2%}".format(int_accuracy))
250/250 [==============================] - 1s 3ms/step - loss: 0.5180 - accuracy: 0.8149
250/250 [==============================] - 1s 2ms/step - loss: 0.5193 - accuracy: 0.8111
Binary model accuracy: 81.49%
Int model accuracy: 81.11%

Exportieren Sie das Modell

Im obigen Code haben Sie die TextVectorization Ebene auf das Dataset angewendet, bevor Sie dem Modell Text TextVectorization haben. Wenn Sie Ihr Modell in die Lage TextVectorization , TextVectorization zu verarbeiten (z. B. um die Bereitstellung zu vereinfachen), können Sie die TextVectorization Ebene in Ihr Modell aufnehmen. Dazu können Sie mit den soeben trainierten Gewichten ein neues Modell erstellen.

export_model = tf.keras.Sequential(
    [binary_vectorize_layer, binary_model,
     layers.Activation('sigmoid')])

export_model.compile(
    loss=losses.SparseCategoricalCrossentropy(from_logits=False),
    optimizer='adam',
    metrics=['accuracy'])

# Test it with `raw_test_ds`, which yields raw strings
loss, accuracy = export_model.evaluate(raw_test_ds)
print("Accuracy: {:2.2%}".format(binary_accuracy))
250/250 [==============================] - 1s 4ms/step - loss: 0.5180 - accuracy: 0.8149
Accuracy: 81.49%

Jetzt kann Ihr Modell rohe Zeichenfolgen als Eingabe verwenden und mithilfe von model.predict eine Punktzahl für jedes Etikett model.predict . Definieren Sie eine Funktion, um das Etikett mit der maximalen Punktzahl zu finden:

def get_string_labels(predicted_scores_batch):
  predicted_int_labels = tf.argmax(predicted_scores_batch, axis=1)
  predicted_labels = tf.gather(raw_train_ds.class_names, predicted_int_labels)
  return predicted_labels

Führen Sie eine Inferenz für neue Daten durch

inputs = [
    "how do I extract keys from a dict into a list?",  # python
    "debug public static void main(string[] args) {...}",  # java
]
predicted_scores = export_model.predict(inputs)
predicted_labels = get_string_labels(predicted_scores)
for input, label in zip(inputs, predicted_labels):
  print("Question: ", input)
  print("Predicted label: ", label.numpy())
Question:  how do I extract keys from a dict into a list?
Predicted label:  b'python'
Question:  debug public static void main(string[] args) {...}
Predicted label:  b'java'

Wenn Sie die Textvorverarbeitungslogik in Ihr Modell aufnehmen, können Sie ein Modell für die Produktion exportieren, das die Bereitstellung vereinfacht und das Potenzial für Zug- / Testversatz verringert.

Es gibt einen Leistungsunterschied, den Sie berücksichtigen müssen, wenn Sie auswählen, wo Ihre TextVectorization Ebene TextVectorization werden soll. Wenn Sie es außerhalb Ihres Modells verwenden, können Sie beim Training auf der GPU eine asynchrone CPU-Verarbeitung und Pufferung Ihrer Daten durchführen. Wenn Sie Ihr Modell auf der GPU trainieren, möchten Sie wahrscheinlich diese Option verwenden, um die beste Leistung bei der Entwicklung Ihres Modells zu erzielen, und dann die TextVectorization-Ebene in Ihr Modell aufnehmen, wenn Sie bereit sind, sich auf die Bereitstellung vorzubereiten .

Besuchen Sie dieses Tutorial , um mehr über das Speichern von Modellen zu erfahren.

Beispiel 2: Vorhersage des Autors von Illiad-Übersetzungen

Im Folgenden finden Sie ein Beispiel für die Verwendung von tf.data.TextLineDataset zum Laden von Beispielen aus Textdateien und tf.text zum Vorverarbeiten der Daten. In diesem Beispiel verwenden Sie drei verschiedene englische Übersetzungen desselben Werks, Homers Illiade, und trainieren ein Modell, um den Übersetzer anhand einer einzelnen Textzeile zu identifizieren.

Laden Sie den Datensatz herunter und erkunden Sie ihn

Die Texte der drei Übersetzungen stammen von:

Die in diesem Lernprogramm verwendeten Textdateien wurden einigen typischen Vorverarbeitungsaufgaben unterzogen, z. B. dem Entfernen von Kopf- und Fußzeilen von Dokumenten, Zeilennummern und Kapiteltiteln. Laden Sie diese leicht munged Dateien lokal herunter.

DIRECTORY_URL = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'
FILE_NAMES = ['cowper.txt', 'derby.txt', 'butler.txt']

for name in FILE_NAMES:
  text_dir = utils.get_file(name, origin=DIRECTORY_URL + name)

parent_dir = pathlib.Path(text_dir).parent
list(parent_dir.iterdir())
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/cowper.txt
819200/815980 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/derby.txt
811008/809730 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/butler.txt
811008/807992 [==============================] - 0s 0us/step
[PosixPath('/home/kbuilder/.keras/datasets/facades.tar.gz'),
 PosixPath('/home/kbuilder/.keras/datasets/Giant Panda'),
 PosixPath('/home/kbuilder/.keras/datasets/derby.txt'),
 PosixPath('/home/kbuilder/.keras/datasets/flower_photos.tar.gz'),
 PosixPath('/home/kbuilder/.keras/datasets/YellowLabradorLooking_new.jpg'),
 PosixPath('/home/kbuilder/.keras/datasets/kandinsky5.jpg'),
 PosixPath('/home/kbuilder/.keras/datasets/spa-eng'),
 PosixPath('/home/kbuilder/.keras/datasets/iris_test.csv'),
 PosixPath('/home/kbuilder/.keras/datasets/butler.txt'),
 PosixPath('/home/kbuilder/.keras/datasets/cats_and_dogs.zip'),
 PosixPath('/home/kbuilder/.keras/datasets/flower_photos'),
 PosixPath('/home/kbuilder/.keras/datasets/image.jpg'),
 PosixPath('/home/kbuilder/.keras/datasets/cifar-10-batches-py.tar.gz'),
 PosixPath('/home/kbuilder/.keras/datasets/shakespeare.txt'),
 PosixPath('/home/kbuilder/.keras/datasets/facades'),
 PosixPath('/home/kbuilder/.keras/datasets/Fireboat'),
 PosixPath('/home/kbuilder/.keras/datasets/iris_training.csv'),
 PosixPath('/home/kbuilder/.keras/datasets/cowper.txt'),
 PosixPath('/home/kbuilder/.keras/datasets/jena_climate_2009_2016.csv.zip'),
 PosixPath('/home/kbuilder/.keras/datasets/cifar-10-batches-py'),
 PosixPath('/home/kbuilder/.keras/datasets/fashion-mnist'),
 PosixPath('/home/kbuilder/.keras/datasets/ImageNetLabels.txt'),
 PosixPath('/home/kbuilder/.keras/datasets/Red_sunflower'),
 PosixPath('/home/kbuilder/.keras/datasets/HIGGS.csv.gz'),
 PosixPath('/home/kbuilder/.keras/datasets/cats_and_dogs_filtered'),
 PosixPath('/home/kbuilder/.keras/datasets/mnist.npz'),
 PosixPath('/home/kbuilder/.keras/datasets/jena_climate_2009_2016.csv'),
 PosixPath('/home/kbuilder/.keras/datasets/spa-eng.zip')]

Laden Sie den Datensatz

Sie verwenden TextLineDataset , mit dem eintf.data.Dataset aus einer Textdatei erstellt wird, in der jedes Beispiel eine Textzeile aus der Originaldatei ist, während text_dataset_from_directory alle Inhalte einer Datei als ein einziges Beispiel behandelt. TextLineDataset ist nützlich für Textdaten, die hauptsächlich TextLineDataset sind (z. B. Gedichte oder Fehlerprotokolle).

Durchlaufen Sie diese Dateien und laden Sie jede in ihren eigenen Datensatz. Jedes Beispiel muss einzeln beschriftet werden. Verwenden tf.data.Dataset.map daher tf.data.Dataset.map , um auf jedes Beispiel eine tf.data.Dataset.map anzuwenden. Dies wird über jedes Beispiel im Dataset iterieren und Paare ( example, label ) zurückgeben.

def labeler(example, index):
  return example, tf.cast(index, tf.int64)
labeled_data_sets = []

for i, file_name in enumerate(FILE_NAMES):
  lines_dataset = tf.data.TextLineDataset(str(parent_dir/file_name))
  labeled_dataset = lines_dataset.map(lambda ex: labeler(ex, i))
  labeled_data_sets.append(labeled_dataset)

Als Nächstes kombinieren Sie diese beschrifteten Datensätze zu einem einzigen Datensatz und mischen ihn.

BUFFER_SIZE = 50000
BATCH_SIZE = 64
VALIDATION_SIZE = 5000
all_labeled_data = labeled_data_sets[0]
for labeled_dataset in labeled_data_sets[1:]:
  all_labeled_data = all_labeled_data.concatenate(labeled_dataset)

all_labeled_data = all_labeled_data.shuffle(
    BUFFER_SIZE, reshuffle_each_iteration=False)

Drucken Sie einige Beispiele wie zuvor aus. Der Datensatz wurde noch nicht gestapelt, daher entspricht jeder Eintrag in all_labeled_data einem Datenpunkt:

for text, label in all_labeled_data.take(10):
  print("Sentence: ", text.numpy())
  print("Label:", label.numpy())
Sentence:  b"the middle of the son of Phyleus' shield with his spear, setting on him"
Label: 2
Sentence:  b"One, prostrate at Achilles' feet, bewail'd"
Label: 1
Sentence:  b"There, face to face, with sinewy arms uprais'd,"
Label: 1
Sentence:  b'To whom Achilles thus with scornful glance;'
Label: 1
Sentence:  b'"Ulysses sage, Laertes\' high-born son,'
Label: 1
Sentence:  b'payment to one who had served him well. He would not give your father'
Label: 2
Sentence:  b'For loss of him, who might have been thy shield'
Label: 1
Sentence:  b'For virtuous qualities above the rest.'
Label: 0
Sentence:  b'revenge for the death of Amphimachus, and sent it whirling over the'
Label: 2
Sentence:  b'In battle slain thy sire shall mourn, or mine;'
Label: 0

Bereiten Sie den Datensatz für das Training vor

Anstatt die Keras TextVectorization Ebene zur Vorverarbeitung unseres Textdatensatzes zu verwenden, verwenden Sie jetzt dietf.text API , um die Daten zu standardisieren und zutf.text , ein Vokabular zu StaticVocabularyTable und StaticVocabularyTable zu verwenden, um Token Ganzzahlen StaticVocabularyTable , die dem Modell StaticVocabularyTable .

Während tf.text verschiedene Tokenizer bereitstellt, verwenden Sie den UnicodeScriptTokenizer um unser Dataset zu tokenisieren. Definieren Sie eine Funktion, um den Text in Kleinbuchstaben umzuwandeln und zu tokenisieren. Sie verwenden tf.data.Dataset.map , um die Tokenisierung auf das Dataset anzuwenden.

tokenizer = tf_text.UnicodeScriptTokenizer()
def tokenize(text, unused_label):
  lower_case = tf_text.case_fold_utf8(text)
  return tokenizer.tokenize(lower_case)
tokenized_ds = all_labeled_data.map(tokenize)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py:206: batch_gather (from tensorflow.python.ops.array_ops) is deprecated and will be removed after 2017-10-25.
Instructions for updating:
`tf.batch_gather` is deprecated, please use `tf.gather` with `batch_dims=-1` instead.

Sie können das Dataset durchlaufen und einige Beispiele mit Token ausdrucken.

for text_batch in tokenized_ds.take(5):
  print("Tokens: ", text_batch.numpy())
Tokens:  [b'the' b'middle' b'of' b'the' b'son' b'of' b'phyleus' b"'" b'shield'
 b'with' b'his' b'spear' b',' b'setting' b'on' b'him']
Tokens:  [b'one' b',' b'prostrate' b'at' b'achilles' b"'" b'feet' b',' b'bewail'
 b"'" b'd']
Tokens:  [b'there' b',' b'face' b'to' b'face' b',' b'with' b'sinewy' b'arms'
 b'uprais' b"'" b'd' b',']
Tokens:  [b'to' b'whom' b'achilles' b'thus' b'with' b'scornful' b'glance' b';']
Tokens:  [b'"' b'ulysses' b'sage' b',' b'laertes' b"'" b'high' b'-' b'born' b'son'
 b',']

Als Nächstes erstellen Sie ein Vokabular, indem Sie Token nach Häufigkeit sortieren und die obersten VOCAB_SIZE Token VOCAB_SIZE .

tokenized_ds = configure_dataset(tokenized_ds)

vocab_dict = collections.defaultdict(lambda: 0)
for toks in tokenized_ds.as_numpy_iterator():
  for tok in toks:
    vocab_dict[tok] += 1

vocab = sorted(vocab_dict.items(), key=lambda x: x[1], reverse=True)
vocab = [token for token, count in vocab]
vocab = vocab[:VOCAB_SIZE]
vocab_size = len(vocab)
print("Vocab size: ", vocab_size)
print("First five vocab entries:", vocab[:5])
Vocab size:  10000
First five vocab entries: [b',', b'the', b'and', b"'", b'of']

Um die Token in ganze Zahlen zu umwandeln, verwenden Sie die vocab auf einen erstellen StaticVocabularyTable . Sie vocab_size + 2 Token Ganzzahlen im Bereich [ 2 , vocab_size + 2 ] zu. Wie bei der TextVectorization Ebene ist 0 für das Auffüllen und 1 für das OOV-Token (Out-of-Vocabulary) reserviert.

keys = vocab
values = range(2, len(vocab) + 2)  # reserve 0 for padding, 1 for OOV

init = tf.lookup.KeyValueTensorInitializer(
    keys, values, key_dtype=tf.string, value_dtype=tf.int64)

num_oov_buckets = 1
vocab_table = tf.lookup.StaticVocabularyTable(init, num_oov_buckets)

Definieren Sie abschließend eine Funktion zum Standardisieren, Tokenisieren und Vektorisieren des Datensatzes mithilfe des Tokenizers und der Nachschlagetabelle:

def preprocess_text(text, label):
  standardized = tf_text.case_fold_utf8(text)
  tokenized = tokenizer.tokenize(standardized)
  vectorized = vocab_table.lookup(tokenized)
  return vectorized, label

Sie können dies an einem einzelnen Beispiel versuchen, um die Ausgabe anzuzeigen:

example_text, example_label = next(iter(all_labeled_data))
print("Sentence: ", example_text.numpy())
vectorized_text, example_label = preprocess_text(example_text, example_label)
print("Vectorized sentence: ", vectorized_text.numpy())
Sentence:  b"the middle of the son of Phyleus' shield with his spear, setting on him"
Vectorized sentence:  [   3  716    6    3   28    6 1595    5  166   14   11   63    2 2384
   22   16]

Führen Sie nun die Vorverarbeitungsfunktion für das Dataset mit tf.data.Dataset.map .

all_encoded_data = all_labeled_data.map(preprocess_text)

Teilen Sie den Datensatz in Zug und Test

Die Keras TextVectorization Ebene TextVectorization und TextVectorization auch die vektorisierten Daten. Das Auffüllen ist erforderlich, da die Beispiele in einem Stapel dieselbe Größe und Form haben müssen, die Beispiele in diesen Datensätzen jedoch nicht alle dieselbe Größe haben - jede Textzeile hat eine andere Anzahl von Wörtern.tf.data.Dataset unterstützt das Aufteilen undtf.data.Dataset -Datasets:

train_data = all_encoded_data.skip(VALIDATION_SIZE).shuffle(BUFFER_SIZE)
validation_data = all_encoded_data.take(VALIDATION_SIZE)
train_data = train_data.padded_batch(BATCH_SIZE)
validation_data = validation_data.padded_batch(BATCH_SIZE)

validation_data und train_data sind keine Sammlungen von ( example, label Paaren, sondern Sammlungen von Stapeln. Jeder Stapel ist ein Paar ( viele Beispiele , viele Beschriftungen ), die als Arrays dargestellt werden. Um zu zeigen:

sample_text, sample_labels = next(iter(validation_data))
print("Text batch shape: ", sample_text.shape)
print("Label batch shape: ", sample_labels.shape)
print("First text example: ", sample_text[0])
print("First label example: ", sample_labels[0])
Text batch shape:  (64, 20)
Label batch shape:  (64,)
First text example:  tf.Tensor(
[   3  716    6    3   28    6 1595    5  166   14   11   63    2 2384
   22   16    0    0    0    0], shape=(20,), dtype=int64)
First label example:  tf.Tensor(2, shape=(), dtype=int64)

Da wir 0 für das Auffüllen und 1 für OOV-Token (Out-of-Vocabulary) verwenden, hat sich die Größe des Vokabulars um zwei erhöht.

vocab_size += 2

Konfigurieren Sie die Datasets für eine bessere Leistung wie zuvor.

train_data = configure_dataset(train_data)
validation_data = configure_dataset(validation_data)

Trainiere das Modell

Sie können ein Modell für diesen Datensatz wie zuvor trainieren.

model = create_model(vocab_size=vocab_size, num_labels=3)
model.compile(
    optimizer='adam',
    loss=losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=['accuracy'])
history = model.fit(train_data, validation_data=validation_data, epochs=3)
Epoch 1/3
697/697 [==============================] - 28s 9ms/step - loss: 0.5208 - accuracy: 0.7643 - val_loss: 0.3767 - val_accuracy: 0.8394
Epoch 2/3
697/697 [==============================] - 3s 4ms/step - loss: 0.2795 - accuracy: 0.8854 - val_loss: 0.3676 - val_accuracy: 0.8510
Epoch 3/3
697/697 [==============================] - 3s 4ms/step - loss: 0.1885 - accuracy: 0.9282 - val_loss: 0.3995 - val_accuracy: 0.8474
loss, accuracy = model.evaluate(validation_data)

print("Loss: ", loss)
print("Accuracy: {:2.2%}".format(accuracy))
79/79 [==============================] - 1s 2ms/step - loss: 0.3995 - accuracy: 0.8474
Loss:  0.3994785249233246
Accuracy: 84.74%

Exportieren Sie das Modell

Damit unser Modell TextVectorization Zeichenfolgen als Eingabe verwenden kann, erstellen Sie eine TextVectorization Ebene, die dieselben Schritte wie unsere benutzerdefinierte Vorverarbeitungsfunktion ausführt. Da Sie bereits ein Vokabular trainiert haben, können Sie set_vocaublary anstatt es adapt wodurch ein neues Vokabular trainiert wird.

preprocess_layer = TextVectorization(
    max_tokens=vocab_size,
    standardize=tf_text.case_fold_utf8,
    split=tokenizer.tokenize,
    output_mode='int',
    output_sequence_length=MAX_SEQUENCE_LENGTH)
preprocess_layer.set_vocabulary(vocab)
export_model = tf.keras.Sequential(
    [preprocess_layer, model,
     layers.Activation('sigmoid')])

export_model.compile(
    loss=losses.SparseCategoricalCrossentropy(from_logits=False),
    optimizer='adam',
    metrics=['accuracy'])
# Create a test dataset of raw strings
test_ds = all_labeled_data.take(VALIDATION_SIZE).batch(BATCH_SIZE)
test_ds = configure_dataset(test_ds)
loss, accuracy = export_model.evaluate(test_ds)
print("Loss: ", loss)
print("Accuracy: {:2.2%}".format(accuracy))
79/79 [==============================] - 6s 9ms/step - loss: 0.5205 - accuracy: 0.7996
Loss:  0.5205461978912354
Accuracy: 79.96%

Der Verlust und die Genauigkeit des Modells für den codierten Validierungssatz und des exportierten Modells für den Rohvalidierungssatz sind erwartungsgemäß gleich.

Führen Sie eine Inferenz für neue Daten durch

inputs = [
    "Join'd to th' Ionians with their flowing robes,",  # Label: 1
    "the allies, and his armour flashed about him so that he seemed to all",  # Label: 2
    "And with loud clangor of his arms he fell.",  # Label: 0
]
predicted_scores = export_model.predict(inputs)
predicted_labels = tf.argmax(predicted_scores, axis=1)
for input, label in zip(inputs, predicted_labels):
  print("Question: ", input)
  print("Predicted label: ", label.numpy())
Question:  Join'd to th' Ionians with their flowing robes,
Predicted label:  1
Question:  the allies, and his armour flashed about him so that he seemed to all
Predicted label:  2
Question:  And with loud clangor of his arms he fell.
Predicted label:  0

Herunterladen weiterer Datensätze mithilfe von TensorFlow-Datensätzen (TFDS)

Sie können viele weitere Datensätze von TensorFlow- Datensätzen herunterladen. Als Beispiel laden Sie das IMDB Large Movie Review-Dataset herunter und trainieren damit ein Modell für die Stimmungsklassifizierung.

train_ds = tfds.load(
    'imdb_reviews',
    split='train',
    batch_size=BATCH_SIZE,
    shuffle_files=True,
    as_supervised=True)
val_ds = tfds.load(
    'imdb_reviews',
    split='train',
    batch_size=BATCH_SIZE,
    shuffle_files=True,
    as_supervised=True)

Drucken Sie einige Beispiele aus.

for review_batch, label_batch in val_ds.take(1):
  for i in range(5):
    print("Review: ", review_batch[i].numpy())
    print("Label: ", label_batch[i].numpy())
Review:  b'Mann photographs the Alberta Rocky Mountains in a superb fashion, and Jimmy Stewart and Walter Brennan give enjoyable performances as they always seem to do. <br /><br />But come on Hollywood - a Mountie telling the people of Dawson City, Yukon to elect themselves a marshal (yes a marshal!) and to enforce the law themselves, then gunfighters battling it out on the streets for control of the town? <br /><br />Nothing even remotely resembling that happened on the Canadian side of the border during the Klondike gold rush. Mr. Mann and company appear to have mistaken Dawson City for Deadwood, the Canadian North for the American Wild West.<br /><br />Canadian viewers be prepared for a Reefer Madness type of enjoyable howl with this ludicrous plot, or, to shake your head in disgust.'
Label:  0
Review:  b"This was an absolutely terrible movie. Don't be lured in by Christopher Walken or Michael Ironside. Both are great actors, but this must simply be their worst role in history. Even their great acting could not redeem this movie's ridiculous storyline. This movie is an early nineties US propaganda piece. The most pathetic scenes were those when the Columbian rebels were making their cases for revolutions. Maria Conchita Alonso appeared phony, and her pseudo-love affair with Walken was nothing but a pathetic emotional plug in a movie that was devoid of any real meaning. I am disappointed that there are movies like this, ruining actor's like Christopher Walken's good name. I could barely sit through it."
Label:  0
Review:  b'This is the kind of film for a snowy Sunday afternoon when the rest of the world can go ahead with its own business as you descend into a big arm-chair and mellow for a couple of hours. Wonderful performances from Cher and Nicolas Cage (as always) gently row the plot along. There are no rapids to cross, no dangerous waters, just a warm and witty paddle through New York life at its best. A family film in every sense and one that deserves the praise it received.'
Label:  1
Review:  b"This is a film which should be seen by anybody interested in, effected by, or suffering from an eating disorder. It is an amazingly accurate and sensitive portrayal of bulimia in a teenage girl, its causes and its symptoms. The girl is played by one of the most brilliant young actresses working in cinema today, Alison Lohman, who was later so spectacular in 'Where the Truth Lies'. I would recommend that this film be shown in all schools, as you will never see a better on this subject. Alison Lohman is absolutely outstanding, and one marvels at her ability to convey the anguish of a girl suffering from this compulsive disorder. If barometers tell us the air pressure, Alison Lohman tells us the emotional pressure with the same degree of accuracy. Her emotional range is so precise, each scene could be measured microscopically for its gradations of trauma, on a scale of rising hysteria and desperation which reaches unbearable intensity. Mare Winningham is the perfect choice to play her mother, and does so with immense sympathy and a range of emotions just as finely tuned as Lohman's. Together, they make a pair of sensitive emotional oscillators vibrating in resonance with one another. This film is really an astonishing achievement, and director Katt Shea should be proud of it. The only reason for not seeing it is if you are not interested in people. But even if you like nature films best, this is after all animal behaviour at the sharp edge. Bulimia is an extreme version of how a tormented soul can destroy her own body in a frenzy of despair. And if we don't sympathise with people suffering from the depths of despair, then we are dead inside."
Label:  1
Review:  b'Okay, you have:<br /><br />Penelope Keith as Miss Herringbone-Tweed, B.B.E. (Backbone of England.) She\'s killed off in the first scene - that\'s right, folks; this show has no backbone!<br /><br />Peter O\'Toole as Ol\' Colonel Cricket from The First War and now the emblazered Lord of the Manor.<br /><br />Joanna Lumley as the ensweatered Lady of the Manor, 20 years younger than the colonel and 20 years past her own prime but still glamourous (Brit spelling, not mine) enough to have a toy-boy on the side. It\'s alright, they have Col. Cricket\'s full knowledge and consent (they guy even comes \'round for Christmas!) Still, she\'s considerate of the colonel enough to have said toy-boy her own age (what a gal!)<br /><br />David McCallum as said toy-boy, equally as pointlessly glamourous as his squeeze. Pilcher couldn\'t come up with any cover for him within the story, so she gave him a hush-hush job at the Circus.<br /><br />and finally:<br /><br />Susan Hampshire as Miss Polonia Teacups, Venerable Headmistress of the Venerable Girls\' Boarding-School, serving tea in her office with a dash of deep, poignant advice for life in the outside world just before graduation. Her best bit of advice: "I\'ve only been to Nancherrow (the local Stately Home of England) once. I thought it was very beautiful but, somehow, not part of the real world." Well, we can\'t say they didn\'t warn us.<br /><br />Ah, Susan - time was, your character would have been running the whole show. They don\'t write \'em like that any more. Our loss, not yours.<br /><br />So - with a cast and setting like this, you have the re-makings of "Brideshead Revisited," right?<br /><br />Wrong! They took these 1-dimensional supporting roles because they paid so well. After all, acting is one of the oldest temp-jobs there is (YOU name another!)<br /><br />First warning sign: lots and lots of backlighting. They get around it by shooting outdoors - "hey, it\'s just the sunlight!"<br /><br />Second warning sign: Leading Lady cries a lot. When not crying, her eyes are moist. That\'s the law of romance novels: Leading Lady is "dewy-eyed."<br /><br />Henceforth, Leading Lady shall be known as L.L.<br /><br />Third warning sign: L.L. actually has stars in her eyes when she\'s in love. Still, I\'ll give Emily Mortimer an award just for having to act with that spotlight in her eyes (I wonder . did they use contacts?)<br /><br />And lastly, fourth warning sign: no on-screen female character is "Mrs." She\'s either "Miss" or "Lady."<br /><br />When all was said and done, I still couldn\'t tell you who was pursuing whom and why. I couldn\'t even tell you what was said and done.<br /><br />To sum up: they all live through World War II without anything happening to them at all.<br /><br />OK, at the end, L.L. finds she\'s lost her parents to the Japanese prison camps and baby sis comes home catatonic. Meanwhile (there\'s always a "meanwhile,") some young guy L.L. had a crush on (when, I don\'t know) comes home from some wartime tough spot and is found living on the street by Lady of the Manor (must be some street if SHE\'s going to find him there.) Both war casualties are whisked away to recover at Nancherrow (SOMEBODY has to be "whisked away" SOMEWHERE in these romance stories!)<br /><br />Great drama.'
Label:  0

Sie können jetzt die Daten vorverarbeiten und ein Modell wie zuvor trainieren.

Bereiten Sie den Datensatz für das Training vor

vectorize_layer = TextVectorization(
    max_tokens=VOCAB_SIZE,
    output_mode='int',
    output_sequence_length=MAX_SEQUENCE_LENGTH)

# Make a text-only dataset (without labels), then call adapt
train_text = train_ds.map(lambda text, labels: text)
vectorize_layer.adapt(train_text)
def vectorize_text(text, label):
  text = tf.expand_dims(text, -1)
  return vectorize_layer(text), label
train_ds = train_ds.map(vectorize_text)
val_ds = val_ds.map(vectorize_text)
# Configure datasets for performance as before
train_ds = configure_dataset(train_ds)
val_ds = configure_dataset(val_ds)

Trainiere das Modell

model = create_model(vocab_size=VOCAB_SIZE + 1, num_labels=1)
model.summary()
Model: "sequential_5"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_2 (Embedding)      (None, None, 64)          640064    
_________________________________________________________________
conv1d_2 (Conv1D)            (None, None, 64)          20544     
_________________________________________________________________
global_max_pooling1d_2 (Glob (None, 64)                0         
_________________________________________________________________
dense_3 (Dense)              (None, 1)                 65        
=================================================================
Total params: 660,673
Trainable params: 660,673
Non-trainable params: 0
_________________________________________________________________
model.compile(
    loss=losses.BinaryCrossentropy(from_logits=True),
    optimizer='adam',
    metrics=['accuracy'])
history = model.fit(train_ds, validation_data=val_ds, epochs=3)
Epoch 1/3
391/391 [==============================] - 5s 9ms/step - loss: 0.5039 - accuracy: 0.6990 - val_loss: 0.3041 - val_accuracy: 0.8795
Epoch 2/3
391/391 [==============================] - 2s 4ms/step - loss: 0.2776 - accuracy: 0.8797 - val_loss: 0.1733 - val_accuracy: 0.9462
Epoch 3/3
391/391 [==============================] - 2s 4ms/step - loss: 0.1690 - accuracy: 0.9348 - val_loss: 0.0919 - val_accuracy: 0.9787
loss, accuracy = model.evaluate(val_ds)

print("Loss: ", loss)
print("Accuracy: {:2.2%}".format(accuracy))
391/391 [==============================] - 1s 2ms/step - loss: 0.0919 - accuracy: 0.9787
Loss:  0.09189144521951675
Accuracy: 97.87%

Exportieren Sie das Modell

export_model = tf.keras.Sequential(
    [vectorize_layer, model,
     layers.Activation('sigmoid')])

export_model.compile(
    loss=losses.SparseCategoricalCrossentropy(from_logits=False),
    optimizer='adam',
    metrics=['accuracy'])
# 0 --> negative review
# 1 --> positive review
inputs = [
    "This is a fantastic movie.",
    "This is a bad movie.",
    "This movie was so bad that it was good.",
    "I will never say yes to watching this movie.",
]
predicted_scores = export_model.predict(inputs)
predicted_labels = [int(round(x[0])) for x in predicted_scores]
for input, label in zip(inputs, predicted_labels):
  print("Question: ", input)
  print("Predicted label: ", label)
Question:  This is a fantastic movie.
Predicted label:  1
Question:  This is a bad movie.
Predicted label:  0
Question:  This movie was so bad that it was good.
Predicted label:  1
Question:  I will never say yes to watching this movie.
Predicted label:  1

Fazit

Dieses Tutorial zeigte verschiedene Möglichkeiten zum Laden und Vorverarbeiten von Text. Als nächsten Schritt können Sie zusätzliche Tutorials auf der Website durchsuchen oder neue Datensätze von TensorFlow- Datensätzen herunterladen.