
什么是GPT-4?完整指南
from tensorflow.keras import datasets, layers, models
# 加載MNIST數(shù)據(jù)集
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()
# 對(duì)數(shù)據(jù)進(jìn)行歸一化處理,將像素值縮放到0到1之間
train_images, test_images = train_images / 255.0, test_images / 255.0
# 擴(kuò)展維度,使數(shù)據(jù)形狀符合卷積神經(jīng)網(wǎng)絡(luò)輸入要求(原本是 (60000, 28, 28) 變?yōu)?(60000, 28, 28, 1))
train_images = tf.expand_dims(train_images, -1)
test_images = tf.expand_dims(test_images, -1)
# 構(gòu)建卷積神經(jīng)網(wǎng)絡(luò)模型
model = models.Sequential()
# 第一個(gè)卷積層,32個(gè)卷積核,卷積核大小3x3,激活函數(shù)用ReLU,輸入形狀為 (28, 28, 1)
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
# 第二個(gè)卷積層
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
# 將卷積層輸出展平,以便連接全連接層
model.add(layers.Flatten())
# 全連接層,有128個(gè)神經(jīng)元,激活函數(shù)用ReLU
model.add(layers.Dense(128, activation='relu'))
# 輸出層,10個(gè)神經(jīng)元對(duì)應(yīng)10個(gè)數(shù)字類別,激活函數(shù)用softmax
model.add(layers.Dense(10, activation='softmax'))
# 編譯模型,指定優(yōu)化器、損失函數(shù)和評(píng)估指標(biāo)
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 訓(xùn)練模型
model.fit(train_images, train_labels, epochs=5, batch_size=64)
# 在測(cè)試集上評(píng)估模型
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f"測(cè)試準(zhǔn)確率: {test_acc}")
這個(gè)簡(jiǎn)單的 CNN 包含了卷積層(用于提取圖像特征)、池化層(降采樣層,進(jìn)行特征降維)以及全連接層(用于分類決策)等常見結(jié)構(gòu),通過在 MNIST 數(shù)據(jù)集上的訓(xùn)練和評(píng)估來展示其基本的工作流程。如果想用于其他圖像相關(guān)任務(wù),通常需要根據(jù)具體的圖像數(shù)據(jù)特點(diǎn)(比如圖像尺寸、類別數(shù)量等)來相應(yīng)地修改網(wǎng)絡(luò)結(jié)構(gòu)和訓(xùn)練參數(shù)等內(nèi)容。
下面來給大家講講這簡(jiǎn)單的CNN每一層的功能:
先說這卷積層吧,你可以把它想象成是一個(gè)能從圖像里找特點(diǎn)的小能手。它里面有好多那種小小的 “工具”,就好比一個(gè)個(gè)小篩子一樣,這些 “小篩子” 在圖像上呀,就像掃地似的,這掃掃那掃掃,從圖像的各個(gè)地方把那些有用的特點(diǎn)給找出來。
比如說圖像里物體的邊邊,或者是那種紋理啥的,通過這些 “小篩子” 一弄,原來的圖像就變成了另外一種有這些特點(diǎn)的圖啦,而且一個(gè)卷積層里可有好多個(gè)這樣的 “小篩子” 同時(shí)干活,這樣就能從好多不同的角度把圖像的各種特點(diǎn)都給找出來了。
再講講池化層,這個(gè)池化層的作用就是給前面找出來的那些特點(diǎn)降降量,為啥要降量呢?因?yàn)榍懊媾鰜淼哪切┨攸c(diǎn)信息太多啦,電腦處理起來就挺費(fèi)勁的,而且太多了也容易出問題呀。
那它咋降量呢?有兩種常見的辦法,一種就是找最大的,啥意思呢?就是在圖像的一小塊地方里,挑出那個(gè)數(shù)值最大的,然后就用這個(gè)最大的代表這一小塊地方,整個(gè)圖像都這么弄一遍,圖像就變小了,但是重要的特點(diǎn)還留著呢。還有一種辦法就是算平均,就是把那一小塊地方里的數(shù)值都加一塊兒,然后除以個(gè)數(shù),算出個(gè)平均數(shù)來代表這小塊地方,反正不管用哪種辦法吧,最后就是讓那些特點(diǎn)信息變少了,電腦處理起來就輕松多啦。
最后就是全連接層,這個(gè)全連接層呢,就像是個(gè)做決定的大管家一樣。它先把前面弄好的那些特點(diǎn)信息都整理到一塊兒,變成一條長(zhǎng)長(zhǎng)的 “信息鏈”,然后呢,它里面有好多小 “工作人員”,每個(gè) “工作人員” 都跟這 “信息鏈” 上的每個(gè)東西連著呢,它們按照自己的一套辦法算一算,最后就能告訴你這個(gè)圖像大概是屬于哪一類的啦,比如說這圖像里畫的是個(gè)啥東西呀,是貓還是狗之類的,它就能給個(gè)判斷出來。
這么一個(gè)簡(jiǎn)單的 CNN 呢,就是靠著這幾個(gè)部分互相配合,就能完成處理圖像的事了。
這里再給出一個(gè)Pytorch的實(shí)現(xiàn),這些代碼都可以直接使用:
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
# 定義數(shù)據(jù)預(yù)處理操作,將圖像轉(zhuǎn)換為張量并歸一化
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
# 加載MNIST訓(xùn)練數(shù)據(jù)集
trainset = torchvision.datasets.MNIST(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64,
shuffle=True, num_workers=2)
# 加載MNIST測(cè)試數(shù)據(jù)集
testset = torchvision.datasets.MNIST(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64,
shuffle=False, num_workers=2)
# 定義卷積神經(jīng)網(wǎng)絡(luò)模型結(jié)構(gòu)
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 3) # 輸入通道1(灰度圖像),32個(gè)卷積核,卷積核大小3x3
self.pool = nn.MaxPool2d(2, 2) # 最大池化層,池化核2x2
self.conv2 = nn.Conv2d(32, 64, 3) # 第二層卷積,輸入通道32,64個(gè)卷積核,卷積核大小3x3
self.fc1 = nn.Linear(64 * 12 * 12, 128) # 全連接層,將卷積層輸出展平后連接
self.fc2 = nn.Linear(128, 10) # 輸出層,對(duì)應(yīng)10個(gè)數(shù)字類別
def forward(self, x):
x = self.pool(torch.relu(self.conv1(x)))
x = self.pool(torch.relu(self.conv2(x)))
x = x.view(-1, 64 * 12 * 12)
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x
net = Net()
# 定義損失函數(shù)和優(yōu)化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.001)
# 訓(xùn)練網(wǎng)絡(luò)
for epoch in range(5): # 訓(xùn)練輪數(shù)可以按需調(diào)整
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 200 == 199:
print(f'[{epoch + 1}, {i + 1}] loss: {running_loss / 200}')
running_loss = 0.0
print('訓(xùn)練完成')
# 在測(cè)試集上測(cè)試網(wǎng)絡(luò)
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'測(cè)試集上的準(zhǔn)確率: {100 * correct / total}%')
下面講講RNN的實(shí)現(xiàn),老樣子依舊先給出一份代碼,然后我再根據(jù)這份代碼來講解RNN。
import tensorflow as tf
import numpy as np
# 1. 準(zhǔn)備模擬數(shù)據(jù)
# 設(shè)定時(shí)間序列的長(zhǎng)度,也就是每個(gè)樣本包含的數(shù)據(jù)點(diǎn)個(gè)數(shù)
time_steps = 10
# 批量大小,一次處理多少個(gè)樣本
batch_size = 32
# 輸入數(shù)據(jù)的維度,這里簡(jiǎn)單設(shè)為1(例如單變量的時(shí)間序列,像股票價(jià)格隨時(shí)間變化這種)
input_dim = 1
# 輸出數(shù)據(jù)的維度,同樣設(shè)為1,比如預(yù)測(cè)下一個(gè)時(shí)間點(diǎn)的值
output_dim = 1
# 生成模擬的輸入數(shù)據(jù),形狀為 (批量大小, 時(shí)間序列長(zhǎng)度, 輸入維度)
x = np.linspace(0, 20 * np.pi, time_steps * batch_size).reshape(batch_size, time_steps, input_dim)
# 對(duì)應(yīng)的輸出數(shù)據(jù)(這里簡(jiǎn)單以正弦函數(shù)為例生成目標(biāo)輸出,模擬預(yù)測(cè)下一個(gè)時(shí)間點(diǎn)的正弦值)
y = np.sin(x).reshape(batch_size, time_steps, output_dim)
# 2. 定義RNN的相關(guān)參數(shù)
# RNN單元中的隱藏單元數(shù)量,決定了模型的復(fù)雜度和對(duì)數(shù)據(jù)特征的學(xué)習(xí)能力
hidden_units = 32
# 3. 定義輸入占位符(placeholder),這是TensorFlow中用于輸入數(shù)據(jù)的一種機(jī)制
# 第一個(gè)None表示批量大小可以在運(yùn)行時(shí)動(dòng)態(tài)指定,后面的維度對(duì)應(yīng)時(shí)間序列長(zhǎng)度和輸入維度
X = tf.placeholder(tf.float32, [None, time_steps, input_dim])
# 同樣,為輸出數(shù)據(jù)定義占位符
Y = tf.placeholder(tf.float32, [None, time_steps, output_dim])
# 4. 定義RNN的權(quán)重和偏置(這是模型學(xué)習(xí)的參數(shù))
# 用于將輸入轉(zhuǎn)換到隱藏狀態(tài)的權(quán)重,形狀為 (輸入維度, 隱藏單元數(shù)量)
weights_input_hidden = tf.Variable(tf.random_normal([input_dim, hidden_units]))
# 隱藏狀態(tài)到隱藏狀態(tài)的權(quán)重(因?yàn)镽NN在每個(gè)時(shí)間步會(huì)用上一時(shí)刻的隱藏狀態(tài)更新當(dāng)前隱藏狀態(tài)),形狀為 (隱藏單元數(shù)量, 隱藏單元數(shù)量)
weights_hidden_hidden = tf.Variable(tf.random_normal([hidden_units, hidden_units]))
# 隱藏狀態(tài)到輸出的權(quán)重,形狀為 (隱藏單元數(shù)量, 輸出維度)
weights_hidden_output = tf.Variable(tf.random_normal([hidden_units, output_dim]))
# 輸入到隱藏層的偏置,形狀為 (隱藏單元數(shù)量,)
bias_input_hidden = tf.Variable(tf.zeros([hidden_units]))
# 隱藏層到隱藏層的偏置,形狀為 (隱藏單元數(shù)量,)
bias_hidden_hidden = tf.Variable(tf.zeros([hidden_units]))
# 隱藏層到輸出的偏置,形狀為 (輸出維度,)
bias_hidden_output = tf.Variable(tf.zeros([output_dim]))
# 5. 定義RNN的計(jì)算邏輯(這里手動(dòng)實(shí)現(xiàn)簡(jiǎn)單的循環(huán)計(jì)算過程)
def rnn_cell(inputs, hidden_state):
"""
這是定義單個(gè)時(shí)間步的RNN單元計(jì)算邏輯的函數(shù)。
參數(shù):
- inputs: 當(dāng)前時(shí)間步的輸入數(shù)據(jù),形狀為 (批量大小, 輸入維度)
- hidden_state: 上一個(gè)時(shí)間步的隱藏狀態(tài),形狀為 (批量大小, 隱藏單元數(shù)量)
返回值:
- new_hidden_state: 當(dāng)前時(shí)間步更新后的隱藏狀態(tài),形狀為 (批量大小, 隱藏單元數(shù)量)
"""
# 先將輸入數(shù)據(jù)進(jìn)行線性變換(乘以權(quán)重并加上偏置),為了和隱藏狀態(tài)進(jìn)行相加
input_transformed = tf.matmul(tf.reshape(inputs, [-1, input_dim]), weights_input_hidden) + bias_input_hidden
# 將變換后的輸入重塑為合適的形狀,方便后續(xù)計(jì)算
input_transformed = tf.reshape(input_transformed, [-1, hidden_units])
# 用上一時(shí)刻的隱藏狀態(tài)進(jìn)行線性變換
hidden_transformed = tf.matmul(hidden_state, weights_hidden_hidden) + bias_hidden_hidden
# 將變換后的輸入和隱藏狀態(tài)相加,得到新的隱藏狀態(tài)(這就是RNN的核心更新步驟)
new_hidden_state = tf.tanh(input_transformed + hidden_transformed)
return new_hidden_state
# 初始化第一個(gè)時(shí)間步的隱藏狀態(tài)為全0,形狀為 (批量大小, 隱藏單元數(shù)量)
initial_hidden_state = tf.zeros([batch_size, hidden_units])
# 循環(huán)遍歷每個(gè)時(shí)間步,逐步計(jì)算隱藏狀態(tài)
all_hidden_states = []
current_hidden_state = initial_hidden_state
for step in range(time_steps):
"""
這里通過循環(huán)來模擬RNN在每個(gè)時(shí)間步的計(jì)算過程。
"""
# 獲取當(dāng)前時(shí)間步的輸入數(shù)據(jù)
current_input = X[:, step, :]
# 使用rnn_cell函數(shù)計(jì)算當(dāng)前時(shí)間步的隱藏狀態(tài)更新
current_hidden_state = rnn_cell(current_input, current_hidden_state)
# 將當(dāng)前時(shí)間步的隱藏狀態(tài)保存下來,方便后續(xù)使用
all_hidden_states.append(current_hidden_state)
# 將所有時(shí)間步的隱藏狀態(tài)堆疊起來,形狀變?yōu)?(時(shí)間序列長(zhǎng)度, 批量大小, 隱藏單元數(shù)量)
all_hidden_states = tf.stack(all_hidden_states, axis=0)
# 調(diào)整隱藏狀態(tài)的順序,使其符合常規(guī)的 (批量大小, 時(shí)間序列長(zhǎng)度, 隱藏單元數(shù)量) 格式
all_hidden_states = tf.transpose(all_hidden_states, [1, 0, 2])
# 6. 計(jì)算輸出(根據(jù)最終的隱藏狀態(tài)得到預(yù)測(cè)的輸出)
# 取最后一個(gè)時(shí)間步的隱藏狀態(tài)(這里假設(shè)我們只關(guān)心最后時(shí)刻的輸出,實(shí)際應(yīng)用中可根據(jù)需求調(diào)整)
last_hidden_state = all_hidden_states[:, -1, :]
# 通過線性變換將隱藏狀態(tài)轉(zhuǎn)換為輸出數(shù)據(jù)
outputs = tf.matmul(last_hidden_state, weights_hidden_output) + bias_hidden_output
# 7. 定義損失函數(shù)(這里使用均方誤差,衡量預(yù)測(cè)值和真實(shí)值之間的差距)
loss = tf.reduce_mean(tf.square(outputs - Y))
# 8. 定義優(yōu)化器(這里使用Adam優(yōu)化器來更新模型的權(quán)重,讓損失函數(shù)盡量變小)
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
# 9. 創(chuàng)建會(huì)話并進(jìn)行訓(xùn)練
with tf.Session() as sess:
# 初始化所有變量
sess.run(tf.global_variables_initializer())
# 進(jìn)行多輪訓(xùn)練
for epoch in range(100):
_, current_loss = sess.run([optimizer, loss], feed_dict={X: x, Y: y})
if epoch % 10 == 0:
print(f'Epoch {epoch}: Loss = {current_loss}')
# 訓(xùn)練完成后,可以用訓(xùn)練好的模型進(jìn)行預(yù)測(cè)(這里簡(jiǎn)單示例,實(shí)際應(yīng)用中可按需擴(kuò)展)
prediction = sess.run(outputs, feed_dict={X: x})
print("預(yù)測(cè)結(jié)果示例:", prediction[0])
這就是數(shù)據(jù)進(jìn)入 RNN 的 “大門” ,就好比你要往一個(gè)機(jī)器里放東西,那輸入層就是放數(shù)據(jù)的地方。比如說我要是處理一句話,那就把這句話里的一個(gè)個(gè)字或者詞按照順序,一個(gè)一個(gè)送進(jìn)去,這就是最開始數(shù)據(jù)進(jìn)來的那一步。
隱藏層呢是 RNN 里很關(guān)鍵的部分。它里面有一個(gè)個(gè)小小的 “計(jì)算單元”,這些單元在每個(gè)時(shí)間步都會(huì)工作。啥是時(shí)間步呢?就是按順序處理數(shù)據(jù)的時(shí)候,每處理一個(gè)小部分就是一個(gè)時(shí)間步,像處理一句話里的每一個(gè)字的時(shí)候,處理每個(gè)字那就是一個(gè)時(shí)間步。
在每個(gè)時(shí)間步里,這個(gè)隱藏層的計(jì)算單元會(huì)拿到當(dāng)前輸入的數(shù)據(jù),然后還會(huì)參考上一個(gè)時(shí)間步自己算出來的一個(gè) “狀態(tài)”,把這倆東西結(jié)合起來,再經(jīng)過一番計(jì)算,得出一個(gè)新的 “狀態(tài)”,留著給下一個(gè)時(shí)間步接著用。就好像這個(gè)計(jì)算單元有個(gè)小 “記憶”,能記住之前算出來的東西,然后再接著往下算。
而且隱藏層里的這些計(jì)算單元會(huì)重復(fù)這樣的操作,一個(gè)時(shí)間步接著一個(gè)時(shí)間步地算下去,直到把咱送進(jìn)去的一整串?dāng)?shù)據(jù),比如一整句話,都處理完為止。
等隱藏層把所有的數(shù)據(jù)都處理完了,就輪到輸出層登場(chǎng)啦。輸出層就是根據(jù)隱藏層最后給出的那個(gè) “狀態(tài)”,來得出一個(gè)結(jié)果。比如說我要是想判斷一句話是啥意思,或者預(yù)測(cè)下一個(gè)字可能是啥,那輸出層就會(huì)根據(jù)隱藏層最后的那個(gè)狀態(tài),給出它的 “答案”,就像告訴咱們它琢磨出來這句話大概表達(dá)什么,或者覺得下一個(gè)字可能是啥樣的。
而現(xiàn)在模型庫(kù)都已經(jīng)內(nèi)置實(shí)現(xiàn)好了的RNN,要使用的話可以直接調(diào)用就行。
import tensorflow as tf
import numpy as np
# 生成一些模擬的時(shí)間序列數(shù)據(jù)示例(這里簡(jiǎn)單生成正弦函數(shù)相關(guān)的數(shù)據(jù)當(dāng)作示例)
time_steps = 20
batch_size = 32
input_dim = 1
output_dim = 1
# 生成輸入數(shù)據(jù)
x = np.linspace(0, 20 * np.pi, time_steps * batch_size).reshape(batch_size, time_steps, input_dim)
y = np.sin(x).reshape(batch_size, time_steps, output_dim)
# 定義RNN模型
model = tf.keras.Sequential([
tf.keras.layers.SimpleRNN(units=32, return_sequences=True, input_shape=(time_steps, input_dim)),
tf.keras.layers.Dense(units=output_dim)
])
# 編譯模型,指定優(yōu)化器、損失函數(shù)等
model.compile(optimizer='adam', loss='mean_squared_error')
# 訓(xùn)練模型
model.fit(x, y, epochs=10, batch_size=batch_size)
# 使用模型進(jìn)行預(yù)測(cè)(這里只是簡(jiǎn)單演示預(yù)測(cè)下一步,實(shí)際可以按需拓展)
new_x = np.linspace(20 * np.pi, 21 * np.pi, time_steps).reshape(1, time_steps, input_dim)
predicted_y = model.predict(new_x)
print(predicted_y
下面還有pytorch的調(diào)用:
import torch
import torch.nn as nn
# 超參數(shù)
input_size = 1
hidden_size = 32
num_layers = 1
output_size = 1
sequence_length = 20
# 生成模擬輸入數(shù)據(jù)(類似上面的示例,簡(jiǎn)單用正弦函數(shù)相關(guān)模擬)
x = torch.linspace(0, 20 * torch.pi, sequence_length).unsqueeze(1).unsqueeze(0).repeat(1, 1, 1)
y = torch.sin(x).squeeze(-1)
# 定義RNN模型類
class RNN(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size):
super(RNN, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
out, _ = self.rnn(x, h0)
out = self.fc(out[:, -1, :])
return out
rnn_model = RNN(input_size, hidden_size, num_layers, output_size)
# 定義損失函數(shù)和優(yōu)化器
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(rnn_model.parameters())
# 訓(xùn)練模型
for epoch in range(100):
optimizer.zero_grad()
output = rnn_model(x)
loss = criterion(output, y)
loss.backward()
optimizer.step()
if epoch % 10 == 0:
print(f'Epoch {epoch}: Loss {loss.item()}')
# 進(jìn)行簡(jiǎn)單預(yù)測(cè)(示例,可按需拓展)
new_x = torch.linspace(20 * torch.pi, 21 * torch.pi, sequence_length).unsqueeze(1).unsqueeze(0)
predicted_y = rnn_model(new_x)
print(predicted_y)
本文章轉(zhuǎn)載微信公眾號(hào)@Chal1ceAI
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)