ChatGPT火了,我連夜詳解AIGC原理,並實戰生成動漫頭像
theme: devui-blue
一、AIGC:人工智慧的新時代
AIGC可能會是人工智慧的下一個時代。儘管很多人還不知道AIGC是什麼。
當還有大批人宣揚所謂人工智慧、元宇宙都是概念,並且捂緊了口袋裡的兩百塊錢的時候,人工智慧行業發生了幾件小事。
首先,由人工智慧生成的一幅油畫作品《太空歌劇院》,獲得了藝術博覽會的冠軍。
有人感覺這有什麼?各種比賽多了去了,不就是獲個獎嗎?
可是這次不一樣,這是一幅油畫作品。在此之前,好的油畫只能由人工繪製。但是現在人工智慧也可以繪製了,而且還拿了冠軍。
很多人類藝術家仰天長嘆:“祖師爺啊,我這代人,在目睹藝術死亡!”
上一次藝術家們發出這樣的感慨,還是1839年,那時照相機問世了。
隨後,ChatGPT橫空出世。它真正做到了和人類“對答如流”。
它也可以做數學題、創作詩歌、寫小說,甚至也能寫程式碼、改bug。
再說一個震驚的報道:由ChatGPT生成的論文,拿下了全班的最高分。導師找到學生,說他上交的論文,段落簡潔、舉例恰當、論據嚴謹,甚至引經據典,古今中外,無所不通,教授不敢相信。學生瑟瑟發抖,他說,這是AI生成的,我只是想應付一下作業。
另外,美國89%的大學生都在用ChatGPT做作業。以色列總統在週三發表了一個演講,內容也是由人工智慧寫的。
現在全球都在討論,這類人工智慧技術,看似是帶來了巨大的商業價值,實則可能會給人類帶來嚴重的打擊。
這項技術就是AIGC(AI-Generated Content),翻譯成中文就是:人工智慧生成內容。
二、AIGC實戰:智慧生成動漫頭像
其實,利用人工智慧生成內容資源,很早就有了。記得有一年的雙十一購物節,上萬商家的廣告圖就是人工智慧生成的。只是現在的資料、演算法、硬體,這三個條件跟上了,這才讓它大放異彩,全民可用。
下面,我就以人工智慧生成動漫頭像為例,採用TensorFlow框架,從頭到尾給大家講一下AIGC的全過程。從原理到實現都很詳細,自己搭建,不調API,最後還帶專案原始碼的那種。
2.1 自動生成的意義
那位問了,自動生成內容有什麼好處?我的天啊,省事省力省錢吶!
下圖是一個遊戲中的海洋怪物。這便是人工智慧生成的。
這個大型遊戲叫《無人深空(No Man's Sky)》。號稱有1840億顆不同的星球,每個星球都有形態各異的怪物。這遊戲玩著得多爽啊?簡直就是視覺震撼吶。這些怪物要是人工來做,得招聘多少團隊,得花費多少時間?
用人工智慧生成的話,你可以像去網咖一樣,跟老闆說:嗨,多開幾臺機子!
當然,下面我要做的,沒有上面那樣地絢麗,甚至很原始。
但是過程類似,原理一致。效果就是AI生成動漫頭像:
2.2 自動生成的原理
AIGC的原理,用中國古話可以一語概括,那就是:讀書破萬卷,下筆如有神。
以生成貓咪的照片來舉例子,基本上AIGC的套路是下面這樣的:
首先,程式會設計兩個角色。一個叫生成器,一個叫鑑別器。
為了便於理解,我們稱呼生成器為藝術家,稱鑑別器為評論家。
藝術家負責生產內容,也就是畫貓。不要覺得擁有藝術家頭銜就很了不起,他可能和你一樣,畫不好。但是,就算亂畫,也得畫。於是,他就畫啊畫啊畫。
評論家呢,相比藝術家就負責一些了。他首先調研了大量貓的照片。他知道了貓的特點,有倆眼睛,有斑紋,有鬍鬚。這些特徵,他門兒清。
下面有意思的就來了。
藝術家這時還啥也不懂,隨便畫一筆,然後交給評論家,說畫好了。評論家拿旁光一看,瞬間就給否了。還給出一些意見,比如連輪廓都沒有。
藝術家一聽,你要輪廓那我就畫個輪廓。他加了個輪廓,又交了上去。評論家正眼一看,又給否了。不過,他還是給出一些意見,比如沒有鬍鬚。
就這樣,這倆人經過成千上萬次的友好磋商(評論家幸好是機器,不然心態崩了)。到後來,藝術家再拿來畫作,評論家會看好久,甚至拿出之前的照片挨個對照。最後他甚至還想詐一下藝術家,說你這是假的,藝術家說這次是真的。這時,評論家說好吧,我確實找不出問題了,我看也是真的。
至此,劇終。
搞一個造假的,再搞一個驗假的。然後訓練。隨著訓練加深,生成器在生成逼真影象方面逐漸變強,而鑑別器在辨別真偽上逐漸變強。當鑑別器無法區分真實圖片和偽造圖片時,訓練過程達到平衡。
上面這一套操作叫“生成對抗網路(Generative Adversarial Networks)”,簡稱叫GAN。我感覺,這套流程有點損,叫“幹”沒毛病。
2.3 資料準備
鑑別器是需要學習資料學習的。因此,我準備了20000張這樣的動漫頭像。
這些資料來自公開資料集Anime-Face-Dataset。資料檔案不大,274MB。你很容易就可以下載下來。這裡面有60000多張圖片。我用我的電腦訓練了一下。200分鐘過去了,一個epoch(把這些資料走一遍)都還沒有結束。那……稍微有效果得半個月之後了。
鄉親們,我這裡是AI小作坊,幹不了大的。於是乎,我就取了20000張圖片,並且將尺寸縮小到56×56畫素,再並且將彩色改為黑白。這樣一來,效率馬上就提高了。2分鐘就可以訓練一圈。如此,我訓練500圈也就是不到一天的時間。這是可以承受的。
上面處理圖片的程式碼:
``` python import cv2
存放源圖片的資料夾
dir_path = "anime" all_files=os.listdir(dir_path)
迴圈裡面的每一個檔案
for j,res_f_name in enumerate(all_files): res_f_path = dir_path+"/"+res_f_name # 讀入單通道 img1 = cv2.imread(res_f_path, 0) # 重新定義尺寸為56 img2=cv2.resize(img1,(56,56),interpolation=cv2.INTER_NEAREST) # 轉存到face資料夾下 cv2.imwrite("face/"+res_f_name, img2) # 超過20000退出迴圈 if j > 20000: break ```
相信加上註釋後,還是通俗易懂的。
檔案準備好了。儘管維度降了,但看起來,這個辨識度還過得去。
下一步要轉為TensorFlow格式化的資料集。
``` python from PIL import Image import pathlib import numpy as np
將圖片檔案轉為陣列
dir_path = "face" data_dir = pathlib.Path(dir_path) imgs = list(data_dir.glob('*.jpg')) img_arr = [] for img in imgs: img = Image.open(str(img)) img_arr.append(np.array(img)) train_images = np.array(img_arr) nums = train_images.shape[0]
train_images = train_images.reshape(nums, 56, 56, 1).astype('float32')
歸一化
train_images = (train_images - 127.5) / 127.5
轉為tensor格式
train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(nums).batch(256) ```
我很想說一下資料形態的變化過程。因為這和後續的神經網路結構有關聯。
首先,我們的圖片是56×56畫素,單通道。所以,圖片的資料陣列img_arr
的形狀是(20000, 56, 56)
。也就是說有20000組56×56的陣列。這裡面的數是int
型的,取值為0到255,表示從純黑到純白。
((20000, 56, 56),
array([[ 0, 0, 0, 0, 0, …… 0],
[ 18, 18, 126, 136, 175, …… 0],
[ 0, 0, 253, 253, 0, …… 0]], dtype=uint8))
然後用reshape
做一個升維,並且用astype('float32')
做一個浮點轉化。
升維的目的,是把每一個畫素點單獨提出來。因為每一個畫素點都需要作為學習和判斷的依據。浮點轉化則是為了提高精確度。
到這一步train_images
的形狀變為(20000, 56, 56, 1)
。
((20000, 56, 56, 1),
array([[ [0.], [0.], [0.], [0.], [0.], …… [0.]],
[ [18.], [18.], [126.], [136.], [175.], …… [0.]],
[ [0.], [0.], [253.], [253.], [0.], …… [0.]]], dtype=float32))
接著,進行一個神奇的操作。執行了(train_images-127.5)/127.5
這一步。這一步是什麼作用呢?我們知道,色值最大是255,那麼他的一半就是127.5。可以看出來,上一步操作就是把資料的區間格式化到[-1,1]
之間。
如果你足夠敏感的話,或許已經猜到。這是要使用tanh
,也就是雙曲正切作為啟用函式。
這個函式的輸出範圍也是在-1到1之間。也就是說,經過一系列計算,它最終會輸出-1到1之間的數值。這個數值我們反向轉化回去,也就是乘以127.5然後加上127.5,那就是AI生成畫素的色值。
2.4 生成器
首先我們來建立一個生成器。用於生成動漫頭像的圖片。
``` python def make_generator_model(): model = tf.keras.Sequential() model.add(layers.Dense(77256, use_bias=False, input_shape=(160,))) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU())
model.add(layers.Reshape((7, 7, 256)))
assert model.output_shape == (None, 7, 7, 256)
model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
assert model.output_shape == (None, 7, 7, 128)
model.add(layers.BatchNormalization())
model.add(layers.LeakyReLU())
……
model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
assert model.output_shape == (None, 56, 56, 1)
return model
生成一個試試
generator = make_generator_model() noise = tf.random.normal([1, 160]) generated_image = generator(noise, training=False) ```
因為我最終會放出全部原始碼,所以這個地方省略了幾層相似的神經網路。
從結構上看,輸入層是大小為160的一維噪點資料。然後通過Conv2DTranspose
實現上取樣,一層傳遞一層,生成變化的影象。最終到輸出層,通過tanh
啟用函式,輸出56×56組資料。這將會是我們要的畫素點。
如果輸出一下,生成器生成的圖片。是下面這個樣子。
這沒錯,一開始生成的影象,就是隨機的畫素噪點。它只有一個確定項,那就是56×56畫素的尺寸。
這就可以了。它已經通過複雜的神經網路,生成圖片了。這個生成器有腦細胞,但剛出生,啥也不懂。
這就像是藝術家第一步能繪製線條了。如果想要畫好貓,那就得找評論家多去溝通。
2.5 鑑別器
我們來建立一個鑑別器。用於判斷一張動漫頭像是不是真的。
``` python def make_discriminator_model(): model = tf.keras.Sequential() model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[56, 56, 1])) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3))
model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
model.add(layers.LeakyReLU())
model.add(layers.Dropout(0.3))
model.add(layers.Flatten())
model.add(layers.Dense(1))
return model
鑑別上一個生成的噪點圖片generated_image試試
discriminator = make_discriminator_model() decision = discriminator(generated_image) ```
我們來看一下這個模型。它的輸入形狀是(56, 56, 1)
。也就是前期準備的資料集的形狀。它的輸出形狀是(1)
,表示鑑別的結果。中間是兩層卷積,用於把輸入向輸出聚攏。採用的是LeakyReLU
啟用函式。
我們把生成器生成的那個噪點圖,鑑別一下,看看啥效果。
tf.Tensor([[0.00207942]], shape=(1, 1), dtype=float32)
看這個輸出結果,數值極小,表示可能性極低。
我們只是建立了一個空的模型。並沒有訓練。它這時就判斷出了不是動漫頭像。倒不是因為它智慧,而是它看啥都是假的。它現在也是個小白。
下面就該訓練訓練了。
2.6 訓練資料
開練!GAN!
``` python cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
def discriminator_loss(real_output, fake_output): real_loss = cross_entropy(tf.ones_like(real_output), real_output) fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output) total_loss = real_loss + fake_loss return total_loss
def generator_loss(fake_output): return cross_entropy(tf.ones_like(fake_output), fake_output)
…… @tf.function def train_step(images):
noise = tf.random.normal([BATCH_SIZE, noise_dim])
with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
generated_images = generator(noise, training=True)
real_output = discriminator(images, training=True)
fake_output = discriminator(generated_images, training=True)
gen_loss = generator_loss(fake_output)
disc_loss = discriminator_loss(real_output, fake_output)
gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)
gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)
generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))
discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))
for epoch in range(500): for image_batch in dataset: train_step(image_batch) ```
同樣,我還是隻放出了部分關鍵程式碼。不然影響你的閱讀。最後我會開源這個專案,不要著急。
我們來分析原理,一定要反覆看,精彩和燒腦程度堪比《三國演義》。我連圖片都不敢加,怕打斷你的思緒。
首先看損失函式。
演算法訓練的一個途徑,就是讓損失函式的值越變越小。損失函式表示差距,預測的差距和實際差距縮小,表示預測變準。
先看一下生成器的損失函式。位置在程式碼中的generator_loss
部分。它返回兩個資料之間的差距。第一個數是造假的結果fake_output
,這個結果是鑑別器給的。另一個數據是標準的成功結果。隨著訓練的進行,演算法框架會讓這個函式的值往小了變。那其實就是讓生成器預測出來的資料,同鑑別器判斷出來的結果,兩者之間的差距變得越來越小。這一番操作,也就是讓框架留意,如果整體趨勢是生成器欺騙鑑別器的能力增強,那就加分。
再看鑑別器的損失函式。也就是程式碼中的discriminator_loss
函式。它這裡稍微複雜一些。我們看到它的值是real_loss
加fake_loss
,是兩項損失值的總和。real_loss
是real_output
和標準答案的差距。fake_loss
是fake_output
和標準答案的差距。
那這兩個值又是怎麼來的呢?得去train_step
函式裡看。real_output
是鑑別器對訓練資料的判斷。fake_loss
是鑑別器對生成器造假結果的判斷。看到這裡,我感嘆人工智慧的心機之重。它什麼都要。
隨著大量學習資料的迴圈,它告訴人工智慧框架,它要鍛鍊自己對現有學習材料鑑別的能力。如果自己猜對了學習資料,也就是那20000張動漫頭像。請提醒我,我要調整自己的見識,修改內部引數。程式碼中定義的training=True
,意思就是可隨著訓練自動調節引數。
同時,伴著它學習現有資料的過程中,它還要實踐。它還要去判斷生成器是不是造假了。它也告訴框架,我要以我現在學到的鑑別能力,去判斷那小子造的圖假不假。
因為人工智慧要想辦法讓損失函式變小。因此得讓fake_loss
的值變小,才能保證discriminator_loss
整體變小。於是,框架又去找生成器。告訴它,鑑別器又學習了一批新知識,現在人家識別造假的能力增強了。不過,我可以偷偷地告訴你,它學了這個還有那個。這麼一來,生成器造假的本領,也增強了。
如此迴圈往復。框架相當於一個“挑唆者”。一邊讓鑑別器提高鑑別能力,一邊也告訴生成器如何實現更高階的造假。最終,世間所有的知識,兩方全部都學到了。鑑別器再也沒有新的知識可以學習。生成器的造假,鑑別器全部認可,也不需要再有新的造假方案。所有防偽知識全透明。
這時AIGC就成功了。
2.7 自動生成
我對20000張動漫圖片訓練了500輪。每一輪都列印一個九宮格的大頭貼。最終我們可以看到這500輪的演變效果。這張圖大約25秒,只播放一遍(如果放完了,拖出來再看),需要耐心看。
從動態圖看,整體趨勢是往畫面更清晰的方向發展的。
動圖比較快,我放上一張靜態圖。這完全是由人工智慧生成的圖片。
生成的程式碼很簡單。
``` python
載入訓練模型
if os.path.exists(checkpoint_dir+"/checkpoint"): checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
生成噪點作為輸入
test_input = tf.random.normal([1, 160])
交給生成器批量生成
predictions = generator(test_input, training=False)
取出一張結果
img_arr = predictions[0][:, :, 0]
將結果復原成圖片畫素色值資料
img_arr = img_arr* 127.5 + 127.5 ```
這是20000張圖,500輪訓練的效果。如果是百萬張圖片,幾千輪訓練呢?完全模擬很簡單。
專案開源地址:http://gitee.com/bigcool/gan_face
三、我們對AIGC該有的態度
AIGC的火爆出圈,引起全球的強烈討論。很多地方甚至打算立法,禁止學生使用它做作業。
雖然我說了這麼多。可能直到現在,依然有人覺得這是噱頭:我的工作這麼高階,是有靈魂的工作,人工智慧寫文章能比我通順?它還寫程式碼?它懂邏輯嗎?
國外有一個IT老哥叫David Gewirtz。他從1982年開始就寫程式碼,幹了40多年,也在蘋果公司待過。他以為用ChatGPT寫程式碼不會有啥驚喜。直到出現結果,卻嚇了他一大跳。
他的需求是給它老婆寫一個網站的外掛,用於挑選顧客,並滾動顧客的名字展示。這個需要幾天完成的工作,ChatGPT很快就完成了。而且程式碼純粹簡潔,極其規範。它還告訴你該操作哪個檔案,該如何部署。
現階段的人工智慧,可能沒有自己的思考,但是它有自己的計算。
你會寫文章,因為你讀過300多本書,並且記住了裡面20%的內容。這些讓你引以為傲。但是人工智慧,它讀過人類歷史上出現過的所有文獻,只要硬碟夠,它全部都能記住。而且它還不停對這些內容做分析、加工、整理:這裡和這裡有關聯,這裡和那裡都是在介紹橙子的營養成分。它通過計算,讓一切知識發生互聯互通。
當有人向人工智慧表示人類的擔憂時,人工智慧也給出了自己的回答。
我比較贊同它的觀點。
抱有其他觀點的人,主要擔心有了人工智慧,人類就會變得不動腦子了。時間長就廢了。
我覺得,這些都是工具。相機出來的時候,也是被畫家抵制,因為成像太簡單了。現在想想,太簡單有問題嗎?沒有!同樣的還有計算器之於算盤,打字之於手寫。甚至TensorFlow 2.0出來時,也被1.0的使用者抵制。他們說開發太簡單了,這讓開發者根本接觸不到底層。殊不知,1.0出來的時候,那些寫組合語言的開發者也想,他們墮落了,居然不操作暫存器。
其實,我感覺這些擔心是多餘的。每個時代都有會屬於自己時代的產物。就像現在我們不用毛筆寫字了,但是我們的祖先也沒有敲過鍵盤呀!可能下一個時代的人,連鍵盤也不敲了。
我是掘金@TF男孩,一位程式設計表演藝術家。
- 60分鐘的文心一言釋出會:我帶你5分鐘看完
- 程式設計師寫小說:我甘心當韭菜
- docx格式文件詳解:xml解析並用html還原
- 評論二則:年齡大了能否寫程式碼、上大學不喜歡IT專業咋整
- ChatGPT火了,我連夜詳解AIGC原理,並實戰生成動漫頭像
- 咱不吃虧,也不能過度自衛
- 兔年了,利用AI風格化實現剪紙兔、年畫兔、煙花兔
- 傻嗎?談男人們飯桌的拼酒現象
- 他扔出一張對話截圖:王總說的
- 老張說:快過年了,搞個AI作曲,用TensorFlow訓練midi檔案
- 為什麼大家都看中學歷?
- 年底了,裁兄弟當職員那哥們兒,如今咋樣了?
- 老張讓我用TensorFlow識別語音命令:前進、停止、左轉、右轉
- 在掘金第一次記錄失眠
- 十五分鐘簡介人工智慧,以聽懂為目的
- 認知史 12:積累階段,沒資格攀比
- 認知史 16:人過留名,雁過留聲
- 認知史 4:普遍共識
- 一文講通OCR文字識別原理與技術全流程(科普版)
- 認知史 7:選擇和努力