开始机器学习
- 机器学习的hello word–手写数字识别
- 语言–python
- 环境/平台–colab
colab介绍
谷歌免费的GPU资源,但是要科学上网,你有谷歌账号就行,具体使用方法自行百度。
cd需要加%才能使用
其他的加!使用
例如:
%cd drive/MyDrive/Colab\ Notebooks
!pwd
开始吧
1.导入一些库
import numpy as np #针对数组运算提供大量的数学函数库
import scipy.special #字符串切片用
import matplotlib.pyplot #画图
2.神经网络的结构
class class neuralNetwork:
#初始化函数
def __init__(self,inputnodes,hiddennodes,outputnodes,learningrate):
#训练函数
def train(self,inputs_list,targets_list):
#预测函数/查询函数 //喜欢怎么叫就怎么叫吧
def query(self,inputs_list):
3.函数的实现
- 3.1初始化函数:
因为是第一次,所以用一个非常简单的神经网络,只有三层,输入层1,隐藏层1,输出层1。
所以初始化时必须先定义一下这些层,同时需要定义学习率(learning rate),激活函数(activation function)。当然,还要初试化权重。
def __init__(self,inputnodes,hiddennodes,outputnodes,learningrate):
#neural number 每一层神经元数量
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
#learning rate 学习率 //我的理解是每次更新权重参数的步长
self.lr = learningrate
#weights 权重
self.wih=(np.random.rand(self.hnodes,self.inodes)-0.5)
self.who=(np.random.rand(self.onodes,self.hnodes)-0.5)
#activation function 激活函数 sigmoid
self.activation_function = lambda x:scipy.special.expit(x)
- 3.2训练函数:
优化方法是SGD(随机梯度下降法),计算梯度利用了反向传播法(直接从前往后算梯度非常复杂,而从后向前则简单很多 就是链式法则//具体理解请自行搜索)。
def train(self,inputs_list,targets_list):
#将输入转为二维矩阵
inputs = np.array(inputs_list,ndmin=2).T #输入的28*28个数
targets = np.array(targets_list,ndmin=2).T#标签 即正确的数
#前向传播
hidden_inputs = np.dot(self.wih,inputs)
hidden_outputs=self.activation_function(hidden_inputs)
final_inputs=np.dot(self.who,hidden_outputs)
final_outputs=self.activation_function(final_inputs)
#反向传播 更新权重
output_errors=targets - final_outputs
hidden_errors=np.dot(self.who.T,output_errors)
self.who += self.lr*np.dot((output_errors*final_outputs*(1.0-final_outputs)),np.transpose(hidden_outputs))
self.wih += self.lr * np.dot((hidden_errors * hidden_outputs * (1.0-hidden_outputs)),np.transpose(inputs))
pass
- 3.3查询函数:
这就很简单了,将数据输入,根据权重直接计算结果。
def query(self,inputs_list):
#将输入转为二维矩阵
inputs = np.array(inputs_list,ndmin=2).T
#print(inputs)
#输入乘以第一层权重
hidden_inputs = np.dot(self.wih,inputs)
#通过激活函数输出
hidden_outputs=self.activation_function(hidden_inputs)
#最后一层,和前面一样
final_inputs=np.dot(self.who,hidden_outputs)
final_outputs=self.activation_function(final_inputs)
return final_outputs
- 3.4整体神经网络代码:
import numpy as np
import scipy.special
import matplotlib.pyplot
class neuralNetwork:
def __init__(self,inputnodes,hiddennodes,outputnodes,learningrate):
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
self.lr = learningrate
#weights
self.wih=(np.random.rand(self.hnodes,self.inodes)-0.5)
self.who=(np.random.rand(self.onodes,self.hnodes)-0.5)
#activation function
self.activation_function = lambda x:scipy.special.expit(x)
pass
def train(self,inputs_list,targets_list):
#将输入转为二维矩阵
inputs = np.array(inputs_list,ndmin=2).T
targets = np.array(targets_list,ndmin=2).T
hidden_inputs = np.dot(self.wih,inputs)
hidden_outputs=self.activation_function(hidden_inputs)
final_inputs=np.dot(self.who,hidden_outputs)
final_outputs=self.activation_function(final_inputs)
output_errors=targets - final_outputs
hidden_errors=np.dot(self.who.T,output_errors)
self.who += self.lr*np.dot((output_errors*final_outputs*(1.0-final_outputs)),np.transpose(hidden_outputs))
self.wih += self.lr * np.dot((hidden_errors * hidden_outputs * (1.0-hidden_outputs)),np.transpose(inputs))
pass
def query(self,inputs_list):
#将输入转为二维矩阵
inputs = np.array(inputs_list,ndmin=2).T
#print(inputs)
#输入乘以第一层权重
hidden_inputs = np.dot(self.wih,inputs)
#通过激活函数输出
hidden_outputs=self.activation_function(hidden_inputs)
#最后一层,和前面一样
final_inputs=np.dot(self.who,hidden_outputs)
final_outputs=self.activation_function(final_inputs)
return final_outputs
pass
4.跑数据训练它:
经典的mnist数据集,直接跑,也不管小批量了好吧,第一次能成就行,直接整个数据跑。7个epoch用时7-8分钟。
#神经元数量
input_nodes = 784
hidden_nodes = 200
output_nodes = 10
#学习率
lr=0.2
#初始化神经网络
n=neuralNetwork(input_nodes,hidden_nodes,output_nodes,lr)
#打开并读取数据集
training_data_file= open("mnist_train.csv",'r')
training_data_list = training_data_file.readlines()
training_data_file.close
#跑7个epoch
for e in range(7):
#每一笔数据取出后将标签拿出来,其他的传给训练函数
for record in training_data_list:
all_values = record.split(',')
inputs=(np.asfarray(all_values[1:])/255.0 *0.99)+0.01
targets = np.zeros(output_nodes)+0.01
targets[int(all_values[0])]=0.99
n.train(inputs,targets)
pass
pass
5.训练完成后进行测试:
#记录正确与否
scorecard = []
#打开并读取数据
test_data_file = open("mnist_test.csv",'r')
test_data_list = test_data_file.readlines()
test_data_file.close()
#测试
for re in test_data_list:
all_values = re.split(',')
#获取正确的标签
correct_lable = int (all_values[0])
#print(correct_lable,"correct lable")
inputs = (np.asfarray(all_values[1:])/255.0*0.99)+0.01
outputs = n.query(inputs)
lable = np.argmax(outputs)
# print(lable,"network's answer")
#正确就写1,否写0
if (lable == correct_lable):
scorecard.append(1)
else:
scorecard.append(0)
scorecard_array = np.asarray(scorecard)
#计算正确率
print("正确率:",scorecard_array.sum()/scorecard_array.size*100,'%')
6.结果还不错,96了。当然,我这是作弊的,学习率没有自己试,而是借鉴了前辈们的,哈哈哈。
感谢观看,后续学习继续更新,奥利给,xdm!
2021/10/22更新
padans:
在复现高斯朴素贝叶斯模型时:
def fit(self, X, y):
classes = y[y.columns[0]].unique() #有几类需要划分
class_count = y[y.columns[0]].value_counts() #每一类的总个数
# 类先验概率
class_prior = class_count / len(y) #P(0) P(1) p(2)
# 计算类条件概率
prior = dict()
for col in X.columns:
for j in classes:
mstd = []
data_x_y = X[(y == j).values][col] #pandas数据格式 共用一个索引 所以这样筛选 且自动遍历所有的行
#print("(y == j).values:",(y == j).values)
# print("data_x_y:",data_x_y)
m_x_y = np.mean(data_x_y) #平均值
print(m_x_y)
mstd.append(m_x_y)
std_x_y = np.std(data_x_y)#标准差
mstd.append(std_x_y)
prior[(col, j)] = mstd
print("prior",prior)
return classes, class_prior, prior
X:
y:
之前没有学过pandas,看不懂其中:
data_x_y = X[(y == j).values][col]
为什么可以在X中用y来筛选?为什么不需要遍历行向量?
Pandas DataFrames :
重点 :共用一个索引
他们可以不一起建立 ,之后建立的series也是共用的。所以可以用y来筛选X中的数据
自动返回一个series,不用再写遍历行的循环。
2021/11/2更新
pytorch的学习(B站up我是土堆的视频)
1.1对数据集的读取:
数据集介绍,图片放在对应的文件夹里,标签就是文件夹名称
导入dataset
from torch.utils.data import Dataset
详细请参考pytorch数据加载
案例:
from torch.utils.data import Dataset
import os
from PIL import Image
class MyData(Dataset):
def __init__(self, root_dir , label_dir):
self.root_dir = root_dir
self.label_dir = label_dir
self.path = os.path.join(root_dir, label_dir)
self.img_path_list = os.listdir(self.path)
def __getitem__(self, idx):
img_name = self.img_path_list[idx]
img_item_path = os.path.join(self.path, img_name)
# img = Image.open(img_item_path)
# label = self.lable_dir
return Image.open(img_item_path), self.label_dir
def __len__(self):
return len(self.img_path_list)
root_dir = "dataset/train"
ants_dir = "ants"
bees_dir = "bees"
ants_dataset = MyData(root_dir, ants_dir)
bees_dataset = MyData(root_dir, bees_dir)
1.2 tensorboard 使用(打印los图和训练的图)
from torch.utils.tensorboard import SummaryWriter
import numpy as np
from PIL import Image
writer = SummaryWriter("logs")
image_path = "dataset/train/ants/6240329_72c01e663e.jpg"
img_PIL = Image.open(image_path)
img_array = np.array(img_PIL)
writer.add_image("test", img_array, 2, dataformats='HWC')
for i in range(100):
writer.add_scalar("y=x", i, i)
writer.close()
# how to open log files
# use Command Prompt with code tensorboard --logdir=logs --port=6007
12/11/5更新
1.3 transforms
对数据进行处理 ,比如将PIL的Image转为tensor(张量)-Totensor
使用方法:
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)
normlize
norm = transforms.Normalize([3, 5, 7], [1, 4, 9])
img_norm = norm(img_tensor)
resize
resize = transforms.Resize(200)
# img PIL -> img_resize PIL
img_resize = resize(img)
# img_resize PIL->img_resize1 tensor
img_resize1 = totensor(img_resize)
compose
# img -> resize -> tensor -> writer
compose = transforms.Compose([transforms.Resize(100), transforms.ToTensor()])
img_compose_resize = compose(img)
writer.add_image("compose", img_compose_resize, 0)
2.1 nn.module
自己写的网络继承nn.module 比如下面 测试maxpooling (从nn导入)
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10("./CIFDataset", train=False, transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=64)
writer = SummaryWriter("logs")
class MyTextModule(nn.Module):
def __init__(self):
super(MyTextModule, self).__init__()
# self.conv1 = Conv2d(in_channels=3, out_channels=3, kernel_size=3, stride=1, padding=0)
self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=False)
def forward(self, input):
# Coutput = self.conv1(x)
output = self.maxpool1(input)
return output
myTextModule = MyTextModule()
step = 0
for data in dataloader:
imgs, targets = data
writer.add_images("imput", imgs, step)
output = myTextModule(imgs)
# output1 = torch.reshape(output, (-1, 3, 32, 32))
writer.add_images("output", output, step)
step += 1
writer.close()
2.2 网络训练的保存和加载
就是你训练后权重怎么保存和使用 总不能每次预测都要重新训练吧 哈哈哈
两种保存方式
import torch
import torchvision
vgg16 = torchvision.models.vgg16(pretrained=False)
# 保存方式1 模型结构加参数
torch.save(vgg16, "vgg16_method1.pth")
# 保存方式2 模型参数(官方推荐)
torch.save(vgg16.state_dict(), "vgg16_method2.pth")
两种读取方式
import torch
import torchvision.models
#方法一获取
model = torch.load("vgg16_method1.pth")
print(model)
# 方法二获取数据
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
model2 = torch.load("vgg16_method2.pth")
print(vgg16)
vgg16_method2.pth 是在保存时自己设置的名字 保存在同级目录下 若想上一级就是"./vgg16_method2.pth"
2.3 自己写一个网络
使用pytorch提供的数据集 cifar10 ,网络结构网上随便找的简单的网络
注释是没有使用Sequential,相当于没有打包在一起,Sequential可以将网络层打包在一起
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
class MyFirstNet(nn.Module):
def __init__(self):
super(MyFirstNet, self).__init__()
# self.conv1 = Conv2d(3, 32, 5, padding=2)
# self.maxpool1 = MaxPool2d(2)
# self.conv2 = Conv2d(32, 32, 5, padding=2)
# self.maxpool2 = MaxPool2d(2)
# self.conv3 = Conv2d(32, 64, 5, padding=2)
# self.maxpool3 = MaxPool2d(2)
# self.flatten = Flatten()
# self.linear1 = Linear(1024, 64)
# self.linear2 = Linear(64, 10)
self.model1 = Sequential(
Conv2d(3, 32, (5, 5), padding=2),
MaxPool2d(2),
Conv2d(32, 32, (5, 5), padding=2),
MaxPool2d(2),
Conv2d(32, 64, (5, 5), padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self, x):
# x = self.conv1(x)
# x = self.maxpool1(x)
# x = self.conv2(x)
# x = self.maxpool2(x)
# x = self.conv3(x)
# x = self.maxpool3(x)
# x = self.flatten(x)
# x = self.linear1(x)
# x = self.linear2(x)
x = self.model1(x)
return x
2.4 训练网络
网络结构从之前的写的网络中导入from FirstNet import MyFirstNet
import time
import torch.optim
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from FirstNet import MyFirstNet
# 导入数据
train_data = torchvision.datasets.CIFAR10("./CIFDataset", train=True, transform=torchvision.transforms.ToTensor())
test_data = torchvision.datasets.CIFAR10("./CIFDataset", train=False, transform=torchvision.transforms.ToTensor())
# train_data_size = len(train_data)
# test_data_size = len(test_data)
# print(train_data_size,test_data_size)
# 数据加载
train_dataloader = DataLoader(train_data, 64)
test_dataloader = DataLoader(test_data, 64)
# 创建网络模型
mynet = torch.load("torch_10.pth") # 使用上次训练完之后的参数
mynet = mynet.cuda()
# 损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.cuda()
# 优化器
lenarning_rate = 1e-5
optimizer = torch.optim.SGD(mynet.parameters(), lr=lenarning_rate)
# 设置训练网络
total_train_step = 0
total_test_step = 0
# 训练轮数
epoch = 10
# 可视化
writer = SummaryWriter("./trainLos")
# 开始训练
start_time = time.time()
for i in range(epoch):
print("---第{}轮训练:---".format(i + 1))
mynet.train()
for imgS, targets in train_dataloader:
imgS = imgS.cuda()
targets = targets.cuda()
output = mynet(imgS)
loss = loss_fn(output, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step += 1
if total_train_step % 100 == 0:
end_time = time.time()
print(end_time - start_time)
print("训练次数:{},Loss:{}".format(total_train_step, loss.item()))
writer.add_scalar("train_loss", loss.item(), total_train_step)
# 测试步骤开始
mynet.eval()
total_accuracy = 0
total_test_loss = 0
with torch.no_grad():
for imgS, targetS in test_dataloader:
imgS = imgS.cuda()
targetS = targetS.cuda()
output = mynet(imgS)
loss = loss_fn(output, targetS)
total_test_loss += loss.item()
accuracy = (output.argmax(1) == targetS).sum()
total_accuracy += accuracy
print("整体测试集误差{}".format(total_test_loss))
print("整体测试集正确率{}".format(total_accuracy/len(test_data)))
writer.add_scalar("test_loss", total_test_loss, total_test_step)
writer.add_scalar("test_accuracy", total_accuracy/len(test_data), total_test_step)
total_test_step += 1
# 保存参数
torch.save(mynet, "torch_{}.pth".format(epoch))
print("模型已保存")
writer.close()
训练几次后的效果,初始Learnningrate=0.01 第一次10个epoch跑完之后,将learnningrate调小10倍 在跑完10个epoch后再继续调小 下图是结果 正确率到0.69基本上就是这个的极限了
2.5 测试网络
用一张没见过的图片进性预测
import torch
import torchvision.transforms
from PIL import Image
img_path = "./imgs/dog.png"
image = Image.open(img_path)
image = image.convert('RGB')
transfrom = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)),
torchvision.transforms.ToTensor()])
image = transfrom(image)
model = torch.load("torch_10.pth", map_location=torch.device('cpu'))
print(model)
image = torch.reshape(image, (1, 3, 32, 32))
model.eval()
with torch.no_grad():
output = model(image)
print(output)
print(output.argmax(1))
测试了2张图片都对了 正确率接近70%也还可以了