【生成式网络】入门篇(三):Style Transfer 的 代码和结果记录

news/2024/5/6 10:56:06/文章来源:https://blog.csdn.net/fangjin_kl/article/details/128036154

文章目录

  • Style Transfer 记录
  • Fast Style Transfer 记录

Style Transfer 记录

经典文章xxx,理论就不介绍了,根据一个content图像,和一个style图像,可以把style图像的style迁移到content图像上。
在代码上有一个跟之前不同的地方,就是这里需要不断优化的变量是这张图像,vgg只是用来提取特征,不需要反传。具体做的时候,把三张图(content 图, style图,和我们希望生成的target图)都通过vgg,提取中间某些层计算出feature,这些feature 之间会计算一个content loss,使得target图和content图内容接近,同时计算一个style loss,使得target图和style图的style接近。

一般为了加速迭代,target会先用content图初始化。

不废话,上代码

import os
os.chdir(os.path.dirname(__file__))
from torchvision import models
from torchvision import transforms
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import argparse
from PIL import Image
from torch.utils.tensorboard import SummaryWritersample_dir = 'samples_style_transfer'
if not os.path.exists(sample_dir):os.makedirs(sample_dir, exist_ok=True)writer = SummaryWriter(sample_dir)device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')def load_image(image_path, transform=None, max_size=None, shape=None):image = Image.open(image_path)if max_size:scale = max_size / max(image.size)size = np.array(image.size) * scaleimage = image.resize(size.astype(int), Image.ANTIALIAS)if shape:image = image.resize(shape, Image.LANCZOS)if transform:image = transform(image).unsqueeze(0)return image.to(device)class VGGNet(nn.Module):def __init__(self):super(VGGNet, self).__init__()self.select = ['0', '5', '10', '19', '28'] self.vgg = models.vgg19(pretrained=True).featuresdef forward(self, x):features = []for name, layer in self.vgg._modules.items():x = layer(x)if name in self.select:features.append(x)return featuresdef main(config):T = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))])content = load_image(config.content, T, max_size=config.max_size)style = load_image(config.style, T, shape=[content.size(2), content.size(3)])target = content.clone().requires_grad_(True)optimizer = torch.optim.Adam([target], lr=config.lr, betas=[0.5, 0.999])vgg = VGGNet().to(device).eval()for epoch in range(config.total_step):target_feature = vgg(target)content_feature = vgg(content)style_feature = vgg(style)style_loss = 0content_loss = 0for f1, f2, f3 in zip(target_feature, content_feature, style_feature):content_loss += torch.mean((f1-f2)**2)_,c,h,w = f1.size()f1 = f1.view(c, h*w)f3 = f3.view(c, h*w)# gram matrixf1 = torch.mm(f1, f1.t())f3 = torch.mm(f3, f3.t())# style lossstyle_loss += torch.mean((f1-f3)**2) / (c*h*w)loss = content_loss + config.style_weight * style_lossoptimizer.zero_grad()loss.backward()optimizer.step()writer.add_scalar('loss', loss.item(), global_step=epoch)writer.add_scalar('content_loss', content_loss.item(), global_step=epoch)writer.add_scalar('style_loss', style_loss.item(), global_step=epoch)if (epoch+1) % config.log_step == 0:print('Epoch [{}/{}], Loss: {:.4f}, Content loss: {:.4f}, Style loss: {:.4f}'.\format(epoch, config.total_step, loss.item(), content_loss.item(), style_loss.item()))if (epoch+1) % config.sample_step == 0:denorm = transforms.Normalize(mean=(-2.12, -2.04, -1.80), std=(4.37, 4.46, 4.44))img = target.clone().squeeze()img = denorm(img).clamp_(0, 1)writer.add_image('img', img, global_step=epoch)if __name__ == "__main__":parser = argparse.ArgumentParser()parser.add_argument('--content', type=str, default='data/content.png')parser.add_argument('--style', type=str, default='data/style.png')parser.add_argument('--max_size', type=int, default=400)parser.add_argument('--total_step', type=int, default=2000)parser.add_argument('--log_step', type=int, default=10)parser.add_argument('--sample_step', type=int, default=500)parser.add_argument('--style_weight', type=float, default=100)parser.add_argument('--lr', type=float, default=0.003)config = parser.parse_args()config.total_step = 20000config.sample_step = 100print(config)main(config)
  • content图
    请添加图片描述

  • style图
    请添加图片描述

  • 接近4000次迭代
    在这里插入图片描述

  • 经过 20000次迭代,能够看到风格越来越接近了。
    在这里插入图片描述
    但是这种style transfer有一个缺点,就是得针对一张图像进行不断迭代,能不能来了一张新图像,送进去后很快就能得到新的图像呢?

