近年来 AI 席卷全球,为此本文作者尝试了近 20 遍,最终用 C++ 创建了一个最简单易懂的生成式 AI 模型,供感兴趣的开发者参考。
原文链接:https://learncplusplus.org/how-to-create-simple-generative-ai-code-in-c/
作者 | Yilmaz Yoru
翻译 | 郑丽媛
短短一年多的时间里,AI 技术发展迅速,其中最引人瞩目的实现是 ChatGPT,它基于一种生成式 AI 技术。后来,我们又有了 GPT-4,GPT-5 也正在研发中。
在各种文本和图像公开测试中,人们普遍认为生成式 AI 是一项非常有创造力的技术。事实上,生成式 AI 是 AI 领域深度学习的一个分支,而所有这些看似神奇的技术背后,都要归功于大量的数学知识。在本文中,我们将编写一些非常简单的 C++ 代码,从给定的输入中学习,并生成随机输出。
什么是 AI?
人工智能(Artificial Intelligence)又称 AI,是指在机器中模拟人类智能,通过编程使其看起来像人类一样思考并模仿人类行为。这个术语也可用于任何表现出与人类思维相关的特征(如学习和解决问题)的机器。如果你想了解更多 AI 的相关术语,可以查阅我之前写的这篇文章:【AI 技术:C++ 人工智能入门】 (https://learncplusplus.org/ai-techs-introduction-to-artificial-intelligence-in-c/) 。
什么是生成式 AI?
生成式 AI(Generative AI、GenAI 或 GAI)是一种 AI 技术,通过生成模型来生成文本、图像、视频或其他数据。生成式 AI 模型通过接受给定的输入(比如文本、图像或数据集)进行学习,然后用生成式模型对这些输入进行训练,进而生成新的输出示例,甚至可以在没有任何人类指示的情况下生成新的内容。
一般来说,用户给出简单的指令(即「提示」),然后它就会根据这些指令和训练好的数据集生成一个新的样本。下面是一个简单的生成式 AI 模型的示例。
有一些生成式 AI 模型包括:生成对抗网络(GANs)、变分自编码器(VAEs)、自回归模型和变换器(Transformer)。
如何用 C++ 创建简单的生成式 AI 模型?
首先,我们来创建一个简单的生成式 AI,它可以通过给定的文本输入进行训练并从中学习。然后,我们可以创建一个生成模型来生成新的句子。在这里,我们将会有一个拥有映射的类,而该映射将保存字符串以及与每个字符串相关的字符串。下面,让我们来定义类和映射。
class GenerativeAI
{
private:
std::map<std::string, std::vector<std::string>> wordRel; // map to world releation
public:
}
我们可以通过将它们添加到字符串向量中来教授单词之间的关系。请注意,这是一个非常简单的学习示例,在真正的生成式 AI 模型中,你应该考虑更多细节,并且可以通过不同激活函数模型中的权重进行训练。更复杂的专业模型有更多层、偏置、隐藏神经元、过滤器、变换器(Transformer)、张量模型等。
接下来,让我们创建一个可以从给定文本中学习字符串类型的方法。例如,下面就是一个可以添加到公共部分 .learn_fromstring() 中的方法。
// Method to learn word relations from a given string
void learn_fromstring(const std::string &sentence)
{
std::istringstream iss(sentence);
std::vector<std::string> tokens{ std::istream_iterator<std::string>{iss},
std::istream_iterator<std::string>{} };
for (size_t i = 0; i < tokens.size() - 1; ++i) {
wordRel[tokens[i]].push_back(tokens[i + 1]);
}
}
在上述方法中,我们先将句子转换为 istringstream,然后从这个 stream 创建一个单词(token)向量。然后我们处理每个单词,并将下一个单词推到其映射的顺序中。例如,如果我们训练「I am」、「I was」、「I have」这类句子,它会把「I」映射和「am」、「was」、「have」添加到这个向量中。换句话说,它存储了「I」后面可能出现的下一个单词。实际上,这些关系是通过单词索引、权重、激活函数等建立起来的。例如,「am」通常与「I」搭配使用,因此它们之间的关系更密切,权重系数也应该更高。举一个简单的例子,我们先不考虑权重和激活函数。
现在,我们需要一个公共部分(public p)下的句子生成器,它可以通过考虑单词之间的关系来生成随机文本。首先,让我们举例说明生成模型,然后再进行解释。
// Method to generate a sequence of words based on learned relations
std::string sentence_generator(const std::string &startWord, int length)
{
std::string currentWord = startWord;
std::string sequence = currentWord;
for (int i = 0; i < length - 1; ++i)
{
if (wordRel.find(currentWord) == wordRel.end()) break;
std::vector<std::string> nextWords = wordRel[currentWord];
std::uniform_int_distribution<int> distribution(0, nextWords.size() - 1);
currentWord = nextWords[distribution(generator)];
sequence += " " + currentWord;
}
return sequence;
}
在上面的 sentence_generator() 方法中,我们先定义第一个单词(你可以选择将第一个使用的单词存储在一个仓库中,也可以随机选择)以及要生成的句子长度。然后,我们在循环中生成句子的中间单词。最后,它将返回新生成的序列句子。
就是这样,非常简单!
为了理解这个映射内部发生了什么,我们可以创建另一个方法来揭示单词之间的关系,如下所示。
// print the word releations
void print_word_relations()
{
std::cout << "Word Relations:" << std::endl;
for (const auto &pair : wordRel)
{
std::cout << pair.first << ":";
for (const auto &word : pair.second)
{
std::cout << " " << word;
}
std::cout << std::endl;
}
std::cout << std::endl;
}
现在我们可以开发主函数了。从这个类中创建一个新的生成式 AI 对象,用 learn_fromstring() 方法训练一些句子。根据给定的句子,输出训练后的单词关系,我们就可以创建许多新句子了,还可以在每个循环中用 sentence_generator() 方法创建一个新的字符串。下面是我训练了一些句子并生成 10 个新句子作为输出的过程。
int main()
{
GenerativeAI generator;
// Learn from sentences
generator.learn_fromstring("I am generative AI test example");
generator.learn_fromstring("I was a code");
generator.learn_fromstring("I can develop applications in C++");
generator.learn_fromstring("I have a generative code example");
generator.learn_fromstring("I should generate different sentences");
generator.learn_fromstring("I am easy with LearnCPlusPlus.org");
// Print word releations that learnt
generator.print_word_relations();
// Generate new sentences
for (int i = 0; i < 10; ++i)
{
std::cout << "Generated Sentence " << i + 1 << ": " << generator.sentence_generator( "I", 4+rnd()%2 ) << std::endl;
}
system("pause");
return 0;
}
有没有用 C++ 编写的简单生成式 AI 模型的完整示例?
有的,下面就是一个用 C++ 写的生成式 AI 的完整示例。
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <random>
std::random_device rnd;
std::mt19937 generator(rnd());
class GenerativeAI
{
private:
std::map<std::string, std::vector<std::string>> wordRel; // map to world releation
public:
// Method to learn word relations from a given string
void learn_fromstring(const std::string &sentence)
{
std::istringstream iss(sentence);
std::vector<std::string> tokens{ std::istream_iterator<std::string>{iss},
std::istream_iterator<std::string>{} };
for (size_t i = 0; i < tokens.size() - 1; ++i) {
wordRel[tokens[i]].push_back(tokens[i + 1]);
}
}
// Method to generate a sequence of words based on learned relations
std::string sentence_generator(const std::string &startWord, int length)
{
std::string currentWord = startWord;
std::string sequence = currentWord;
for (int i = 0; i < length - 1; ++i)
{
if (wordRel.find(currentWord) == wordRel.end()) break;
std::vector<std::string> nextWords = wordRel[currentWord];
std::uniform_int_distribution<int> distribution(0, nextWords.size() - 1);
currentWord = nextWords[distribution(generator)];
sequence += " " + currentWord;
}
return sequence;
}
// print the word releations
void print_word_relations()
{
std::cout << "Word Relations:" << std::endl;
for (const auto &pair : wordRel)
{
std::cout << pair.first << ":";
for (const auto &word : pair.second)
{
std::cout << " " << word;
}
std::cout << std::endl;
}
std::cout << std::endl;
}
};
int main()
{
GenerativeAI generator;
// Learn from sentences
generator.learn_fromstring("I am generative AI test example");
generator.learn_fromstring("I was a code");
generator.learn_fromstring("I can develop applications in C++");
generator.learn_fromstring("I have a generative code example");
generator.learn_fromstring("I should generate different sentences");
generator.learn_fromstring("I am easy with LearnCPlusPlus.org");
// Print word releations that learnt
generator.print_word_relations();
// Generate new sentences
for (int i = 0; i < 10; ++i)
{
std::cout << "Generated Sentence " << i + 1 << ": " << generator.sentence_generator( "I", 4+rnd()%2 ) << std::endl;
}
system("pause");
return 0;
}
结果如下:
最后需要说明一点:为了尽可能让大家易于理解和便于编码,我试着制作了大约 20 个不同的示例(包括一些来自 Copilot 的支持)并尽量将其简化,所以这应该是最简单易行的生成式 AI 模型了。
推荐阅读: