2023年的深度学习入门攻略(2) – 给openai API写前端

上一篇咱们说了,现在的大规模预练习模型技能还避免不了回答问题时出现低级过错。
可是其实,人类犯的逻辑过错也是层出不穷。

比方,有人就以为要想学好chatgpt,就要先学好Python。
其隐含的推理过程可能是这样的:

  • TensorFlow需求运用Python

  • PyTorch需求运用Python

  • Scikit-Learn需求运用Python

  • Hugging Face需求运用Python

  • 它们都是机器学习相关的库,它们都运用Python

=>

  • chatgpt也是机器学习相关的库,所以也需求运用Python

所以,需求学习Python

固然,运用传统深度学习结构基本上都要跟Python打交道。并且Python仅仅一层皮,为了练习和推理更头疼的是装置各种加快结构和库,比方CUDA和cudnn等库。并且这些库一般都不支撑最新的Python版别和CUDA版别。为了避免库打架,基本针对每一种首要结构就要搭一套Python虚拟环境。这些结构之间的CUDA库的需求不同的话还得装多个版别。

乃至假如你单机用的是相对小众的设备比方3090,4090之类的卡,通用的结构库还不见得支撑你的高端设备,还得自己从源码从头编译一个。

假如你还要搞跟CV相关的算法的话,那么你要装的库更多,很多本地库还抵触。还要装置适合CPU的并行计算库和数学库。Intel的相对成熟,假如你还买的是AMD的CPU,那继续适配吧。

诸如此类。

可是,现在一切的计算都是跑在openai的服务器上,你不管懂多少TensorFlow, PyTorch, JAX, Torch Dynamo, Torch Inductor, Trition, OpenMP, CUDA, Vulkan, TVM, LLVM MLIR等等通天本领都用不上。

现在能做的事情,基本上便是依照openai API的格式拼几个字符串和json串,发给openai的服务器,然后解析从openai服务器回来的状况码和成果的json串。

没错,这跟深度学习结构没有任何相似之处,这便是纯纯的前端干的活儿。任何言语只需有HTTP客户端库,再配上一个输入框和一个显现的文本框,就齐活了。

正因为仅仅HTTP API的封装,所以调用chatgpt不仅有官方的python库和node.js库,还有Java,Go,Kotlin,Swift,R,C#等各种言语的封装,很多言语还不只一个版别。不管是在命令行,网页里,小程序里,Android运用,iOS运用,Windows桌面运用,Unity游戏里等各种客户端里运用都非常便利。

伪装成Python库:10行搞定一切

openai将它们的API封装在了一个Python库里面,咱们能够像调用Python库相同去调用。这样也是有意义的,能够用来跟本地的其他结构进行协作。

装置老一套,pip:pip install openai
不需求conda,没有版别的强需求。不需求CUDA,不需求MKL,Windows下不需求MinGW,… :)

然后去openai注册一个API key。

import openai
openai.api_key = '你的API key'
completion = openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
    {"role": "user", "content": "生成用Python调用openai API的示例代码"}
  ]
)
print(completion.choices[0].message.content)

然后运转就能够了,只需你的网络连接没问题,就能够像网页相同看到chatgpt相同的成果了。

运转成果如下:

import openai
import pprint
# 设置你的 API 密钥,这儿需求调用 API 才能正常运转
openai.api_key = "YOUR_API_KEY"
# 创立一个 OpenAI GPT-3 模型实例
model_engine = "text-davinci-002"
model = openai.Model(model_engine)
# 界说一个prompt(即生成文本的起点)
prompt = "The quick brown fox"
# 调用 openai API 生成文本
response = model.generate(
  prompt=prompt,
  temperature=0.5,
  max_tokens=100,
  n=1,
  stop=None,
)
# 将回来的成果打印出来
pprint.pprint(response.choices[0].text)

到本文写作的2023年4月4日,gpt-3.5-turbo是最强大并且最划算的模型。其它的API,模型和办法,效果和费用都不如这一个。所以,要不要学惯用text-davinci-003等其它模型全看兴趣了,它们不能提供更强的才能了。

有的同学表明,上面的句子看不懂,怎么办?
太好办了,把上面的代码发给openai的API,让chatgpt来给咱们解说:

import openai
openai.api_key = '你的API key'
str1 = """
解释一下下面的代码是作什么用的?
completion = openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
    {"role": "user", "content": "生成用Python调用openai API的示例代码"}
  ]
)
print(completion.choices[0].message.content)
"""
completion = openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
    {"role": "user", "content": str1}
  ]
)
print(completion.choices[0].message.content)

这是openai api给咱们回来的解说:

这段代码是运用OpenAI API中的Chat API来生成一个自然言语对话的示例。它指定了要运用的练习模型为"gpt-3.5-turbo",并且设置了一个包含一条用户音讯的对话历史记录。这个对话历史记录是一个字典,其中包含两个键:"role""content"。这个对话历史记录被传递
给ChatCompletion.create()办法,以生成一条完整的对话。最后,代码打印出了OpenAI回来的答复的内容。

详细玩法的例子

跨言语程序翻译

比方咱们想把刚才调用openai的代码翻译成kotlin的,以便在Android运用里用。就让openai API帮咱们翻译:

import openai
openai.api_key = '你的API Key'
str1 = """
翻译成Kotlin
completion = openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
    {"role": "user", "content": "生成用Python调用openai API的示例代码"}
  ]
)
print(completion.choices[0].message.content)
"""
completion = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": str1}
    ]
)
print(completion.choices[0].message.content)

生成代码如下:

var completion = ChatCompletion.create(
  model = "gpt-3.5-turbo",
  messages = listOf(
    Message(role = "user", content = "生成用Python调用openai API的示例代码")
  )
)
println(completion.choices[0].message.content)

翻译成Swift,咱们自己改句子,我就不写了,成果如下:

var completion = try! openai.ChatCompletion.create(
  model: "gpt-3.5-turbo",
  messages: [
    .init(role: "user", content: "生成用Python调用openai API的示例代码")
  ]
)
print(completion.choices[0].message.content)

让它帮咱们翻译成Go言语:

package main
import (
        "fmt"
        "github.com/openai/go-api"
)
func main() {
        client := openai.NewClient("YOUR_API_KEY")
        prompt := []openai.ChatMessage{
                {Role: "user", Text: "生成用Python调用openai API的示例代码"},
        }
        chatOpts := &openai.ChatOpts{
                Model:       "davinci",
                Prompt:      &prompt,
                MaxTokens:   openai.Int(64),
                Temperature: openai.Float32(0.6),
        }
        resp, err := client.CreateChat(chatOpts)
        if err != nil {
                fmt.Println(err)
                return
        }
        message := resp.Choices[0].Text
        fmt.Println(message)
}

咱们发现,Go的翻译它用的是老模型davnici,咱们教它一下新的python API用法,然后让它翻译成Go的:

str1 = """
调用openai chat api的官方例子如下:
import openai
openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Who won the world series in 2020?"},
        {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
        {"role": "user", "content": "Where was it played?"}
    ]
)
chat api的API地址为:https://api.openai.com/v1/chat/completions
请依据此生成用Go言语调用的例程
"""
completion = openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
    {"role": "user", "content": str1}
  ]
)
print(completion.choices[0].message.content)
```python
生成的代码成果如下:
```go
package main
import (
        "bytes"
        "encoding/json"
        "fmt"
        "net/http"
)
type Message struct {
        Role    string `json:"role"`
        Content string `json:"content"`
}
type ChatRequest struct {
        Model    string    `json:"model"`
        Messages []Message `json:"messages"`
}
type ChatResponse struct {
        ID      string `json:"id"`
        Created int64  `json:"created"`
        Model   string `json:"model"`
        Object  string `json:"object"`
}
func main() {
        url := "https://api.openai.com/v1/chat/completions"
        req := ChatRequest{
                Model: "gpt-3.5-turbo",
                Messages: []Message{
                        {Role: "system", Content: "You are a helpful assistant."},
                        {Role: "user", Content: "Who won the world series in 2020?"},
                        {Role: "assistant", Content: "The Los Angeles Dodgers won the World Series in 2020."},
                        {Role: "user", Content: "Where was it played?"},
                },
        }
        payloadBytes, err := json.Marshal(req)
        if err != nil {
                fmt.Println("Error:", err)
                return
        }
        body := bytes.NewReader(payloadBytes)
        req, err := http.NewRequest("POST", url, body)
        if err != nil {
                fmt.Println("Error:", err)
                return
        }
        req.Header.Set("Content-Type", "application/json")
        req.Header.Set("Authorization", "Bearer [API_KEY]") // Replace [API_KEY] with your OpenAI API key
        client := http.Client{}
        resp, err := client.Do(req)
        if err != nil {
                fmt.Println("Error:", err)
                return
        }
        defer resp.Body.Close()
        var chatResp ChatResponse
        decoder := json.NewDecoder(resp.Body)
        if err := decoder.Decode(&chatResp); err != nil {
                fmt.Println("Error:", err)
                return
        }
        fmt.Println("ID:", chatResp.ID)
}

修正代码bug

仍是老办法,prompt就写修正代码bug:

str1 = """
修正下面代码的bug:
```javas
    private StringBuffer encoder(String arg) {
        if (arg == null) {
            arg = "";
        }
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            md5.update(arg.getBytes(SysConstant.charset));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return toHex(md5.digest());
    }

“””

completion = openai.ChatCompletion.create(
model=”gpt-3.5-turbo”,
messages=[
{“role”: “user”, “content”: str1}
]
)

print(completion.choices[0].message.content)


输出如下:
===========================================
以下是修正后的代码:
```java
private StringBuffer encoder(String arg) {
    if (arg == null) {
        arg = "";
    }
    StringBuffer hexString = new StringBuffer();
    try {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md5.digest(arg.getBytes(StandardCharsets.UTF_8));
        for (byte b : messageDigest) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return hexString;
}

修正的bug如下:

  1. 运用了StringBuffer,在多线程下是线程安全的;
  2. 在处理字节数组转换为16进制字符串时,选用了更简略的方式;
  3. 选用了Java 7中引入的StandardCharsets.UTF_8代替原有的SysConstant.charset,运用Java规范库中的字符集;
  4. 捕捉NoSuchAlgorithmException反常,避免产生过错。

==========================================

写摘要

仍是老办法,写prompt.

str1 = """
下面一段文字的首要观念是什么:
I have a dream that one day this nation will rise up and live out the true meaning of its creed: "We hold these truths to be self-evident, that all men are created equal."
I have a dream that one day on the red hills of Georgia, the sons of former slaves and the sons of former slave owners will be able to sit down together at the table of brotherhood.
I have a dream that one day even the state of Mississippi, a state sweltering with the heat of injustice, sweltering with the heat of oppression, will be transformed into an oasis of freedom and justice.
I have a dream that my four little children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character.
I have a dream today!
I have a dream that one day, down in Alabama, with its vicious racists, with its governor having his lips dripping with the words of "interposition" and "nullification" -- one day right there in Alabama little black boys and black girls will be able to join hands with little white boys and white girls as sisters and brothers.
I have a dream today!
I have a dream that one day every valley shall be exalted, and every hill and mountain shall be made low, the rough places will be made plain, and the crooked places will be made straight; "and the glory of the Lord shall be revealed and all flesh shall see it together."
"""
completion = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": str1}
    ]
)
print(completion.choices[0].message.content)

输出如下:

The main point of this text is that the speaker has a dream for racial equality and justice, where people of different races can come together, and discrimination is eradicated.

还能够找关键字:

str1 = """
下面一段话的关键字:
We introduce LLaMA, a collection of foundation language models ranging from 7B to 65B parameters. We train our models on trillions of tokens, and show that it is possible to train state-of-the-art models using publicly available datasets exclusively, without resorting to proprietary and inaccessible datasets. In particular, LLaMA-13B outperforms GPT-3 (175B) on most benchmarks, and LLaMA- 65B is competitive with the best models, Chinchilla-70B and PaLM-540B. We release all our models to the research community.
"""
completion = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": str1}
    ]
)
print(completion.choices[0].message.content)

输出如下:

LLaMA, language models, parameters, trillions of tokens, state-of-the-art models, publicly available datasets, GPT-3, benchmarks, Chinchilla-70B, PaLM-540B, research community.

数学推导

比方咱们给出皮亚诺正义的5条正义,让gpt 3.5帮咱们界说加法和乘法两种操作:

str1 = """
依据下面5条正义,界说加法和乘法两种操作:
榜首,0是一个自然数
第二,任何自然数n都有一个自然数Suc(n)作为它的后继
第三,0不是任何自然数的后继
第四,后继函数是单一的,即,假如Suc(m)=Suc(n),则m=n.
第五,令Q为关于自然数的一个性质。假如0具有性质Q,并且 假如自然数n具有性质Q,则Suc(n)也具有性质Q,那么一切自然数n都有性质Q
"""
completion = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": str1}
    ]
)
print(completion.choices[0].message.content)

输出如下:

加法界说:
关于任何自然数n,界说加法操作+如下:
n+0=n (依据榜首正义)
n+Suc(m)=Suc(n+m) (依据第二、四正义)
乘法界说:
关于任何自然数n,界说乘法操作*如下:
n*0=0 (依据榜首正义)
n*Suc(m)=n*m+n (依据第二、四正义)

补全API – Completion

补全API的才能本质上跟Chat API没有太大的区别。因为不必指令人物了,比起Chat API能够更简练一点。

咱们来看一个例子:

code1 = '请给林肯传记列一个提纲'
completion = openai.Completion.create(
    model="text-davinci-003",
    prompt=code1,
    max_tokens=2048,
    temperature=1
)
print(completion.choices[0].text)

输出如下:

一、林肯的童年阅历
(1)出身环境
(2)家庭教育和兄弟姐妹
(3)小时候的日子
二、林肯的教育发展
(1)接受过的教育
(2)取得的成就
三、林肯的政治生涯
(1)职务和重大成果
(2)有影响力的言论
四、林肯受追捧的原因
(1)实践诠释真理
(2)立场稳健无私
(3)支持奴隶解放

text-davinci-003是根据最新的gpt 3.5的,才能较强而速度较慢的一个模型,假如想用更快可是质量差一点的能够选用更弱一些的根据gpt 3的text-curie-001,text-babbage-001和text-ada-001。他们的才能顺次递减。

在现在这个时刻,text-davinci-003是比gpt-3.5-turbo要贵一点的,请注意关注下预算。

另外,gpt4现在只要在Chat API上才有。所以便是让咱们知道有Completion这个API就好。现在不管是才能上(gpt4)仍是预算上(gpt-3.5-turbo)都是Chat API占优。

小结

从现在这个时点看,基本上只学习ChatCompletion一个API就足够用了。功能全靠Prompt来指定。