当然有,那就是fast neural style transfer

Fast Style Transfer 记录

相关原理可以参考 https://blog.csdn.net/qq_33590958/article/details/96122789
相当于设计了一个transform 的网络,专门做风格转换,然后继续保留预训练好的vgg网络用来提取特征做loss,整体loss还是参考了原来的文章,有了这个transform网络,只需要训练好这个网络,新的图像输进去,一个前向过程就输出了转换后的图像,速度很快。不过也有个缺陷,那就是每个新的style图,都需要重新训练网络(我的理解是这样,有错的话欢迎指出)。
在这里插入图片描述
具体transform的网络结构如下,是全连接网络,大致分三个阶段,下采样-> 残差模块->上采样模块
在这里插入图片描述

代码是参考了pytorch的example代码,如下

import os
# os.chdir(os.path.dirname(__file__))
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torchvision
from torchvision import transforms
from torchvision import datasets
from torchvision import models
from torch.utils.tensorboard import SummaryWriter
import numpy as np
from PIL import Image
import argparsesample_dir = 'samples_fast_style_transfer'
if not os.path.exists(sample_dir):os.makedirs(sample_dir, exist_ok=True)writer = SummaryWriter(sample_dir)device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
np.random.seed(0)
torch.manual_seed(0)def load_image(filename, size=None, scale=None):img = Image.open(filename).convert('RGB')if size is not None:img = img.resize((size, size), Image.ANTIALIAS)elif scale is not None:size = (int(img.size[0] / scale), int(img.size[1] / scale))img = img.resize(size, Image.ANTIALIAS)return imgdef save_image(filename, data):img = data.clone.clamp(0, 255).numpy()img = img.transpose(1,2,0).astype('uint8')img = Image.fromarray(img)img.save(filename)def gram_matrix(y):b,ch,h,w = y.size()features = y.view(b,ch,h*w)features_t = features.transpose(1,2)gram = features.bmm(features_t)/(ch*h*w)return gramdef normalize_batch(batch):# normalize using imagenet mean and stdmean = batch.new_tensor([0.485, 0.456, 0.406]).view(-1, 1, 1)std = batch.new_tensor([0.229, 0.224, 0.225]).view(-1, 1, 1)batch = batch.div_(255.0)return (batch - mean) / stddef save_checkpoint(model, epochs):model.eval().cpu()save_model_filename = "epoch_" + str(epochs) + ".model"save_model_path = os.path.join(sample_dir, save_model_filename)torch.save(model.state_dict(), save_model_path)print("\nDone, trained model saved at", save_model_path)class ConvLayer(torch.nn.Module):def __init__(self, in_channels, out_channels, kernel_size, stride):super(ConvLayer, self).__init__()reflection_padding = kernel_size // 2self.reflection_pad = torch.nn.ReflectionPad2d(reflection_padding)self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride)def forward(self, x):out = self.reflection_pad(x)out = self.conv2d(out)return outclass ResidualBlock(torch.nn.Module):"""ResidualBlockintroduced in: https://arxiv.org/abs/1512.03385recommended architecture: http://torch.ch/blog/2016/02/04/resnets.html"""def __init__(self, channels):super(ResidualBlock, self).__init__()self.conv1 = ConvLayer(channels, channels, kernel_size=3, stride=1)self.in1 = torch.nn.InstanceNorm2d(channels, affine=True)self.conv2 = ConvLayer(channels, channels, kernel_size=3, stride=1)self.in2 = torch.nn.InstanceNorm2d(channels, affine=True)self.relu = torch.nn.ReLU()def forward(self, x):residual = xout = self.relu(self.in1(self.conv1(x)))out = self.in2(self.conv2(out))out = out + residualreturn outclass UpsampleConvLayer(torch.nn.Module):"""UpsampleConvLayerUpsamples the input and then does a convolution. This method gives better resultscompared to ConvTranspose2d.ref: http://distill.pub/2016/deconv-checkerboard/"""def __init__(self, in_channels, out_channels, kernel_size, stride, upsample=None):super(UpsampleConvLayer, self).__init__()self.upsample = upsamplereflection_padding = kernel_size // 2self.reflection_pad = torch.nn.ReflectionPad2d(reflection_padding) # 可以重点关注这个padding方式,参考https://blog.csdn.net/LionZYT/article/details/120181586self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride)def forward(self, x):x_in = xif self.upsample:x_in = torch.nn.functional.interpolate(x_in, mode='nearest', scale_factor=self.upsample)out = self.reflection_pad(x_in)out = self.conv2d(out)return outclass TransformerNet(torch.nn.Module):def __init__(self):super(TransformerNet, self).__init__()# Initial convolution layersself.conv1 = ConvLayer(3, 32, kernel_size=9, stride=1)self.in1 = torch.nn.InstanceNorm2d(32, affine=True)self.conv2 = ConvLayer(32, 64, kernel_size=3, stride=2)self.in2 = torch.nn.InstanceNorm2d(64, affine=True)self.conv3 = ConvLayer(64, 128, kernel_size=3, stride=2)self.in3 = torch.nn.InstanceNorm2d(128, affine=True)# Residual layersself.res1 = ResidualBlock(128)self.res2 = ResidualBlock(128)self.res3 = ResidualBlock(128)self.res4 = ResidualBlock(128)self.res5 = ResidualBlock(128)# Upsampling Layersself.deconv1 = UpsampleConvLayer(128, 64, kernel_size=3, stride=1, upsample=2)self.in4 = torch.nn.InstanceNorm2d(64, affine=True)self.deconv2 = UpsampleConvLayer(64, 32, kernel_size=3, stride=1, upsample=2)self.in5 = torch.nn.InstanceNorm2d(32, affine=True)self.deconv3 = ConvLayer(32, 3, kernel_size=9, stride=1)# Non-linearitiesself.relu = torch.nn.ReLU()def forward(self, X):y = self.relu(self.in1(self.conv1(X)))y = self.relu(self.in2(self.conv2(y)))y = self.relu(self.in3(self.conv3(y)))y = self.res1(y)y = self.res2(y)y = self.res3(y)y = self.res4(y)y = self.res5(y)y = self.relu(self.in4(self.deconv1(y)))y = self.relu(self.in5(self.deconv2(y)))y = self.deconv3(y)return yfrom collections import namedtuple
class Vgg16(nn.Module):def __init__(self, required_grad=False):super(Vgg16, self).__init__()vgg_pretrained_features = models.vgg16(pretrained=True).featuresself.slice1 = torch.nn.Sequential()self.slice2 = torch.nn.Sequential()self.slice3 = torch.nn.Sequential()self.slice4 = torch.nn.Sequential()for x in range(4):self.slice1.add_module(str(x), vgg_pretrained_features[x])for x in range(4, 9):self.slice2.add_module(str(x), vgg_pretrained_features[x])for x in range(9, 16):self.slice3.add_module(str(x), vgg_pretrained_features[x])for x in range(16, 23):self.slice4.add_module(str(x), vgg_pretrained_features[x])if not required_grad:for param in self.parameters():param.requires_grad_(False)def forward(self, X):h = self.slice1(X)h_relu1_2 = hh = self.slice2(h)h_relu2_2 = hh = self.slice3(h)h_relu3_3 = hh = self.slice4(h)h_relu4_3 = hvgg_outputs = namedtuple("VggOutputs", ['relu1_2', 'relu2_2', 'relu3_3', 'relu4_3'])out = vgg_outputs(h_relu1_2, h_relu2_2, h_relu3_3, h_relu4_3)return outdef train():epochs = 10batch_size = 4image_size = 256learning_rate = 1e-3style_weight = 1e6content_weight = 1e1log_step = 10dataset_path = 'data/fast_neural_style/dataset'style_image = 'data/fast_neural_style/style-images/mosaic.jpg'content_image = 'data/fast_neural_style/content-images/amber.jpg'T = transforms.Compose([transforms.Resize(image_size),transforms.CenterCrop(image_size),transforms.ToTensor(),transforms.Lambda(lambda x : x.mul(255))])train_dataset = datasets.ImageFolder(dataset_path, T)train_loader = DataLoader(train_dataset, batch_size=batch_size, drop_last=True, shuffle=True)transformer = TransformerNet().to(device)optimizer = torch.optim.Adam(transformer.parameters(), lr=learning_rate)mse_loss = torch.nn.MSELoss()vgg = Vgg16(required_grad=False).to(device)# load style imagestyle_T = transforms.Compose([transforms.ToTensor(),transforms.Lambda(lambda x :x.mul(255))])style = load_image(style_image, size = image_size)style = style_T(style)style = style.repeat(batch_size, 1,1,1).to(device)features_style = vgg(normalize_batch(style))gram_style = [gram_matrix(y) for y in features_style]cnt = 0# load content imagecontent_image = load_image(content_image)content_transform = transforms.Compose([transforms.ToTensor(),transforms.Lambda(lambda x: x.mul(255))])content_image = content_transform(content_image)content_image = content_image.unsqueeze(0).to(device)for epoch in range(epochs):transformer.train()for batchid, (x, _) in enumerate(train_loader):x = x.to(device)y = transformer(x)# 这里是为了让数据的均值和方差符合预训练模型的分布x = normalize_batch(x)y = normalize_batch(y.mul(255))features_x = vgg(x)features_y = vgg(y)content_loss = mse_loss(features_y.relu2_2, features_x.relu2_2) * content_weightstyle_loss = 0for ft_y, gm_s in zip(features_y, gram_style):gm_y = gram_matrix(ft_y)style_loss += mse_loss(gm_y, gm_s)style_loss = style_loss * style_weighttotal_loss = content_loss  + style_loss optimizer.zero_grad()total_loss.backward()optimizer.step()cnt += 1if cnt % log_step == 0:print('Epoch [{}/{}], Step [{}], Loss: {:.4f}, Content loss: {:.4f}, Style loss: {:.4f}'.\format(epoch, epochs, cnt, total_loss.item(), content_loss.item(), style_loss.item()))writer.add_scalar('loss', total_loss.item(), global_step=cnt)writer.add_scalar('content_loss', content_loss.item(), global_step=cnt)writer.add_scalar('style_loss', style_loss.item(), global_step=cnt)if cnt % 100 == 0:img = eval(content_image, transformer)writer.add_image('target_images', img, global_step=cnt, dataformats='CHW')save_checkpoint(transformer, epoch)def eval(content_image, transformer):transformer.eval()output_image = transformer(content_image).cpu()transformer.train()mean = output_image.new_tensor([0.485, 0.456, 0.406]).view(-1, 1, 1)std = output_image.new_tensor([0.229, 0.224, 0.225]).view(-1, 1, 1)output_image = output_image * std + meanreturn output_image[0].clamp(0, 1)if __name__ == '__main__':train()

重点可以看看这段代码,按照代码的解释,这里上采样不是通过convTranspose来实现,而是先做一个ReflectionPad,再进行插值来上采样,然后做一个conv,按照注释的说法,这样效果比ConvTranspose2d好。

class UpsampleConvLayer(torch.nn.Module):"""UpsampleConvLayerUpsamples the input and then does a convolution. This method gives better resultscompared to ConvTranspose2d.ref: http://distill.pub/2016/deconv-checkerboard/"""def __init__(self, in_channels, out_channels, kernel_size, stride, upsample=None):super(UpsampleConvLayer, self).__init__()self.upsample = upsamplereflection_padding = kernel_size // 2self.reflection_pad = torch.nn.ReflectionPad2d(reflection_padding) # 可以重点关注这个padding方式,参考https://blog.csdn.net/LionZYT/article/details/120181586self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride)def forward(self, x):x_in = xif self.upsample:x_in = torch.nn.functional.interpolate(x_in, mode='nearest', scale_factor=self.upsample)out = self.reflection_pad(x_in)out = self.conv2d(out)return out

ReflectionPad 可以参考https://blog.csdn.net/LionZYT/article/details/120181586
函数用途:对输入图像以最外围像素为对称轴,做四周的轴对称镜像填充。

在这里插入图片描述
效果如下

  • 原图content图请添加图片描述
  • style 图
    请添加图片描述
  • 最终风格迁移后的效果图

我个人觉得风格也没那么接近,但是有点那个意思了,在训练过程中也是变得越来越清晰的。
在这里插入图片描述
这里我也贴出最后官方给的output的效果

  • 官方训练的结果,看着好多了
    请添加图片描述

这份代码里 style_weight 和content_weight 给的奇高,不知道是为了什么,我稍作了调整,可能影响了最终的训练,大家可以自行再调整一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_228066.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

硬件定义软件?还是,软件定义硬件?

文章目录**1 软件和硬件****1.1 软件和硬件的定义****1.2 “硬件定义软件”和“软件定义硬件”的定义****1.3 CPU,软件和硬件解耦****1.4 CPU的软硬件定义****2 硬件定义软件****2.1 系统从软件逐步到硬件****2.2 硬件架构决定了软件设计****2.2.1 ASIC的硬件定义**…

django 开启CSRFtoken校验,以及postman实现问题

1.0 Django默认的CSRFtoken 表现: 后端使用的是Django的表单验证 post请求携带参数的问题 2.0 先处理post请求携带数据的csrfmiddlewaretoken 在登录界面 在input输入框中隐藏,所以需要提取input的value值,在【tests】脚本中进行提取&…

【C++11重点语法】lambda表达式,初始化列表

目录 引子:C11为什么的源来 语法1:初始化列表 1.2.2 多个对象的列表初始化 语法3:默认成员函数控制(delete,default) 语法4:lambda表达式 引子:C11为什么的源来 在2003年C标准…

简述RabbitMQ的架构设计

Broker: rabbitmq的服务节点Queue: 队列,是RabbitMQ的内部对象,⽤于存储消息。RabbitMQ中消息只能存储在队列中。⽣产者投递消息到队列,消费者从队列中获取消息并消费。多个消费者可以订阅同⼀个队列,这时队…

【Linux】shell命令行简单解释器

回顾一下,我们前面学习了进程创建,进程终止,进程等待,进程替换,通过这些内容我们可以来进行实现简单的shell命令行解释器!!!下面我们直接来看一看如何去实现shell命令行解释器&#…

[附源码]Python计算机毕业设计SSM临港新片区招商引资项目管理系统的设计与实现(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

嫦娥五号探测器详细介绍

嫦娥五号(Change 5),即嫦娥五号探测器,是由中国空间技术研究院研制的中国首个实施无人月面取样返回的航天器,是完成中国探月工程重大科技专项“绕、落、回”三步走发展战略最后一步的关键任务。 中国探月工程三步走 嫦…

cisco asa学习笔记

cisco asa学习笔记一、网络模拟实验中的问题调试记录1、ASA自身接口地址ping不通(从远端路由过来的主机)2、同安全级别的接口默认不能通信&#xff0c;怎么才能通信&#xff1f;3、一个asa连接3个路由器&#xff0c;互联互通解决方案<1>方案1 全局开启policy-map inspect…

算法竞赛入门【码蹄集进阶塔335题】(MT2281-2285)

算法竞赛入门【码蹄集进阶塔335题】(MT2281-2285&#xff09; 文章目录算法竞赛入门【码蹄集进阶塔335题】(MT2281-2285&#xff09;前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f;目录1. MT2281 另一种模2. MT2282 小码哥的认可3. MT2283 整数…

影响工业产品设计的主要因素

设计师对工业产品的产品外观设计主要依靠形状、图案和颜色的结合&#xff0c;创造出具有一定功能性质的新产品。在这个过程中&#xff0c;设计师需要充分利用各种因素&#xff0c;外观工业设计公司强调材料的机制和颜色。那么&#xff0c;影响产品设计的主要因素是什么呢? 一、…

【Linux】8.0 多线程

文章目录1.0 Linux线程概念1.1 Linux线程基本概念1.2 Linux线程优劣介绍2.0 Linux线程控制2.1 pthread_create(创建线程)2.2 pthread_join(线程等待)2.3 pthread_exit(线程终止)2.4 pthread_detach(线程分离)3.0 线程id和LWP的关系4.0 Linux线程互斥4.1 线程互斥相关概念4.2 线…

spring-boot-starter-data-redis 引发的一系列惨案

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> pom 引入jar包 &#xff0c;如果redis配置文件使用 lettuce &#xff0c;还需要引入 commons-pool2 &a…

数据可视化,销量第一的新能源汽车是什么?比亚迪新能源汽车销量接近60万辆

去年以来&#xff0c;新能源汽车火热度席卷全球&#xff0c;中国的新能源汽车无论制造或者销售&#xff0c;数量增长迅猛。下面小编用一款数据可视化软件&#xff0c;带你用可视化数据解读高端制造背后&#xff0c;中国新能源汽车的具体销售情况。同样如果你工作上有数据报表需…

固话号码认证有什么好处?固话号码认证有什么作用?

固话号码认证为企业提供号码认证服务&#xff0c;在来电时显示企业信息&#xff0c;可提高电话号码辨识度&#xff0c;防止错误标记&#xff0c;确保展现的企业信息与企业的手机终端、APP等多平台展示信息一致&#xff0c;保证品牌企业的身份及商业价值。 那如何上线号码认证服…

多点DMALL × Apache Kyuubi:构建统一SQL Proxy探索实践

伴随着国家产业升级的推进和云原生技术成熟&#xff0c;多点 DMALL 大数据技术也经历了从存算一体到存算分离的架构调整变迁。本文将从引入 Kyuubi 实现统一 SQL Proxy 的角度讲述这一探索实践的历程。 多点 DMALL 成立于2015年&#xff0c;提供一站式全渠道数字零售解决方案 D…

离线解锁 CodeCombat 全关卡教程 使用docker安装实现

背景 暂时还没收入&#xff0c;想玩顺便&#xff0c;但官方的有点贵&#xff08;是真的贵&#xff0c;扛不住&#xff09; 前期准备 下载安装docker desktop https://www.123pan.com/s/fmvUVv-HqApH&#xff0c; 这个安装不会的随便搜一个教程&#xff0c;挺多的。我随便找了一…

HTML篇_二、HTML简介_HTML入门必修第一课

HTML篇_二、HTML简介 一、HTML的基本结构 1.1 HTML的基本结构及解析 基本结构 这里我们先放一段代码块来进行展示&#xff0c;感受一下来自HTML的魅力。然后下文再对这段代码块进行解析。 <!DOCTYPE html> <html><head><meta charset"utf-8&quo…

使用自己的数据集测试Unbiased Mean Teacher for Cross-domain Object Detection

要复现Unbiased Mean Teacher for Cross-domain Object Detection&#xff08;UMT&#xff09;&#xff0c;首先要正确运行CycleGAN。 1. CycleGAN CycleGAN的github链接&#xff1a;https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix 1.1 CycleGAN环境配置 git cl…

[附源码]SSM计算机毕业设计学生宿舍设备报修JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

板卡测评 | 基于TI AM5708开发板——ARM+DSP多核异构开发案例分享

本次测评板卡是创龙科技旗下的TL570x-EVM,它是一款基于TI Sitara系列AM5708ARM Cortex-A15+浮点DSPC66x处理器设计的异构多核SOC评估板,由核心板和评估底板组成。核心板经过专业的PCB Layout和高低温测试验证,稳定可靠,可满足各种工业应用环境。 评估板接口资源丰富,引出…